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");
44 assert(relplt->reltab);
45 assert(relplt->linkptr);
46 assert(relplt->linkptr->symtab);
48 CIRCLEQ_FOREACH(rel, &relplt->reltab->rels, elem) {
54 if (rel->type != R_386_JMP_SLOT) {
58 sym = CIRCLEQ_FIRST(&relplt->linkptr->symtab->syms);
59 for (i = 1; i < rel->sym; i++) {
60 sym = CIRCLEQ_NEXT(sym, elem);
67 if (!strcmp(sym->name, name)) {
68 /* If this is the symbol we are looking for, then in an x86 binary
69 * the jump to the dynamic symbol is probably at offset (j * 16)
70 * from the start of the PLT, where j is the PLT entry and 16 is
71 * the number of bytes the machine code in a PLT entry take. */
72 GElf_Addr addr = plt->shdr.sh_addr + (16 * j);
73 ELFU_DEBUG("dynsymLookupVal: Guessing symbol '%s' is in destination memory at %jx (PLT entry #%d).\n", name, addr, j);
78 ELFU_WARN("dynsymLookupVal: Could not find symbol '%s' in destination ELF.\n", name);
84 static GElf_Word symtabLookupVal(ElfuElf *metarget, ElfuScn *msst, GElf_Word entry)
93 assert(!CIRCLEQ_EMPTY(&msst->symtab->syms));
95 sym = CIRCLEQ_FIRST(&msst->symtab->syms);
96 for (i = 1; i < entry; i++) {
97 sym = CIRCLEQ_NEXT(sym, elem);
105 assert(elfu_mScnByOldscn(metarget, sym->scnptr));
106 return elfu_mScnByOldscn(metarget, sym->scnptr)->shdr.sh_addr + sym->value;
107 } else if (sym->shndx == SHN_UNDEF) {
108 /* Look the symbol up in .dyn.plt. If it cannot be found there then
109 * .rel.dyn may need to be expanded with a COPY relocation so the
110 * dynamic linker fixes up the (TODO). */
111 return pltLookupVal(metarget, sym->name);
112 } else if (sym->shndx == SHN_ABS) {
115 ELFU_WARN("symtabLookupVal: Symbol binding COMMON is not supported, using 0.\n");
121 assert(elfu_mScnByOldscn(metarget, sym->scnptr));
122 return elfu_mScnByOldscn(metarget, sym->scnptr)->shdr.sh_addr;
124 ELFU_WARN("symtabLookupVal: Symbol type FILE is not supported, using 0.\n");
127 ELFU_WARN("symtabLookupVal: Unknown symbol type %d for %s.\n", sym->type, sym->name);
132 void elfu_mRelocate32(ElfuElf *metarget, ElfuScn *mstarget, ElfuScn *msrt)
139 ELFU_DEBUG("Relocating in section of type %d size %jx\n",
140 mstarget->shdr.sh_type,
141 mstarget->shdr.sh_size);
143 CIRCLEQ_FOREACH(rel, &msrt->reltab->rels, elem) {
144 Elf32_Word *dest = (Elf32_Word*)(((char*)(mstarget->data.d_buf)) + rel->offset);
145 Elf32_Word a = rel->addendUsed ? rel->addend : *dest;
146 Elf32_Addr p = mstarget->shdr.sh_addr + rel->offset;
147 Elf32_Addr s = symtabLookupVal(metarget, msrt->linkptr, rel->sym);
148 Elf32_Word newval = *dest;
152 ELFU_DEBUG("Skipping relocation: R_386_NONE");
155 ELFU_DEBUG("Relocation: R_386_32");
159 ELFU_DEBUG("Relocation: R_386_PC32");
164 ELFU_DEBUG("Skipping relocation: Unknown type %d", rel->type);
166 ELFU_DEBUG(", overwriting %x with %x.\n", *dest, newval);