From fb071309905c2911bd696c2cd0eafdae02d1e80b Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Tue, 1 Oct 2024 18:20:10 -0400 Subject: [PATCH] dont require phdr to link --- mld/link.c | 46 ++++++++++++++-------- mld/link.h | 8 ++++ mld/obj.c | 105 ++++++++++++++++++++++++++++++++++++++++++++------- mld/seg.c | 54 ++++++++++---------------- mld/symtab.c | 4 ++ 5 files changed, 154 insertions(+), 63 deletions(-) diff --git a/mld/link.c b/mld/link.c index 032c275..8e61ce2 100644 --- a/mld/link.c +++ b/mld/link.c @@ -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) diff --git a/mld/link.h b/mld/link.h index 435a8d5..93a2ccd 100644 --- a/mld/link.h +++ b/mld/link.h @@ -35,6 +35,9 @@ #define TEXT_VADDR_MIN 0x00400000 #define DATA_VADDR_MIN 0x10000000 +// alignment of a section +#define SEC_ALIGN 0x1000 + // pre define struct linker; struct object; @@ -42,6 +45,7 @@ struct segment; struct string_table; struct symbol_table; struct symbol_table_mapping; +struct glboff_table; /// /// relocation table @@ -220,6 +224,10 @@ struct object { // program table Elf32_Phdr *phdr; size_t phdr_len; + bool phdr_local; // if phdr was created though malloc + + // phdr <=> shdr mappings + uint32_t *phdr_to_shdr_mapping; // object meta const char *name; diff --git a/mld/obj.c b/mld/obj.c index b065316..e986a75 100644 --- a/mld/obj.c +++ b/mld/obj.c @@ -49,10 +49,10 @@ static int load_ehdr(struct object *object) EHDR_ASSERT(type, sizeof(Elf32_Half)); EHDR_ASSERT(machine, sizeof(Elf32_Half)); EHDR_ASSERT(version, sizeof(Elf32_Word)); - EHDR_ASSERT(flags, sizeof(Elf32_Word)); + // EHDR_ASSERT(flags, sizeof(Elf32_Word)); EHDR_ASSERT(ehsize, sizeof(Elf32_Half)); - EHDR_ASSERT(phentsize, sizeof(Elf32_Half)); - EHDR_ASSERT(shentsize, sizeof(Elf32_Half)); + // EHDR_ASSERT(phentsize, sizeof(Elf32_Half)); + // EHDR_ASSERT(shentsize, sizeof(Elf32_Half)); #undef EHDR_ASSERT @@ -81,23 +81,94 @@ static int load_shdr(struct object *object) return M_SUCCESS; } +/** + * Create the phdr + */ +static int create_phdr(struct object *object) +{ + uint32_t entries = 0; + for (uint32_t i = 0; i < object->shdr_len; i++) { + Elf32_Shdr *hdr = &object->shdr[i]; + uint32_t type = B32(hdr->sh_type); + + if (type != SHT_PROGBITS && type != SHT_NOBITS) + continue; + + entries += 1; + } + + Elf32_Phdr *phdr = malloc(entries * sizeof(Elf32_Phdr)); + if (phdr == NULL) { + PERROR("cannot alloc"); + return M_ERROR; + } + + object->phdr = phdr; + object->phdr_len = entries; + object->phdr_local = true; + + uint32_t *mapping = malloc(entries * sizeof(uint32_t)); + if (mapping == NULL) { + PERROR("cannot alloc"); + return M_ERROR; + } + + object->phdr_to_shdr_mapping = mapping; + + uint32_t index = 0; + for (uint32_t i = 0; i < object->shdr_len; i++) { + Elf32_Shdr *hdr = &object->shdr[i]; + uint32_t type = B32(hdr->sh_type); + + if (type != SHT_PROGBITS && type != SHT_NOBITS) + continue; + mapping[index] = i; + phdr[index++] = (Elf32_Phdr) { + .p_type = B32(PT_LOAD), + .p_flags = B32( + // execute + ((B32(hdr->sh_flags) & SHF_EXECINSTR) + ? PF_X : 0) | + // write + ((B32(hdr->sh_flags) & SHF_WRITE) + ? PF_W : 0) | + // read + ((B32(hdr->sh_flags) & SHF_ALLOC) + ? PF_R : 0) + ), + .p_offset = hdr->sh_offset, + .p_vaddr = hdr->sh_addr, + .p_paddr = hdr->sh_addr, + .p_filesz = hdr->sh_size, + .p_memsz = hdr->sh_size, + .p_align = B32(SEC_ALIGN), + }; + } + + return M_SUCCESS; +} + /** * Map the phdr */ static int load_phdr(struct object *object) { - size_t phdr_len = B16(object->ehdr->e_phentsize) * - B16(object->ehdr->e_phnum); - size_t phdr_off = B32(object->ehdr->e_phoff); - object->phdr = (Elf32_Phdr *) (object->mapped + phdr_off); - object->phdr_len = B16(object->ehdr->e_phnum); + //size_t phdr_len = B16(object->ehdr->e_phentsize) * + // B16(object->ehdr->e_phnum); - if (BOUND_CHK(object, phdr_len, phdr_off)) { - ERROR("cannot read phdr"); - return M_ERROR; - } + //if (phdr_len < 1) + return create_phdr(object); - return M_SUCCESS; + //size_t phdr_off = B32(object->ehdr->e_phoff); + //object->phdr = (Elf32_Phdr *) (object->mapped + phdr_off); + //object->phdr_len = B16(object->ehdr->e_phnum); + + //if (BOUND_CHK(object, phdr_len, phdr_off)) { + // ERROR("cannot read phdr"); + // return M_ERROR; + //} + + //return M_SUCCESS; } /** @@ -231,7 +302,7 @@ static int load_shstrtab(struct object *object) */ static int load_segments(struct object *object) { - object->segment_len = B16(object->ehdr->e_phnum); + object->segment_len = object->phdr_len; object->segments = malloc(sizeof(struct segment) * object->segment_len); @@ -287,6 +358,8 @@ int object_load(struct object *object, char *path, uint32_t index) object->mapped = NULL; object->name = path; object->index = index; + object->phdr_local = false; + object->phdr_to_shdr_mapping = NULL; /** load the file */ if (map_file(object, path)) @@ -331,6 +404,10 @@ void object_free(struct object *obj) free(obj->strtabs); if (obj->segments != NULL) free(obj->segments); + if (obj->phdr_local) + free(obj->phdr); + if (obj->phdr_to_shdr_mapping) + free(obj->phdr_to_shdr_mapping); if (obj->fd > 0) close(obj->fd); if (obj->mapped != NULL && obj->mapped != MAP_FAILED) diff --git a/mld/seg.c b/mld/seg.c index 61c5296..61c337a 100644 --- a/mld/seg.c +++ b/mld/seg.c @@ -25,43 +25,29 @@ static int load_phdr(struct object *obj, struct segment *seg, size_t index) */ static int load_shdr(struct object *obj, struct segment *seg, size_t index) { - bool found = false; + uint32_t shndx = obj->phdr_to_shdr_mapping[index]; + Elf32_Shdr *hdr = &obj->shdr[shndx]; - for (size_t i = 0; i < obj->shdr_len; i++) { - Elf32_Shdr *hdr = &obj->shdr[i]; - - // find shdr that matches the offset in phdr - if (!PHDR_SHDR_MATCH(seg->phdr, hdr)) - continue; - - // get name - uint32_t name = B32(hdr->sh_name); - if (name >= obj->shstrtab->len) { - ERROR("section name index [%d] out of bounds", name); - return M_ERROR; - } - seg->name = &obj->shstrtab->data[name]; - - // map bytes - uint32_t len = B32(hdr->sh_size); - uint32_t off = B32(hdr->sh_offset); - seg->bytes = (unsigned char *) (obj->mapped + off); - - if (BOUND_CHK(obj, len, off)) { - ERROR("cannot map seg %s:%d", seg->name, index); - return M_ERROR; - } - - found = true; - seg->shdr = hdr; - seg->shdr_idx = i; - break; - } - - if (!found) { - ERROR("cannot find shdr for segment [%d]", index); + // get name + uint32_t name = B32(hdr->sh_name); + if (name >= obj->shstrtab->len) { + ERROR("section name index [%d] out of bounds", name); return M_ERROR; } + seg->name = &obj->shstrtab->data[name]; + + // map bytes + uint32_t len = B32(hdr->sh_size); + uint32_t off = B32(hdr->sh_offset); + seg->bytes = (unsigned char *) (obj->mapped + off); + + if (BOUND_CHK(obj, len, off)) { + ERROR("cannot map seg %s:%d", seg->name, index); + return M_ERROR; + } + + seg->shdr = hdr; + seg->shdr_idx = shndx; return M_SUCCESS; } diff --git a/mld/symtab.c b/mld/symtab.c index 9417673..314a1c3 100644 --- a/mld/symtab.c +++ b/mld/symtab.c @@ -56,6 +56,10 @@ int symtab_get(struct symbol_table *symtab, Elf32_Sym **res, const char *name, if (strcmp(name, symname) != 0) continue; + // ignore absolute symbols + if (B16(sym->st_shndx) == SHN_ABS) + continue; + // only allow retrevial of local variables from the // same object if (sym->st_info >> 4 != STB_GLOBAL && symtab->map != NULL &&