From 31a268f63f649cbe1cbcd5047e3a5d7d30f7c397 Mon Sep 17 00:00:00 2001 From: norly Date: Sat, 15 Jun 2013 22:21:57 +0100 Subject: [PATCH] Factor out symbol table handling --- include/libelfu/modelops.h | 7 ++ src/modelops/relocate.c | 139 +---------------------- src/modelops/symtab.c | 223 +++++++++++++++++++++++++++++++++++++ src/modelops/toFile.c | 82 +------------- 4 files changed, 235 insertions(+), 216 deletions(-) create mode 100644 src/modelops/symtab.c diff --git a/include/libelfu/modelops.h b/include/libelfu/modelops.h index 40d0ade..cf11b20 100644 --- a/include/libelfu/modelops.h +++ b/include/libelfu/modelops.h @@ -10,6 +10,13 @@ #define ELFU_SYMSTR(symtabscn, off) (((char*)(symtabscn)->linkptr->data.d_buf) + (off)) +GElf_Word elfu_mSymtabLookupVal(ElfuElf *me, ElfuScn *msst, GElf_Word entry); +void elfu_mSymtabFlatten(ElfuElf *me); + + +void elfu_mRelocate(ElfuElf *metarget, ElfuScn *mstarget, ElfuScn *msrt); + + size_t elfu_mPhdrCount(ElfuElf *me); void elfu_mPhdrUpdateChildOffsets(ElfuPhdr *mp); diff --git a/src/modelops/relocate.c b/src/modelops/relocate.c index f04b7c0..90a319b 100644 --- a/src/modelops/relocate.c +++ b/src/modelops/relocate.c @@ -4,139 +4,8 @@ #include -static void* subFindByName(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2) -{ - char *name = (char*)aux1; - (void)aux2; - - if (elfu_mScnName(me, ms)) { - if (!strcmp(elfu_mScnName(me, ms), name)) { - return ms; - } - } - - /* Continue */ - return NULL; -} - -/* Hazard a guess where a function may be found in the PLT */ -static GElf_Word pltLookupVal(ElfuElf *metarget, char *name) -{ - ElfuScn *relplt; - ElfuScn *plt; - ElfuRel *rel; - GElf_Word j; - - relplt = elfu_mScnForall(metarget, subFindByName, ".rel.plt", NULL); - if (!relplt) { - ELFU_WARN("dynsymLookupVal: Could not find .rel.plt section in destination ELF.\n"); - return 0; - } - - plt = elfu_mScnForall(metarget, subFindByName, ".plt", NULL); - if (!plt) { - ELFU_WARN("dynsymLookupVal: Could not find .plt section in destination ELF.\n"); - return 0; - } - - - /* Look up name. If the j-th entry in .rel.plt has the name we are - * looking for, we assume that the (j+1)-th entry in .plt is machine - * code to jump to the function. - * Your mileage may vary, but it works on my GNU binaries. */ - assert(relplt->linkptr); - j = 0; - CIRCLEQ_FOREACH(rel, &relplt->reltab.rels, elem) { - GElf_Word i; - ElfuSym *sym; - char *symname; - - j++; - - /* We only consider runtime relocations for functions. - * Technically, these relocations write the functions' addresses - * to the GOT, not the PLT, after the dynamic linker has found - * them. */ - if ((metarget->elfclass == ELFCLASS32 && rel->type != R_386_JMP_SLOT) - || (metarget->elfclass == ELFCLASS64 && rel->type != R_X86_64_JUMP_SLOT)) { - continue; - } - - /* Get the (rel->sym)-th symbol from the symbol table that - * .rel.plt points to. */ - sym = CIRCLEQ_FIRST(&relplt->linkptr->symtab.syms); - for (i = 1; i < rel->sym; i++) { - sym = CIRCLEQ_NEXT(sym, elem); - } - - symname = ELFU_SYMSTR(relplt->linkptr, sym->name); - if (!strcmp(symname, name)) { - /* If this is the symbol we are looking for, then in an x86 binary - * the jump to the dynamic symbol is probably at offset (j * 16) - * from the start of the PLT, where j is the PLT entry and 16 is - * the number of bytes the machine code in a PLT entry take. */ - GElf_Addr addr = plt->shdr.sh_addr + (16 * j); - ELFU_DEBUG("dynsymLookupVal: Guessing symbol '%s' is in destination memory at %jx (PLT entry #%d).\n", name, addr, j); - return addr; - } - } - - ELFU_WARN("dynsymLookupVal: Could not find symbol '%s' in destination ELF.\n", name); - - return 0; -} - - -static GElf_Word symtabLookupVal(ElfuElf *metarget, ElfuScn *msst, GElf_Word entry) -{ - GElf_Word i; - ElfuSym *sym; - char *symname; - - assert(metarget); - assert(msst); - assert(entry > 0); - assert(!CIRCLEQ_EMPTY(&msst->symtab.syms)); - - sym = CIRCLEQ_FIRST(&msst->symtab.syms); - for (i = 1; i < entry; i++) { - sym = CIRCLEQ_NEXT(sym, elem); - } - symname = ELFU_SYMSTR(msst, sym->name); - - switch (sym->type) { - case STT_NOTYPE: - case STT_OBJECT: - case STT_FUNC: - if (sym->scnptr) { - ElfuScn *newscn = elfu_mScnByOldscn(metarget, sym->scnptr); - assert(newscn); - return newscn->shdr.sh_addr + sym->value; - } else if (sym->shndx == SHN_UNDEF) { - /* Look the symbol up in .rel.plt. If it cannot be found there then - * .rel.dyn may need to be expanded with a COPY relocation so the - * dynamic linker fixes up the (TODO). */ - return pltLookupVal(metarget, symname); - } else if (sym->shndx == SHN_ABS) { - return sym->value; - } else { - ELFU_WARN("symtabLookupVal: Symbol binding COMMON is not supported, using 0.\n"); - return 0; - } - break; - case STT_SECTION: - assert(sym->scnptr); - assert(elfu_mScnByOldscn(metarget, sym->scnptr)); - return elfu_mScnByOldscn(metarget, sym->scnptr)->shdr.sh_addr; - case STT_FILE: - ELFU_WARN("symtabLookupVal: Symbol type FILE is not supported, using 0.\n"); - return 0; - default: - ELFU_WARN("symtabLookupVal: Unknown symbol type %d for %s.\n", sym->type, symname); - return 0; - } -} - +/* Apply relocation information from section *msrt to data in + * section *mstarget (which is stored in *metarget). */ void elfu_mRelocate(ElfuElf *metarget, ElfuScn *mstarget, ElfuScn *msrt) { ElfuRel *rel; @@ -156,7 +25,7 @@ void elfu_mRelocate(ElfuElf *metarget, ElfuScn *mstarget, ElfuScn *msrt) 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); + Elf32_Addr s32 = elfu_mSymtabLookupVal(metarget, msrt->linkptr, rel->sym); switch(rel->type) { case R_386_NONE: ELFU_DEBUG("Skipping relocation: R_386_NONE\n"); @@ -176,7 +45,7 @@ void elfu_mRelocate(ElfuElf *metarget, ElfuScn *mstarget, ElfuScn *msrt) 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); + Elf64_Addr s64 = elfu_mSymtabLookupVal(metarget, msrt->linkptr, rel->sym); switch(rel->type) { case R_X86_64_NONE: diff --git a/src/modelops/symtab.c b/src/modelops/symtab.c new file mode 100644 index 0000000..a7c1485 --- /dev/null +++ b/src/modelops/symtab.c @@ -0,0 +1,223 @@ +#include +#include +#include +#include + + +static void* subFindByName(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2) +{ + char *name = (char*)aux1; + (void)aux2; + + if (elfu_mScnName(me, ms)) { + if (!strcmp(elfu_mScnName(me, ms), name)) { + return ms; + } + } + + /* Continue */ + return NULL; +} + +/* Hazard a guess where a function may be found in the PLT */ +static GElf_Word pltLookupVal(ElfuElf *me, char *name) +{ + ElfuScn *relplt; + ElfuScn *plt; + ElfuRel *rel; + GElf_Word j; + + relplt = elfu_mScnForall(me, subFindByName, ".rel.plt", NULL); + if (!relplt) { + ELFU_WARN("dynsymLookupVal: Could not find .rel.plt section in destination ELF.\n"); + return 0; + } + + plt = elfu_mScnForall(me, subFindByName, ".plt", NULL); + if (!plt) { + ELFU_WARN("dynsymLookupVal: Could not find .plt section in destination ELF.\n"); + return 0; + } + + + /* Look up name. If the j-th entry in .rel.plt has the name we are + * looking for, we assume that the (j+1)-th entry in .plt is machine + * code to jump to the function. + * Your mileage may vary, but it works on my GNU binaries. */ + assert(relplt->linkptr); + j = 0; + CIRCLEQ_FOREACH(rel, &relplt->reltab.rels, elem) { + GElf_Word i; + ElfuSym *sym; + char *symname; + + j++; + + /* We only consider runtime relocations for functions. + * Technically, these relocations write the functions' addresses + * to the GOT, not the PLT, after the dynamic linker has found + * them. */ + if ((me->elfclass == ELFCLASS32 && rel->type != R_386_JMP_SLOT) + || (me->elfclass == ELFCLASS64 && rel->type != R_X86_64_JUMP_SLOT)) { + continue; + } + + /* Get the (rel->sym)-th symbol from the symbol table that + * .rel.plt points to. */ + sym = CIRCLEQ_FIRST(&relplt->linkptr->symtab.syms); + for (i = 1; i < rel->sym; i++) { + sym = CIRCLEQ_NEXT(sym, elem); + } + + symname = ELFU_SYMSTR(relplt->linkptr, sym->name); + if (!strcmp(symname, name)) { + /* If this is the symbol we are looking for, then in an x86 binary + * the jump to the dynamic symbol is probably at offset (j * 16) + * from the start of the PLT, where j is the PLT entry and 16 is + * the number of bytes the machine code in a PLT entry take. */ + GElf_Addr addr = plt->shdr.sh_addr + (16 * j); + ELFU_DEBUG("dynsymLookupVal: Guessing symbol '%s' is in destination memory at %jx (PLT entry #%d).\n", name, addr, j); + return addr; + } + } + + ELFU_WARN("dynsymLookupVal: Could not find symbol '%s' in destination ELF.\n", name); + + return 0; +} + + + +/* Look up a value in the symbol table section *msst which is in *me. + * If it is not found there, see if we can find it in *me's PLT. */ +GElf_Word elfu_mSymtabLookupVal(ElfuElf *me, ElfuScn *msst, GElf_Word entry) +{ + GElf_Word i; + ElfuSym *sym; + char *symname; + + assert(me); + assert(msst); + assert(entry > 0); + assert(!CIRCLEQ_EMPTY(&msst->symtab.syms)); + + sym = CIRCLEQ_FIRST(&msst->symtab.syms); + for (i = 1; i < entry; i++) { + sym = CIRCLEQ_NEXT(sym, elem); + } + symname = ELFU_SYMSTR(msst, sym->name); + + switch (sym->type) { + case STT_NOTYPE: + case STT_OBJECT: + case STT_FUNC: + if (sym->scnptr) { + ElfuScn *newscn = elfu_mScnByOldscn(me, sym->scnptr); + assert(newscn); + return newscn->shdr.sh_addr + sym->value; + } else if (sym->shndx == SHN_UNDEF) { + /* Look the symbol up in .rel.plt. If it cannot be found there then + * .rel.dyn may need to be expanded with a COPY relocation so the + * dynamic linker fixes up the (TODO). */ + return pltLookupVal(me, symname); + } else if (sym->shndx == SHN_ABS) { + return sym->value; + } else { + ELFU_WARN("symtabLookupVal: Symbol binding COMMON is not supported, using 0.\n"); + return 0; + } + break; + case STT_SECTION: + assert(sym->scnptr); + assert(elfu_mScnByOldscn(me, sym->scnptr)); + return elfu_mScnByOldscn(me, sym->scnptr)->shdr.sh_addr; + case STT_FILE: + ELFU_WARN("symtabLookupVal: Symbol type FILE is not supported, using 0.\n"); + return 0; + default: + ELFU_WARN("symtabLookupVal: Unknown symbol type %d for %s.\n", sym->type, symname); + return 0; + } +} + + + +/* Convert symtab from memory model to elfclass specific format */ +void elfu_mSymtabFlatten(ElfuElf *me) +{ + ElfuSym *sym; + size_t numsyms = 0; + + elfu_mLayoutAuto(me); + + /* Update section indexes and count symbols */ + CIRCLEQ_FOREACH(sym, &me->symtab->symtab.syms, elem) { + if (sym->scnptr) { + sym->shndx = elfu_mScnIndex(me, sym->scnptr); + } + + numsyms++; + } + + /* Copy symbols to elfclass-specific format */ + if (me->elfclass == ELFCLASS32) { + size_t newsize = (numsyms + 1) * sizeof(Elf32_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) { + Elf32_Sym *es = ((Elf32_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 = ELF32_ST_INFO(sym->bind, sym->type); + es->st_other = sym->other; + es->st_shndx = sym->shndx; + + i++; + } + } else if (me->elfclass == ELFCLASS64) { + 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 { + // Unknown elfclass + assert(0); + } + + elfu_mLayoutAuto(me); +} diff --git a/src/modelops/toFile.c b/src/modelops/toFile.c index 90dc247..1fec8b0 100644 --- a/src/modelops/toFile.c +++ b/src/modelops/toFile.c @@ -4,86 +4,6 @@ #include -static void flattenSymtab(ElfuElf *me) -{ - ElfuSym *sym; - size_t numsyms = 0; - - elfu_mLayoutAuto(me); - - /* Update section indexes and count symbols */ - CIRCLEQ_FOREACH(sym, &me->symtab->symtab.syms, elem) { - if (sym->scnptr) { - sym->shndx = elfu_mScnIndex(me, sym->scnptr); - } - - numsyms++; - } - - /* Copy symbols to elfclass-specific format */ - if (me->elfclass == ELFCLASS32) { - size_t newsize = (numsyms + 1) * sizeof(Elf32_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) { - Elf32_Sym *es = ((Elf32_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 = ELF32_ST_INFO(sym->bind, sym->type); - es->st_other = sym->other; - es->st_shndx = sym->shndx; - - i++; - } - } else if (me->elfclass == ELFCLASS64) { - 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 { - // Unknown elfclass - assert(0); - } - - elfu_mLayoutAuto(me); -} - - static void modelToPhdrs(ElfuElf *me, Elf *e) { ElfuPhdr *mp; @@ -163,7 +83,7 @@ static void* modelToSection(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2) void elfu_mToElf(ElfuElf *me, Elf *e) { if (me->symtab) { - flattenSymtab(me); + elfu_mSymtabFlatten(me); } -- 2.30.2