summaryrefslogtreecommitdiff
path: root/src/libelfu/modelops/relocate.c
diff options
context:
space:
mode:
authornorly <ny-git@enpas.org>2013-06-26 19:57:39 +0100
committernorly <ny-git@enpas.org>2013-06-26 21:33:14 +0100
commit95516f950cf67ee154f362425c1472637d9f3e22 (patch)
treea60fbab2d4f19ac4178f00b4f23926cc6afe5d75 /src/libelfu/modelops/relocate.c
parent9ebc757b5592844e47bcddfba7335d2e7c590a8b (diff)
Separate PLT lookup
Diffstat (limited to 'src/libelfu/modelops/relocate.c')
-rw-r--r--src/libelfu/modelops/relocate.c114
1 files changed, 82 insertions, 32 deletions
diff --git a/src/libelfu/modelops/relocate.c b/src/libelfu/modelops/relocate.c
index 2eada04..7f78524 100644
--- a/src/libelfu/modelops/relocate.c
+++ b/src/libelfu/modelops/relocate.c
@@ -6,9 +6,10 @@
/* 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)
+int elfu_mRelocate(ElfuElf *metarget, ElfuScn *mstarget, ElfuScn *msrt)
{
ElfuRel *rel;
+ ElfuSym *sym;
assert(mstarget);
assert(msrt);
@@ -20,51 +21,100 @@ void elfu_mRelocate(ElfuElf *metarget, ElfuScn *mstarget, ElfuScn *msrt)
CIRCLEQ_FOREACH(rel, &msrt->reltab.rels, elem) {
Elf32_Word *dest32 = (Elf32_Word*)(mstarget->databuf + rel->offset);
Elf64_Word *dest64 = (Elf64_Word*)(mstarget->databuf + rel->offset);
+ GElf_Addr s;
+ int haveSymval = 0;
+ sym = elfu_mSymtabIndexToSym(msrt->linkptr, rel->sym);
+ assert(sym);
+
+ haveSymval = !elfu_mSymtabLookupSymToAddr(metarget,
+ msrt->linkptr,
+ sym,
+ &s);
+ if (!haveSymval) {
+ if (sym->shndx == SHN_UNDEF) {
+ haveSymval = !elfu_mDynLookupPltAddrByName(metarget,
+ elfu_mSymtabSymToName(msrt->linkptr, sym),
+ &s);
+ } else if (sym->shndx == SHN_COMMON) {
+ // TODO: Lookup in .rel.dyn
+ }
+ }
if (metarget->elfclass == ELFCLASS32) {
Elf32_Word a32 = rel->addendUsed ? rel->addend : *dest32;
Elf32_Addr p32 = mstarget->shdr.sh_addr + rel->offset;
- 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");
- break;
- case R_386_32:
- *dest32 = s32 + a32;
- break;
- case R_386_PC32:
- *dest32 = s32 + a32 - p32;
- break;
+ Elf32_Addr s32 = (Elf32_Addr)s;
+ switch(metarget->ehdr.e_machine) {
+ case EM_386:
+ switch(rel->type) {
+ case R_386_NONE:
+ ELFU_DEBUG("Skipping relocation: R_386_NONE\n");
+ break;
+ case R_386_32:
+ if (!haveSymval) {
+ goto MISSINGSYM;
+ }
+ *dest32 = s32 + a32;
+ break;
+ case R_386_PC32:
+ if (!haveSymval) {
+ goto MISSINGSYM;
+ }
+ *dest32 = s32 + a32 - p32;
+ break;
+ default:
+ ELFU_DEBUG("elfu_mRelocate: Skipping unknown relocation type %d\n", rel->type);
+ }
+ break;
default:
- ELFU_DEBUG("Skipping relocation: Unknown type %d\n", rel->type);
+ ELFU_WARN("elfu_mRelocate: Unknown machine type. Aborting.\n");
}
} else if (metarget->elfclass == ELFCLASS64) {
- Elf64_Word a64 = rel->addend;
+ Elf64_Word a64 = rel->addendUsed ? rel->addend : *dest64;
Elf64_Addr p64 = mstarget->shdr.sh_addr + rel->offset;
- Elf64_Addr s64 = elfu_mSymtabLookupVal(metarget, msrt->linkptr, rel->sym);
-
- /* x86-64 only uses RELA with explicit addend. */
- assert(rel->addendUsed);
+ Elf64_Addr s64 = (Elf64_Addr)s;
- switch(rel->type) {
- case R_X86_64_NONE:
- ELFU_DEBUG("Skipping relocation: R_386_NONE\n");
+ switch(metarget->ehdr.e_machine) {
+ case EM_X86_64:
+ switch(rel->type) {
+ case R_X86_64_NONE:
+ ELFU_DEBUG("Skipping relocation: R_386_NONE\n");
+ break;
+ case R_X86_64_64:
+ if (!haveSymval) {
+ goto MISSINGSYM;
+ }
+ *dest64 = s64 + a64;
+ break;
+ case R_X86_64_PC32:
+ if (!haveSymval) {
+ goto MISSINGSYM;
+ }
+ *dest32 = s64 + a64 - p64;
+ break;
+ case R_X86_64_32:
+ if (!haveSymval) {
+ goto MISSINGSYM;
+ }
+ *dest32 = s64 + a64;
+ break;
+ default:
+ ELFU_DEBUG("elfu_mRelocate: Skipping unknown relocation type %d", rel->type);
+ }
break;
- case R_X86_64_64:
- *dest64 = s64 + a64;
- break;
- case R_X86_64_PC32:
- *dest32 = s64 + a64 - p64;
- break;
- case R_X86_64_32:
- *dest32 = s64 + a64;
- break;
-
default:
- ELFU_DEBUG("Skipping relocation: Unknown type %d", rel->type);
+ ELFU_WARN("elfu_mRelocate: Unknown machine type. Aborting.\n");
}
}
}
+
+ return 0;
+
+ MISSINGSYM:
+ ELFU_WARN("elfu_mRelocate: Could not resolve symbol %s. Aborting.\n",
+ elfu_mSymtabSymToName(msrt->linkptr, sym));
+ return -1;
+
}