diff options
Diffstat (limited to '')
-rw-r--r-- | mld/link.c | 29 | ||||
-rw-r--r-- | mld/link.h | 29 |
2 files changed, 47 insertions, 11 deletions
@@ -47,6 +47,7 @@ static int load_objects(struct linker *linker) skip_obj: } + // load runtime object if not set to be freestanding if (linker->args->freestanding == false) { #define _STR(x) _STR2(x) #define _STR2(x) #x @@ -69,6 +70,9 @@ skip_obj: */ static int relocate_segment_name(struct linker *linker, const char *name) { + // find each segment with the provided segment name, + // and then relocate them + for (size_t i = 0; i < linker->obj_len; i++) { struct object *obj = &linker->objects[i]; for (size_t j = 0; j < obj->segment_len; j++) { @@ -122,6 +126,7 @@ static int relocate_segment_name(struct linker *linker, const char *name) M_SUCCESS) { if (segtab_ent_push(ent, seg)) return M_ERROR; + // otherwise create a new segment table entry } else { // update vaddr to be page aligned uint32_t m = seg->new_vaddr % SEC_ALIGN; @@ -134,7 +139,7 @@ static int relocate_segment_name(struct linker *linker, const char *name) linker->data_vaddr += add; } - // else create a new segment + // create a new segment if (segtab_push(&linker->segments, NULL, seg)) return M_ERROR; } @@ -146,6 +151,9 @@ static int relocate_segment_name(struct linker *linker, const char *name) static int relocate_segments(struct linker *linker) { + // for each object, find each different + // unique segment name + for (size_t i = 0; i < linker->obj_len; i++) { struct object *obj = &linker->objects[i]; for (size_t j = 0; j < obj->segment_len; j++) { @@ -154,6 +162,9 @@ static int relocate_segments(struct linker *linker) // check if the segment has already been relocated if (seg->new_vaddr != 0) continue; + + // relocate each segment with that segment + // name if(relocate_segment_name(linker, seg->name)) return M_ERROR; } @@ -165,6 +176,14 @@ static int relocate_segments(struct linker *linker) static int relocate_symbol(struct linker *linker, struct object *obj, struct symbol_table *symtab, const Elf32_Sym *sym) { + // given the symbol and the object its in + // 1. make sure the symbol is valid + // 2. get the segment in the object that the symbol is in + // 3. get tthe segment table entry that the segment is also + // in. This allows us to get the offset into the segment_table + // 4. the new shndx is the offset + 1 (since segments start at + // shndx 1 + size_t shndx = B16(sym->st_shndx); if (shndx == 0 || shndx == SHN_ABS) return M_SUCCESS; // ignore this symbol @@ -177,11 +196,15 @@ static int relocate_symbol(struct linker *linker, struct object *obj, return M_ERROR; } + // make sure the symbol name is + // in bounds if (B32(sym->st_name) >= symtab->strtab->len) { ERROR("symbol name out of bounds"); return M_ERROR; } + // find the segment that this symbol + // is contained in struct segment *sec = NULL; for (size_t i = 0; i < obj->phdr_len; i++) { if (obj->phdr_to_shdr_mapping[i] == shndx) { @@ -245,13 +268,17 @@ static int relocate_symbol(struct linker *linker, struct object *obj, static int relocate_symbols(struct linker *linker) { + // relocate in each object for (size_t i = 0; i < linker->obj_len; i++) { struct object *obj = &linker->objects[i]; + // look though each shdr entry and find + // any symbol tables for (size_t j = 0; j < obj->shdr_len; j++) { struct symbol_table *symtab = &obj->symtabs[j]; if (symtab->len < 1) continue; + // for each symbol in the table, relocate it for (size_t k = 0; k < symtab->len; k++) { const Elf32_Sym *sym = &symtab->syms[k]; if (relocate_symbol(linker, obj, symtab, sym)) @@ -92,11 +92,6 @@ struct symbol_table { struct symbol_table_mapping *map; }; -/// -/// symbol table map -/// (metadata for each symbol) -/// - int symtab_init(struct symbol_table *symtab); void symtab_free(struct symbol_table *symtab); @@ -104,6 +99,13 @@ int symtab_push(struct symbol_table *symtab, const Elf32_Sym *sym); int symtab_get(struct symbol_table *symtab, Elf32_Sym **sym, const char *name, int32_t obj_idx); +/// +/// symbol table map +/// (metadata for each symbol) +/// stores each object that a symbol +/// is in +/// + struct symbol_table_mapping { uint32_t len; uint32_t size; @@ -163,6 +165,9 @@ int segment_load(struct object *object, struct segment *segment, size_t index); /// /// segment table +/// holds each segment that +/// share the same name +/// (i.e. all .text segments) /// struct segment_table_entry { @@ -172,6 +177,7 @@ struct segment_table_entry { uint32_t off; uint32_t vaddr; // weak segment pointers. we do not own these!!! + // (but we own the array) struct segment **parts; }; @@ -181,9 +187,10 @@ void segtab_ent_free(struct segment_table_entry *ent); int segtab_ent_push(struct segment_table_entry *ent, struct segment *seg); uint32_t segtab_ent_size(struct segment_table_entry *ent); -// holds each segment by name -// and all the segment parts from each of the -// object files +/// +/// segment table +/// holds each segment table entry by name +/// struct segment_table { uint32_t len; uint32_t size; @@ -215,14 +222,16 @@ struct object { Elf32_Ehdr *ehdr; // section header table - Elf32_Shdr *shdr; + Elf32_Shdr *shdr; // weak size_t shdr_len; // program table - Elf32_Phdr *phdr; + Elf32_Phdr *phdr; // owned size_t phdr_len; // phdr <=> shdr mappings + // need a way to find any assoiciated + // phdr with a shdr, and also reverse uint32_t *phdr_to_shdr_mapping; // object meta |