diff options
Diffstat (limited to 'mld/segtab.c')
-rw-r--r-- | mld/segtab.c | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/mld/segtab.c b/mld/segtab.c new file mode 100644 index 0000000..22356d5 --- /dev/null +++ b/mld/segtab.c @@ -0,0 +1,147 @@ +#include <stdlib.h> +#include <merror.h> + +#include "link.h" + +#define SEGTAB_INIT_SIZE 8 + +int segtab_init(struct segment_table *segtab) +{ + segtab->len = 0; + segtab->size = SEGTAB_INIT_SIZE; + segtab->entries = malloc(sizeof(struct segment_table_entry) * + SEGTAB_INIT_SIZE); + + if (segtab->entries == NULL) { + PERROR("cannot alloc"); + return M_ERROR; + } + + return M_SUCCESS; +} + +void segtab_free(struct segment_table *segtab) +{ + for (uint32_t i = 0; i < segtab->len; i++) { + segtab_ent_free(&segtab->entries[i]); + } + free(segtab->entries); +} + +/* create a new entry with <seg> as its first segment part */ +int segtab_push(struct segment_table *segtab, struct segment_table_entry **res, + struct segment *seg) +{ + if (segtab->len >= segtab->size) { + uint32_t size = segtab->size * 2; + void *new = realloc(segtab->entries, + sizeof(struct segment_table_entry) * size); + if (new == NULL) { + PERROR("cannot relloc"); + return M_ERROR; + } + segtab->size = size; + segtab->entries = new; + } + + struct segment_table_entry ent; + if (segtab_ent_init(&ent)) + return M_ERROR; + ent.name = seg->name; + ent.vaddr = seg->vaddr; + ent.off = seg->off; + + if (segtab_ent_push(&ent, seg)) { + segtab_ent_free(&ent); + return M_ERROR; + } + + segtab->entries[segtab->len] = ent; + + if (res != NULL) + *res = &segtab->entries[segtab->len]; + + segtab->len++; + + return M_SUCCESS; +} + +/* find a segment table entry with a given name */ +int segtab_get(struct segment_table *segtab, struct segment_table_entry **ent, + const char *name) +{ + for (uint32_t i = 0; i < segtab->len; i++) { + const char *segname = segtab->entries[i].name; + if (strcmp(name, segname) != 0) + continue; + + *ent = &segtab->entries[i]; + return M_SUCCESS; + } + + return M_ERROR; +} + +int segtab_ent_init(struct segment_table_entry *ent) +{ + ent->len = 0; + ent->size = SEGTAB_INIT_SIZE; + ent->parts = malloc(sizeof(struct segment *) * + SEGTAB_INIT_SIZE); + + if (ent->parts == NULL) { + PERROR("cannot alloc"); + return M_ERROR; + } + + return M_SUCCESS; +} + +void segtab_ent_free(struct segment_table_entry *ent) +{ + free(ent->parts); +} + +int segtab_ent_push(struct segment_table_entry *ent, struct segment *seg) +{ + if (ent->len >= ent->size) { + uint32_t size = ent->size * 2; + void *new = realloc(ent->parts, + sizeof(struct segment *) * size); + if (new == NULL) { + PERROR("cannot relloc"); + return M_ERROR; + } + ent->size = size; + ent->parts = new; + } + + if (ent->len > 0) { + struct segment *first = ent->parts[0]; + if (first->align != seg->align) { + ERROR("segment '%s' doest not have matching alignment", + ent->name); + } + if (first->read != seg->read || + first->write != seg->write || + first->execute != seg->execute) { + ERROR("segment '%s' doest not have matching RWX", + ent->name); + } + } else { + ent->off = seg->new_off; + ent->vaddr = seg->new_vaddr; + } + + ent->parts[ent->len++] = seg; + return M_SUCCESS; +} + +uint32_t segtab_ent_size(struct segment_table_entry *ent) +{ + uint32_t size = 0; + for (uint32_t i = 0; i < ent->len; i++) { + size += ent->parts[i]->size; + } + return size; +} |