diff options
Diffstat (limited to 'mld/link.c')
-rw-r--r-- | mld/link.c | 46 |
1 files changed, 31 insertions, 15 deletions
@@ -12,8 +12,6 @@ #include "link.h" #include "mips.h" -#define SEC_ALIGN 0x1000 - static int load_objects(struct linker *linker) { int max_entries = linker->args->in_count + 1; @@ -168,7 +166,7 @@ static int relocate_symbol(struct linker *linker, struct object *obj, struct symbol_table *symtab, const Elf32_Sym *sym) { size_t shndx = B16(sym->st_shndx); - if (shndx == 0) + if (shndx == 0 || shndx == SHN_ABS) return M_SUCCESS; // ignore this symbol // find the given section @@ -184,11 +182,9 @@ static int relocate_symbol(struct linker *linker, struct object *obj, return M_ERROR; } - Elf32_Shdr const *shdr = &obj->shdr[shndx]; struct segment *sec = NULL; for (size_t i = 0; i < obj->phdr_len; i++) { - Elf32_Phdr *temp = &obj->phdr[i]; - if (PHDR_SHDR_MATCH(temp, shdr)) { + if (obj->phdr_to_shdr_mapping[i] == shndx) { sec = &obj->segments[i]; break; } @@ -219,6 +215,20 @@ static int relocate_symbol(struct linker *linker, struct object *obj, new.st_shndx = B16(new_shndx); new.st_size = 0; + // rename symbol if its name is empty to perm placeholder + //if (B32(sym->st_name) == 0) { + // #define __MAX 512 + // char name[__MAX]; + // memset(name, 0, __MAX); + // strcat(name, "__sym"); + // snprintf(name + strlen(name), __MAX - strlen(name), "%d", + // B32(sym->st_value)); + // if (strtab_push(linker->symtab.strtab, name, &str_off)) + // return M_ERROR; + // new.st_name = B32(str_off); + // #undef __MAX + //} + if (symtab_get(&linker->symtab, NULL, name, obj->index) == M_SUCCESS) { ERROR("cannot link doubly defiend symbol '%s'", name); return M_ERROR; @@ -447,33 +457,38 @@ static int relocate_instruction_rela(struct linker *linker, // 16bit absolute if (vaddr_abs > UINT16_MAX) warn = true; - ins.immd = (uint16_t)vaddr_abs; + ins.immd += (uint16_t)vaddr_abs; break; case R_MIPS_PC16: // 16bit relative shifted if (vaddr_rel > INT16_MAX || vaddr_rel < INT16_MIN) warn = true; - ins.offset = vaddr_rel; + ins.offset += vaddr_rel; break; case R_MIPS_26: + case R_MIPS_JALR: // 26bit absolute shifted if (vaddr_abs >= (1 << 25)) warn = true; - ins.target = (vaddr_abs & 0x0FFFFFFF) >> 2; + ins.target += (vaddr_abs & 0x0FFFFFFF) >> 2; break; case R_MIPS_PC26_S2: // 26bit relative shifted if (vaddr_rel >= (1 << 24) || -vaddr_rel > (1 << 24)) warn = true; - ins.offs26 = vaddr_rel; + ins.offs26 += vaddr_rel; break; case R_MIPS_LO16: // lo 16bit absolute - ins.immd = (uint16_t)(vaddr_abs & 0xFFFF); + ins.immd += (uint16_t)(vaddr_abs & 0xFFFF); break; case R_MIPS_HI16: // hi 16bit absolute - ins.immd = (uint16_t)(vaddr_abs >> 16); + ins.immd += (uint16_t)(vaddr_abs >> 16); + break; + case R_MIPS_32: + // 32bit absolute + ins.raw = vaddr_abs; break; default: ERROR("do not know how do handle relocation type [%d]", typ); @@ -596,9 +611,6 @@ static void update_offsets(struct linker *linker) static int write_file(struct linker *linker) { - extern char *current_file; - current_file = linker->args->out_file; - int fd = open(linker->args->out_file, O_RDWR | O_CREAT, 0711); if (fd < 0) { PERROR("cannot write"); @@ -739,12 +751,16 @@ static void linker_free(struct linker *linker) int link_files(struct linker_arguments args) { struct linker linker; + extern char *current_file; + int res = M_SUCCESS; if (res == M_SUCCESS) res = linker_init(&linker, &args); if (res == M_SUCCESS) res = load_objects(&linker); + + current_file = args.out_file; if (res == M_SUCCESS) res = relocate_segments(&linker); if (res == M_SUCCESS) |