From 825613b8e4f141a82d2b8be22d7fba68fed5ef96 Mon Sep 17 00:00:00 2001 From: norly Date: Sat, 15 Jun 2013 21:42:53 +0100 Subject: [PATCH] Basic x86-64 support, not very usable in practice Turns out that x86-64 aligns LOAD segments to 0x200000 bytes. Given that the mapping starts at 0x400000, there is not much room to expand... so there will be a need to add additional LOAD headers. --- src/elfops/check.c | 4 +- src/modelops/fromFile.c | 100 +++++++++++++++++++++++++++++----------- src/modelops/relocate.c | 74 +++++++++++++++++++---------- src/modelops/toFile.c | 30 ++++++++++-- 4 files changed, 153 insertions(+), 55 deletions(-) diff --git a/src/elfops/check.c b/src/elfops/check.c index 6e56bae..e184b26 100644 --- a/src/elfops/check.c +++ b/src/elfops/check.c @@ -24,8 +24,8 @@ int elfu_eCheck(Elf *e) goto ERROR; } - if (ehdr.e_machine != EM_386) { - ELFU_WARN("Sorry, only x86-32 ELF files are supported at the moment.\n"); + if (ehdr.e_machine != EM_386 && ehdr.e_machine != EM_X86_64) { + ELFU_WARN("Sorry, only x86-32 and x86-64 ELF files are supported at the moment.\n"); goto ERROR; } diff --git a/src/modelops/fromFile.c b/src/modelops/fromFile.c index 28ecb85..bc089bf 100644 --- a/src/modelops/fromFile.c +++ b/src/modelops/fromFile.c @@ -5,41 +5,69 @@ #include -static void parseSymtab32(ElfuScn *ms, ElfuScn**origScnArr) +static void parseSymtab(ElfuElf *me, ElfuScn *ms, ElfuScn**origScnArr) { + ElfuSym *sym; size_t i; assert(ms); assert(ms->data.d_buf); assert(origScnArr); + /* Parse symbols from their elfclass-specific format */ + if (me->elfclass == ELFCLASS32) { + for (i = 1; (i + 1) * sizeof(Elf32_Sym) <= ms->shdr.sh_size; i++) { + Elf32_Sym *cursym = ((Elf32_Sym*)ms->data.d_buf) + i; + ElfuSym *newsym = malloc(sizeof(*sym)); + assert(newsym); - for (i = 1; (i + 1) * sizeof(Elf32_Sym) <= ms->shdr.sh_size; i++) { - Elf32_Sym *cursym = &(((Elf32_Sym*)ms->data.d_buf)[i]); - ElfuSym *sym = malloc(sizeof(*sym)); - assert(sym); + newsym->name = cursym->st_name; + newsym->value = cursym->st_value; + newsym->size = cursym->st_size; + newsym->bind = ELF32_ST_BIND(cursym->st_info); + newsym->type = ELF32_ST_TYPE(cursym->st_info); + newsym->other = cursym->st_other; + newsym->shndx = cursym->st_shndx; - sym->name = cursym->st_name; - sym->value = cursym->st_value; - sym->size = cursym->st_size; - sym->bind = ELF32_ST_BIND(cursym->st_info); - sym->type = ELF32_ST_TYPE(cursym->st_info); - sym->other = cursym->st_other; - sym->shndx = cursym->st_shndx; - switch (cursym->st_shndx) { + + CIRCLEQ_INSERT_TAIL(&ms->symtab.syms, newsym, elem); + } + } else if (me->elfclass == ELFCLASS64) { + for (i = 1; (i + 1) * sizeof(Elf64_Sym) <= ms->shdr.sh_size; i++) { + Elf64_Sym *cursym = ((Elf64_Sym*)ms->data.d_buf) + i; + ElfuSym *newsym = malloc(sizeof(*sym)); + assert(newsym); + + newsym->name = cursym->st_name; + newsym->value = cursym->st_value; + newsym->size = cursym->st_size; + newsym->bind = ELF64_ST_BIND(cursym->st_info); + newsym->type = ELF64_ST_TYPE(cursym->st_info); + newsym->other = cursym->st_other; + newsym->shndx = cursym->st_shndx; + + + + CIRCLEQ_INSERT_TAIL(&ms->symtab.syms, newsym, elem); + } + } else { + // Unknown elfclass + assert(0); + } + + /* For each section, find the section it points to if any. */ + CIRCLEQ_FOREACH(sym, &ms->symtab.syms, elem) { + switch (sym->shndx) { case SHN_UNDEF: case SHN_ABS: case SHN_COMMON: sym->scnptr = NULL; break; default: - sym->scnptr = origScnArr[cursym->st_shndx - 1]; + sym->scnptr = origScnArr[sym->shndx - 1]; break; } - - - CIRCLEQ_INSERT_TAIL(&ms->symtab.syms, sym, elem); } } @@ -60,10 +88,8 @@ static void parseReltab32(ElfuScn *ms) assert(rel); rel->offset = currel->r_offset; - rel->sym = ELF32_R_SYM(currel->r_info); rel->type = ELF32_R_TYPE(currel->r_info); - rel->addendUsed = 0; rel->addend = 0; @@ -72,6 +98,32 @@ static void parseReltab32(ElfuScn *ms) } +static void parseRelatab64(ElfuScn *ms) +{ + size_t i; + + assert(ms); + assert(ms->data.d_buf); + + + for (i = 0; (i + 1) * sizeof(Elf64_Rela) <= ms->shdr.sh_size; i++) { + Elf64_Rela *currel = &(((Elf64_Rela*)ms->data.d_buf)[i]); + ElfuRel *rel; + + rel = malloc(sizeof(*rel)); + assert(rel); + + rel->offset = currel->r_offset; + rel->sym = ELF64_R_SYM(currel->r_info); + rel->type = ELF64_R_TYPE(currel->r_info); + rel->addendUsed = 1; + rel->addend = currel->r_addend; + + CIRCLEQ_INSERT_TAIL(&ms->reltab.rels, rel, elem); + } +} + + static int cmpScnOffs(const void *ms1, const void *ms2) { assert(ms1); @@ -360,11 +412,7 @@ ElfuElf* elfu_mFromElf(Elf *e) case SHT_SYMTAB: me->symtab = ms; case SHT_DYNSYM: - if (me->elfclass == ELFCLASS32) { - parseSymtab32(ms, secArray); - } else if (me->elfclass == ELFCLASS64) { - // TODO - } + parseSymtab(me, ms, secArray); break; } } @@ -379,14 +427,14 @@ ElfuElf* elfu_mFromElf(Elf *e) if (me->elfclass == ELFCLASS32) { parseReltab32(ms); } else if (me->elfclass == ELFCLASS64) { - // TODO + // Not used on x86-64 } break; case SHT_RELA: if (me->elfclass == ELFCLASS32) { // TODO } else if (me->elfclass == ELFCLASS64) { - // TODO + parseRelatab64(ms); } break; } diff --git a/src/modelops/relocate.c b/src/modelops/relocate.c index ea84937..2c9873c 100644 --- a/src/modelops/relocate.c +++ b/src/modelops/relocate.c @@ -57,7 +57,8 @@ static GElf_Word pltLookupVal(ElfuElf *metarget, char *name) * Technically, these relocations write the functions' addresses * to the GOT, not the PLT, after the dynamic linker has found * them. */ - if (rel->type != R_386_JMP_SLOT) { + if ((metarget->elfclass == ELFCLASS32 && rel->type != R_386_JMP_SLOT) + || (metarget->elfclass == ELFCLASS64 && rel->type != R_X86_64_JUMP_SLOT)) { continue; } @@ -148,29 +149,54 @@ void elfu_mRelocate32(ElfuElf *metarget, ElfuScn *mstarget, ElfuScn *msrt) mstarget->shdr.sh_size); CIRCLEQ_FOREACH(rel, &msrt->reltab.rels, elem) { - Elf32_Word *dest = (Elf32_Word*)(((char*)(mstarget->data.d_buf)) + rel->offset); - Elf32_Word a = rel->addendUsed ? rel->addend : *dest; - Elf32_Addr p = mstarget->shdr.sh_addr + rel->offset; - Elf32_Addr s = symtabLookupVal(metarget, msrt->linkptr, rel->sym); - Elf32_Word newval = *dest; - - switch(rel->type) { - case R_386_NONE: - ELFU_DEBUG("Skipping relocation: R_386_NONE"); - break; - case R_386_32: - ELFU_DEBUG("Relocation: R_386_32"); - newval = s + a; - break; - case R_386_PC32: - ELFU_DEBUG("Relocation: R_386_PC32"); - newval = s + a - p; - break; - - default: - ELFU_DEBUG("Skipping relocation: Unknown type %d", rel->type); + Elf32_Word *dest32 = (Elf32_Word*)(((char*)(mstarget->data.d_buf)) + rel->offset); + Elf64_Word *dest64 = (Elf64_Word*)(((char*)(mstarget->data.d_buf)) + rel->offset); + + + if (metarget->elfclass == ELFCLASS32) { + Elf32_Word a32 = rel->addendUsed ? rel->addend : *dest32; + Elf32_Addr p32 = mstarget->shdr.sh_addr + rel->offset; + Elf32_Addr s32 = symtabLookupVal(metarget, msrt->linkptr, rel->sym); + switch(rel->type) { + case R_386_NONE: + ELFU_DEBUG("Skipping relocation: R_386_NONE\n"); + break; + case R_386_32: + *dest32 = s32 + a32; + break; + case R_386_PC32: + *dest32 = s32 + a32 - p32; + break; + + default: + ELFU_DEBUG("Skipping relocation: Unknown type %d\n", rel->type); + } + } else if (metarget->elfclass == ELFCLASS64) { + /* x86-64 only uses RELA with explicit addend. */ + assert(rel->addendUsed); + Elf64_Word a64 = rel->addend; + Elf64_Addr p64 = mstarget->shdr.sh_addr + rel->offset; + Elf64_Addr s64 = symtabLookupVal(metarget, msrt->linkptr, rel->sym); + + switch(rel->type) { + case R_X86_64_NONE: + ELFU_DEBUG("Skipping relocation: R_386_NONE\n"); + break; + case R_X86_64_64: + *dest64 = s64 + a64; + break; + case R_X86_64_PC32: + *dest32 = s64 + a64 - p64; + break; + case R_X86_64_32: + *dest32 = s64 + a64; + break; + + default: + ELFU_DEBUG("Skipping relocation: Unknown type %d", rel->type); + } } - ELFU_DEBUG(", overwriting %x with %x.\n", *dest, newval); - *dest = newval; + + } } diff --git a/src/modelops/toFile.c b/src/modelops/toFile.c index 434130e..90dc247 100644 --- a/src/modelops/toFile.c +++ b/src/modelops/toFile.c @@ -49,10 +49,34 @@ static void flattenSymtab(ElfuElf *me) i++; } } else if (me->elfclass == ELFCLASS64) { - // TODO - assert(0); + size_t newsize = (numsyms + 1) * sizeof(Elf64_Sym); + size_t i; + + if (me->symtab->data.d_buf) { + free(me->symtab->data.d_buf); + } + me->symtab->data.d_buf = malloc(newsize); + assert(me->symtab->data.d_buf); + + me->symtab->data.d_size = newsize; + me->symtab->shdr.sh_size = newsize; + memset(me->symtab->data.d_buf, 0, newsize); + + i = 1; + CIRCLEQ_FOREACH(sym, &me->symtab->symtab.syms, elem) { + Elf64_Sym *es = ((Elf64_Sym*)me->symtab->data.d_buf) + i; + + es->st_name = sym->name; + es->st_value = sym->value; + es->st_size = sym->size; + es->st_info = ELF64_ST_INFO(sym->bind, sym->type); + es->st_other = sym->other; + es->st_shndx = sym->shndx; + + i++; + } } else { - // Never reached + // Unknown elfclass assert(0); } -- 2.30.2