diff options
Diffstat (limited to 'src/libelfu/model/symtab.c')
-rw-r--r-- | src/libelfu/model/symtab.c | 157 |
1 files changed, 43 insertions, 114 deletions
diff --git a/src/libelfu/model/symtab.c b/src/libelfu/model/symtab.c index 1dd778e..0cf107b 100644 --- a/src/libelfu/model/symtab.c +++ b/src/libelfu/model/symtab.c @@ -4,103 +4,62 @@ #include <libelfu/libelfu.h> -static void* subFindByName(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2) +int elfu_mSymtabLookupSymToAddr(ElfuElf *me, ElfuScn *msst, ElfuSym *sym, GElf_Addr *result) { - char *name = (char*)aux1; - (void)aux2; + char *symname = ELFU_SYMSTR(msst, sym->name); - 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) { - /* x86-64 uses .rela.plt instead */ - relplt = elfu_mScnForall(me, subFindByName, ".rela.plt", NULL); - } - if (!relplt) { - ELFU_WARN("dynsymLookupVal: Could not find .rel.plt section in destination ELF.\n"); - return 0; - } + switch (sym->type) { + case STT_NOTYPE: + case STT_OBJECT: + case STT_FUNC: + if (sym->shndx == SHN_UNDEF) { + return -1; + } else if (sym->shndx == SHN_ABS) { + *result = sym->value; + return 0; + } else if (sym->shndx == SHN_COMMON) { + return -1; + } else { + ElfuScn *newscn; - plt = elfu_mScnForall(me, subFindByName, ".plt", NULL); - if (!plt) { - ELFU_WARN("dynsymLookupVal: Could not find .plt section in destination ELF.\n"); - return 0; + assert (sym->scnptr); + newscn = elfu_mScnByOldscn(me, sym->scnptr); + assert(newscn); + *result = newscn->shdr.sh_addr + sym->value; + return 0; + } + break; + case STT_SECTION: + assert(sym->scnptr); + assert(elfu_mScnByOldscn(me, sym->scnptr)); + *result = elfu_mScnByOldscn(me, sym->scnptr)->shdr.sh_addr; + return 0; + case STT_FILE: + ELFU_WARN("elfu_mSymtabLookupSymToAddr: Symbol type FILE is not supported.\n"); + return -1; + default: + ELFU_WARN("elfu_mSymtabLookupSymToAddr: Unknown symbol type %d for %s.\n", sym->type, symname); + return -1; } +} - /* 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 %x (PLT entry #%u).\n", name, (unsigned)addr, j); - return addr; - } - } - - ELFU_WARN("dynsymLookupVal: Could not find symbol '%s' in destination ELF.\n", name); +char* elfu_mSymtabSymToName(ElfuScn *msst, ElfuSym *sym) +{ + assert(msst); + assert(sym); - return 0; + return ELFU_SYMSTR(msst, sym->name); } -/* 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) +ElfuSym* elfu_mSymtabIndexToSym(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)); @@ -109,44 +68,14 @@ GElf_Word elfu_mSymtabLookupVal(ElfuElf *me, ElfuScn *msst, GElf_Word entry) 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; - } + return sym; } + /* Look up a value in the symbol table section *msst which is in *me. */ -GElf_Word elfu_mSymtabLookupAddrByName(ElfuElf *me, ElfuScn *msst, char *name) +GElf_Addr elfu_mSymtabLookupAddrByName(ElfuElf *me, ElfuScn *msst, char *name) { ElfuSym *sym; |