From 1ca19c5484ee0f18a3701b3f98ac8ca43df8b505 Mon Sep 17 00:00:00 2001 From: norly Date: Thu, 27 Jun 2013 01:00:17 +0100 Subject: [PATCH] Lookup dynamically linked global variables. This works ONLY in position-dependent executables. Processing position-independent code includes generating and inserting code that finds out the current instruction address. That's beyond the scope of editing normal executables, which are usually position-dependent unless requested otherwise. --- include/libelfu/modelops.h | 1 + src/libelfu/modelops/dynlookup.c | 57 ++++++++++++++++++++++++++++++++ src/libelfu/modelops/relocate.c | 7 ++-- 3 files changed, 63 insertions(+), 2 deletions(-) diff --git a/include/libelfu/modelops.h b/include/libelfu/modelops.h index 3ebf0a3..e9ea9ee 100644 --- a/include/libelfu/modelops.h +++ b/include/libelfu/modelops.h @@ -54,6 +54,7 @@ int elfu_mLayoutAuto(ElfuElf *me); int elfu_mDynLookupPltAddrByName(ElfuElf *me, char *name, GElf_Addr *result); +int elfu_mDynLookupReldynAddrByName(ElfuElf *me, char *name, GElf_Addr *result); int elfu_mRelocate(ElfuElf *metarget, ElfuScn *mstarget, ElfuScn *msrt); diff --git a/src/libelfu/modelops/dynlookup.c b/src/libelfu/modelops/dynlookup.c index a2cd3ae..e20adfe 100644 --- a/src/libelfu/modelops/dynlookup.c +++ b/src/libelfu/modelops/dynlookup.c @@ -91,3 +91,60 @@ int elfu_mDynLookupPltAddrByName(ElfuElf *me, char *name, GElf_Addr *result) return -1; } + + + +/* Hazard a guess where a global variable may be found in .bss, + * based on dynamic linking information in .rel.dyn */ +int elfu_mDynLookupReldynAddrByName(ElfuElf *me, char *name, GElf_Addr *result) +{ + ElfuScn *reldyn; + ElfuRel *rel; + GElf_Word j; + + reldyn = elfu_mScnForall(me, subFindByName, ".rel.dyn", NULL); + if (!reldyn) { + /* x86-64 uses .rela.dyn instead */ + reldyn = elfu_mScnForall(me, subFindByName, ".rela.dyn", NULL); + } + if (!reldyn) { + ELFU_WARN("elfu_mDynLookupReldynAddrByName: Could not find .rel.dyn section in destination ELF.\n"); + return -1; + } + + + assert(reldyn->linkptr); + j = 0; + CIRCLEQ_FOREACH(rel, &reldyn->reltab.rels, elem) { + ElfuSym *sym; + char *symname; + + j++; + + /* We only consider COPY relocations for global variables here. + * Technically, these relocations write the variables' contents + * to .bss. */ + if ((me->elfclass == ELFCLASS32 && rel->type != R_386_COPY) + || (me->elfclass == ELFCLASS64 && rel->type != R_X86_64_COPY)) { + continue; + } + + /* Get the (rel->sym)-th symbol from the symbol table that + * .rel.dyn points to. */ + sym = elfu_mSymtabIndexToSym(reldyn->linkptr, rel->sym); + assert(sym); + + symname = elfu_mSymtabSymToName(reldyn->linkptr, sym); + if (!strcmp(symname, name)) { + GElf_Addr addr = rel->offset; + ELFU_DEBUG("elfu_mDynLookupReldynAddrByName: Guessing symbol '%s' is in destination memory at %x (PLT entry #%u).\n", name, (unsigned)addr, j); + *result = addr; + return 0; + } + } + + ELFU_WARN("elfu_mDynLookupReldynAddrByName: Could not find or use symbol '%s' in destination ELF.\n", name); + ELFU_WARN(" NOTE: Only R_*_COPY relocations are resolved to global variables.\n"); + + return -1; +} diff --git a/src/libelfu/modelops/relocate.c b/src/libelfu/modelops/relocate.c index 7f78524..94598e6 100644 --- a/src/libelfu/modelops/relocate.c +++ b/src/libelfu/modelops/relocate.c @@ -36,8 +36,11 @@ int elfu_mRelocate(ElfuElf *metarget, ElfuScn *mstarget, ElfuScn *msrt) haveSymval = !elfu_mDynLookupPltAddrByName(metarget, elfu_mSymtabSymToName(msrt->linkptr, sym), &s); - } else if (sym->shndx == SHN_COMMON) { - // TODO: Lookup in .rel.dyn + if (!haveSymval) { + haveSymval = !elfu_mDynLookupReldynAddrByName(metarget, + elfu_mSymtabSymToName(msrt->linkptr, sym), + &s); + } } } -- 2.30.2