diff options
Diffstat (limited to 'mld/link.c')
-rw-r--r-- | mld/link.c | 57 |
1 files changed, 37 insertions, 20 deletions
@@ -16,8 +16,11 @@ static int load_objects(struct linker *linker) { + int max_entries = linker->args->in_count + 1; + // 1 needed for the runtime + linker->objects = malloc(sizeof(struct object) * - linker->args->in_count); + max_entries); linker->obj_len = 0; if (linker->objects == NULL) { @@ -46,6 +49,19 @@ static int load_objects(struct linker *linker) skip_obj: } + if (linker->args->freestanding == false) { + #define _STR(x) _STR2(x) + #define _STR2(x) #x + + char *path = _STR(PREFIX) "/lib/mips/runtime.o"; + struct object *obj = &linker->objects[linker->obj_len++]; + if (object_load(obj, path)) + return M_ERROR; + + #undef _STR + #undef _STR2 + } + return M_SUCCESS; } @@ -161,7 +177,7 @@ static int relocate_symbol(struct linker *linker, struct object *obj, struct segment *sec = NULL; for (size_t i = 0; i < obj->phdr_len; i++) { Elf32_Phdr *temp = &obj->phdr[i]; - if (shdr->sh_offset == temp->p_offset) { + if (PHDR_SHDR_MATCH(temp, shdr)) { sec = &obj->segments[i]; break; } @@ -386,30 +402,22 @@ static int relocate_instruction_rela(struct linker *linker, return M_ERROR; } Elf32_Sym *sym = &symtab->syms[idx]; - const char *symname = symtab->strtab->data + B32(sym->st_name); - - /// get the section header that the symbol is related to - Elf32_Shdr *shdr = NULL; - if (B16(sym->st_shndx) >= seg->obj->shdr_len) { - ERROR("shndx index [%d] out of bounds", B16(sym->st_shndx)); + char const *sym_name = symtab->strtab->data + B32(sym->st_name); + if (B32(sym->st_name) >= symtab->strtab->len) { + ERROR("relocation symbol name out of bounds"); return M_ERROR; } - shdr = &seg->obj->shdr[B16(sym->st_shndx)]; - /// get the segment that the symbol is in - struct segment_table_entry *ent; - const char *segname = seg->obj->shstrtab->data + B32(shdr->sh_name); - if (B32(shdr->sh_name) >= seg->obj->shstrtab->len) { - ERROR("relocation segment name out of bounds"); - return M_ERROR; - } - if (segtab_get(&linker->segments, &ent, segname)) { - ERROR("could not locate segment for relocation"); + // get the new sym for the new vaddr + Elf32_Sym *new_sym = NULL; + if (symtab_get(&linker->symtab, &new_sym, sym_name)) { + ERROR("relocation symbol not found"); return M_ERROR; } - uint32_t sym_vaddr = B32(sym->st_value) + ent->vaddr; + /// get the segment that the symbol is in + uint32_t sym_vaddr = B32(new_sym->st_value); uint32_t *ins_raw = (uint32_t *) &seg->bytes[off]; union mips_instruction_data ins; @@ -462,7 +470,7 @@ static int relocate_instruction_rela(struct linker *linker, *ins_raw = B32(ins.raw); if (warn) - WARNING("truncating relocation for symbol '%s'", symname); + WARNING("truncating relocation for symbol '%s'", sym_name); return M_SUCCESS; @@ -647,6 +655,15 @@ static int link_executable(struct linker *linker) ehdr->e_shnum = B16(linker->shdr_len); ehdr->e_shstrndx = B16(linker->shstrtab_shidx); + Elf32_Sym *entry = NULL; + if (symtab_get(&linker->symtab, &entry, "_start")) { + ERROR("undefined symbol _start"); + return M_ERROR; + } + + // BE to BE, no endiness conversion needed + ehdr->e_entry = entry->st_value; + update_offsets(linker); if (write_file(linker)) |