}
- /* 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++;
- if (rel->type != R_386_JMP_SLOT) {
+ /* 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 ((metarget->elfclass == ELFCLASS32 && rel->type != R_386_JMP_SLOT)
+ || (metarget->elfclass == ELFCLASS64 && rel->type != R_X86_64_JUMP_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->name) {
- continue;
- }
-
- if (!strcmp(sym->name, 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
{
GElf_Word i;
ElfuSym *sym;
+ char *symname;
assert(metarget);
assert(msst);
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->name);
+ return pltLookupVal(metarget, symname);
} else if (sym->shndx == SHN_ABS) {
return sym->value;
} else {
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->name);
+ ELFU_WARN("symtabLookupVal: Unknown symbol type %d for %s.\n", sym->type, symname);
return 0;
}
}
mstarget->shdr.sh_size);
CIRCLEQ_FOREACH(rel, &msrt->reltab.rels, elem) {
- Elf32_Word *dest = (Elf32_Word*)(((char*)(mstarget->data.d_buf)) + rel->offset);
- Elf32_Word a = rel->addendUsed ? rel->addend : *dest;
- Elf32_Addr p = mstarget->shdr.sh_addr + rel->offset;
- Elf32_Addr s = symtabLookupVal(metarget, msrt->linkptr, rel->sym);
- Elf32_Word newval = *dest;
-
- switch(rel->type) {
- case R_386_NONE:
- ELFU_DEBUG("Skipping relocation: R_386_NONE");
- break;
- case R_386_32:
- ELFU_DEBUG("Relocation: R_386_32");
- newval = s + a;
- break;
- case R_386_PC32:
- ELFU_DEBUG("Relocation: R_386_PC32");
- newval = s + a - p;
- break;
-
- default:
- ELFU_DEBUG("Skipping relocation: Unknown type %d", rel->type);
+ Elf32_Word *dest32 = (Elf32_Word*)(((char*)(mstarget->data.d_buf)) + rel->offset);
+ Elf64_Word *dest64 = (Elf64_Word*)(((char*)(mstarget->data.d_buf)) + rel->offset);
+
+
+ if (metarget->elfclass == ELFCLASS32) {
+ Elf32_Word a32 = rel->addendUsed ? rel->addend : *dest32;
+ Elf32_Addr p32 = mstarget->shdr.sh_addr + rel->offset;
+ Elf32_Addr s32 = symtabLookupVal(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;
+
+ default:
+ ELFU_DEBUG("Skipping relocation: Unknown type %d\n", rel->type);
+ }
+ } else if (metarget->elfclass == ELFCLASS64) {
+ /* x86-64 only uses RELA with explicit addend. */
+ assert(rel->addendUsed);
+ Elf64_Word a64 = rel->addend;
+ Elf64_Addr p64 = mstarget->shdr.sh_addr + rel->offset;
+ Elf64_Addr s64 = symtabLookupVal(metarget, msrt->linkptr, rel->sym);
+
+ switch(rel->type) {
+ case R_X86_64_NONE:
+ ELFU_DEBUG("Skipping relocation: R_386_NONE\n");
+ 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_DEBUG(", overwriting %x with %x.\n", *dest, newval);
- *dest = newval;
+
+
}
}