1 /* This file is part of centaur.
3 * centaur is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License 2 as
5 * published by the Free Software Foundation.
7 * centaur is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with centaur. If not, see <http://www.gnu.org/licenses/>.
19 #include <libelfu/libelfu.h>
22 static void* subFindByName(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
24 char *name = (char*)aux1;
27 if (elfu_mScnName(me, ms)) {
28 if (!strcmp(elfu_mScnName(me, ms), name)) {
38 /* Hazard a guess where a function may be found in the PLT */
39 int elfu_mDynLookupPltAddrByName(ElfuElf *me, char *name, GElf_Addr *result)
46 relplt = elfu_mScnForall(me, subFindByName, ".rel.plt", NULL);
48 /* x86-64 uses .rela.plt instead */
49 relplt = elfu_mScnForall(me, subFindByName, ".rela.plt", NULL);
52 ELFU_WARN("elfu_mDynLookupPltAddr: Could not find .rel.plt section in destination ELF.\n");
56 plt = elfu_mScnForall(me, subFindByName, ".plt", NULL);
58 ELFU_WARN("elfu_mDynLookupPltAddr: Could not find .plt section in destination ELF.\n");
63 /* Look up name. If the j-th entry in .rel.plt has the name we are
64 * looking for, we assume that the (j+1)-th entry in .plt is machine
65 * code to jump to the function.
66 * Your mileage may vary, but it works on my GNU binaries. */
67 assert(relplt->linkptr);
69 CIRCLEQ_FOREACH(rel, &relplt->reltab.rels, elem) {
76 /* We only consider runtime relocations for functions.
77 * Technically, these relocations write the functions' addresses
78 * to the GOT, not the PLT, after the dynamic linker has found
80 if ((me->elfclass == ELFCLASS32 && rel->type != R_386_JMP_SLOT)
81 || (me->elfclass == ELFCLASS64 && rel->type != R_X86_64_JUMP_SLOT)) {
85 /* Get the (rel->sym)-th symbol from the symbol table that
86 * .rel.plt points to. */
87 sym = CIRCLEQ_FIRST(&relplt->linkptr->symtab.syms);
88 for (i = 1; i < rel->sym; i++) {
89 sym = CIRCLEQ_NEXT(sym, elem);
92 symname = ELFU_SYMSTR(relplt->linkptr, sym->name);
93 if (!strcmp(symname, name)) {
94 /* If this is the symbol we are looking for, then in an x86 binary
95 * the jump to the dynamic symbol is probably at offset (j * 16)
96 * from the start of the PLT, where j is the PLT entry and 16 is
97 * the number of bytes the machine code in a PLT entry take. */
98 GElf_Addr addr = plt->shdr.sh_addr + (16 * j);
99 ELFU_DEBUG("elfu_mDynLookupPltAddr: Guessing symbol '%s' is in destination memory at %x (PLT entry #%u).\n", name, (unsigned)addr, j);
105 ELFU_WARN("elfu_mDynLookupPltAddr: Could not find symbol '%s' in destination ELF.\n", name);
112 /* Hazard a guess where a global variable may be found in .bss,
113 * based on dynamic linking information in .rel.dyn */
114 int elfu_mDynLookupReldynAddrByName(ElfuElf *me, char *name, GElf_Addr *result)
120 reldyn = elfu_mScnForall(me, subFindByName, ".rel.dyn", NULL);
122 /* x86-64 uses .rela.dyn instead */
123 reldyn = elfu_mScnForall(me, subFindByName, ".rela.dyn", NULL);
126 ELFU_WARN("elfu_mDynLookupReldynAddrByName: Could not find .rel.dyn section in destination ELF.\n");
131 assert(reldyn->linkptr);
133 CIRCLEQ_FOREACH(rel, &reldyn->reltab.rels, elem) {
139 /* We only consider COPY relocations for global variables here.
140 * Technically, these relocations write the variables' contents
142 if ((me->elfclass == ELFCLASS32 && rel->type != R_386_COPY)
143 || (me->elfclass == ELFCLASS64 && rel->type != R_X86_64_COPY)) {
147 /* Get the (rel->sym)-th symbol from the symbol table that
148 * .rel.dyn points to. */
149 sym = elfu_mSymtabIndexToSym(reldyn->linkptr, rel->sym);
152 symname = elfu_mSymtabSymToName(reldyn->linkptr, sym);
153 if (!strcmp(symname, name)) {
154 GElf_Addr addr = rel->offset;
155 ELFU_DEBUG("elfu_mDynLookupReldynAddrByName: Guessing symbol '%s' is in destination memory at %x (PLT entry #%u).\n", name, (unsigned)addr, j);
161 ELFU_WARN("elfu_mDynLookupReldynAddrByName: Could not find or use symbol '%s' in destination ELF.\n", name);
162 ELFU_WARN(" NOTE: Only R_*_COPY relocations are resolved to global variables.\n");