diff options
author | norly <ny-git@enpas.org> | 2013-06-15 16:27:28 +0100 |
---|---|---|
committer | norly <ny-git@enpas.org> | 2013-06-15 16:32:15 +0100 |
commit | 5868bb32246367139f0d17a989650964f90a7958 (patch) | |
tree | 7601bc12cfe88cb3c180c42fe1e3d1ee293c3559 /src/modelops/relocate.c | |
parent | 3c14755015340e48ae68aa874f672e7c9d289832 (diff) |
Merge symbol tables. (Not fully ELF conformant)
Also, remove that nameptr member from symbols. It just *had* to cause
trouble.
Symbols are simply appended to the target's symbol table, which means
that LOCAL symbols are not inserted at the beginning and we are thus
ignoring an ELF spec. Might change that in the future, it's good enough
for now and it's sure not to break anything with the old symbols.
The code currently assumes that the target *has* a symbol table. We'll
have to fix that, and also remove undefined and duplicate symbols.
Diffstat (limited to 'src/modelops/relocate.c')
-rw-r--r-- | src/modelops/relocate.c | 32 |
1 files changed, 21 insertions, 11 deletions
diff --git a/src/modelops/relocate.c b/src/modelops/relocate.c index 0bd8ee8..ea84937 100644 --- a/src/modelops/relocate.c +++ b/src/modelops/relocate.c @@ -40,29 +40,36 @@ static GElf_Word pltLookupVal(ElfuElf *metarget, char *name) } - /* Look up name */ + /* 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 (rel->type != R_386_JMP_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); } - if (!sym->nameptr) { - continue; - } - - if (!strcmp(sym->nameptr, name)) { + 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 @@ -83,6 +90,7 @@ static GElf_Word symtabLookupVal(ElfuElf *metarget, ElfuScn *msst, GElf_Word ent { GElf_Word i; ElfuSym *sym; + char *symname; assert(metarget); assert(msst); @@ -93,19 +101,21 @@ static GElf_Word symtabLookupVal(ElfuElf *metarget, ElfuScn *msst, GElf_Word ent 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) { - assert(elfu_mScnByOldscn(metarget, sym->scnptr)); - return elfu_mScnByOldscn(metarget, sym->scnptr)->shdr.sh_addr + sym->value; + 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 .dyn.plt. If it cannot be found there then + /* 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, sym->nameptr); + return pltLookupVal(metarget, symname); } else if (sym->shndx == SHN_ABS) { return sym->value; } else { @@ -121,7 +131,7 @@ static GElf_Word symtabLookupVal(ElfuElf *metarget, ElfuScn *msst, GElf_Word ent 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, sym->nameptr); + ELFU_WARN("symtabLookupVal: Unknown symbol type %d for %s.\n", sym->type, symname); return 0; } } |