summaryrefslogtreecommitdiff
path: root/src/modelops/relocate.c
diff options
context:
space:
mode:
authornorly <ny-git@enpas.org>2013-06-15 16:27:28 +0100
committernorly <ny-git@enpas.org>2013-06-15 16:32:15 +0100
commit5868bb32246367139f0d17a989650964f90a7958 (patch)
tree7601bc12cfe88cb3c180c42fe1e3d1ee293c3559 /src/modelops/relocate.c
parent3c14755015340e48ae68aa874f672e7c9d289832 (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.c32
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;
}
}