X-Git-Url: https://git.enpas.org/?a=blobdiff_plain;f=src%2Flibelfu%2Fmodelops%2Frelocate.c;h=7f78524acf962b9af6ce1736376fde770bdbe7dd;hb=95516f950cf67ee154f362425c1472637d9f3e22;hp=2eada0424e8a27e000df13950770a93619d9f234;hpb=9ebc757b5592844e47bcddfba7335d2e7c590a8b;p=centaur.git 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; + }