4 #include <libelfu/libelfu.h>
7 static void* subFindByName(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
9 char *name = (char*)aux1;
12 if (elfu_mScnName(me, ms)) {
13 if (!strcmp(elfu_mScnName(me, ms), name)) {
22 /* Hazard a guess where a function may be found in the PLT */
23 static GElf_Word pltLookupVal(ElfuElf *metarget, char *name)
30 relplt = elfu_mScnForall(metarget, subFindByName, ".rel.plt", NULL);
32 ELFU_WARN("dynsymLookupVal: Could not find .rel.plt section in destination ELF.\n");
36 plt = elfu_mScnForall(metarget, subFindByName, ".plt", NULL);
38 ELFU_WARN("dynsymLookupVal: Could not find .plt section in destination ELF.\n");
43 /* Look up name. If the j-th entry in .rel.plt has the name we are
44 * looking for, we assume that the (j+1)-th entry in .plt is machine
45 * code to jump to the function.
46 * Your mileage may vary, but it works on my GNU binaries. */
47 assert(relplt->linkptr);
49 CIRCLEQ_FOREACH(rel, &relplt->reltab.rels, elem) {
56 /* We only consider runtime relocations for functions.
57 * Technically, these relocations write the functions' addresses
58 * to the GOT, not the PLT, after the dynamic linker has found
60 if ((metarget->elfclass == ELFCLASS32 && rel->type != R_386_JMP_SLOT)
61 || (metarget->elfclass == ELFCLASS64 && rel->type != R_X86_64_JUMP_SLOT)) {
65 /* Get the (rel->sym)-th symbol from the symbol table that
66 * .rel.plt points to. */
67 sym = CIRCLEQ_FIRST(&relplt->linkptr->symtab.syms);
68 for (i = 1; i < rel->sym; i++) {
69 sym = CIRCLEQ_NEXT(sym, elem);
72 symname = ELFU_SYMSTR(relplt->linkptr, sym->name);
73 if (!strcmp(symname, name)) {
74 /* If this is the symbol we are looking for, then in an x86 binary
75 * the jump to the dynamic symbol is probably at offset (j * 16)
76 * from the start of the PLT, where j is the PLT entry and 16 is
77 * the number of bytes the machine code in a PLT entry take. */
78 GElf_Addr addr = plt->shdr.sh_addr + (16 * j);
79 ELFU_DEBUG("dynsymLookupVal: Guessing symbol '%s' is in destination memory at %jx (PLT entry #%d).\n", name, addr, j);
84 ELFU_WARN("dynsymLookupVal: Could not find symbol '%s' in destination ELF.\n", name);
90 static GElf_Word symtabLookupVal(ElfuElf *metarget, ElfuScn *msst, GElf_Word entry)
99 assert(!CIRCLEQ_EMPTY(&msst->symtab.syms));
101 sym = CIRCLEQ_FIRST(&msst->symtab.syms);
102 for (i = 1; i < entry; i++) {
103 sym = CIRCLEQ_NEXT(sym, elem);
105 symname = ELFU_SYMSTR(msst, sym->name);
112 ElfuScn *newscn = elfu_mScnByOldscn(metarget, sym->scnptr);
114 return newscn->shdr.sh_addr + sym->value;
115 } else if (sym->shndx == SHN_UNDEF) {
116 /* Look the symbol up in .rel.plt. If it cannot be found there then
117 * .rel.dyn may need to be expanded with a COPY relocation so the
118 * dynamic linker fixes up the (TODO). */
119 return pltLookupVal(metarget, symname);
120 } else if (sym->shndx == SHN_ABS) {
123 ELFU_WARN("symtabLookupVal: Symbol binding COMMON is not supported, using 0.\n");
129 assert(elfu_mScnByOldscn(metarget, sym->scnptr));
130 return elfu_mScnByOldscn(metarget, sym->scnptr)->shdr.sh_addr;
132 ELFU_WARN("symtabLookupVal: Symbol type FILE is not supported, using 0.\n");
135 ELFU_WARN("symtabLookupVal: Unknown symbol type %d for %s.\n", sym->type, symname);
140 void elfu_mRelocate(ElfuElf *metarget, ElfuScn *mstarget, ElfuScn *msrt)
147 ELFU_DEBUG("Relocating in section of type %d size %jx\n",
148 mstarget->shdr.sh_type,
149 mstarget->shdr.sh_size);
151 CIRCLEQ_FOREACH(rel, &msrt->reltab.rels, elem) {
152 Elf32_Word *dest32 = (Elf32_Word*)(((char*)(mstarget->data.d_buf)) + rel->offset);
153 Elf64_Word *dest64 = (Elf64_Word*)(((char*)(mstarget->data.d_buf)) + rel->offset);
156 if (metarget->elfclass == ELFCLASS32) {
157 Elf32_Word a32 = rel->addendUsed ? rel->addend : *dest32;
158 Elf32_Addr p32 = mstarget->shdr.sh_addr + rel->offset;
159 Elf32_Addr s32 = symtabLookupVal(metarget, msrt->linkptr, rel->sym);
162 ELFU_DEBUG("Skipping relocation: R_386_NONE\n");
168 *dest32 = s32 + a32 - p32;
172 ELFU_DEBUG("Skipping relocation: Unknown type %d\n", rel->type);
174 } else if (metarget->elfclass == ELFCLASS64) {
175 /* x86-64 only uses RELA with explicit addend. */
176 assert(rel->addendUsed);
177 Elf64_Word a64 = rel->addend;
178 Elf64_Addr p64 = mstarget->shdr.sh_addr + rel->offset;
179 Elf64_Addr s64 = symtabLookupVal(metarget, msrt->linkptr, rel->sym);
183 ELFU_DEBUG("Skipping relocation: R_386_NONE\n");
189 *dest32 = s64 + a64 - p64;
196 ELFU_DEBUG("Skipping relocation: Unknown type %d", rel->type);