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 *me, char *name)
30 relplt = elfu_mScnForall(me, subFindByName, ".rel.plt", NULL);
32 /* x86-64 uses .rela.plt instead */
33 relplt = elfu_mScnForall(me, subFindByName, ".rela.plt", NULL);
36 ELFU_WARN("dynsymLookupVal: Could not find .rel.plt section in destination ELF.\n");
40 plt = elfu_mScnForall(me, subFindByName, ".plt", NULL);
42 ELFU_WARN("dynsymLookupVal: Could not find .plt section in destination ELF.\n");
47 /* Look up name. If the j-th entry in .rel.plt has the name we are
48 * looking for, we assume that the (j+1)-th entry in .plt is machine
49 * code to jump to the function.
50 * Your mileage may vary, but it works on my GNU binaries. */
51 assert(relplt->linkptr);
53 CIRCLEQ_FOREACH(rel, &relplt->reltab.rels, elem) {
60 /* We only consider runtime relocations for functions.
61 * Technically, these relocations write the functions' addresses
62 * to the GOT, not the PLT, after the dynamic linker has found
64 if ((me->elfclass == ELFCLASS32 && rel->type != R_386_JMP_SLOT)
65 || (me->elfclass == ELFCLASS64 && rel->type != R_X86_64_JUMP_SLOT)) {
69 /* Get the (rel->sym)-th symbol from the symbol table that
70 * .rel.plt points to. */
71 sym = CIRCLEQ_FIRST(&relplt->linkptr->symtab.syms);
72 for (i = 1; i < rel->sym; i++) {
73 sym = CIRCLEQ_NEXT(sym, elem);
76 symname = ELFU_SYMSTR(relplt->linkptr, sym->name);
77 if (!strcmp(symname, name)) {
78 /* If this is the symbol we are looking for, then in an x86 binary
79 * the jump to the dynamic symbol is probably at offset (j * 16)
80 * from the start of the PLT, where j is the PLT entry and 16 is
81 * the number of bytes the machine code in a PLT entry take. */
82 GElf_Addr addr = plt->shdr.sh_addr + (16 * j);
83 ELFU_DEBUG("dynsymLookupVal: Guessing symbol '%s' is in destination memory at %x (PLT entry #%u).\n", name, (unsigned)addr, j);
88 ELFU_WARN("dynsymLookupVal: Could not find symbol '%s' in destination ELF.\n", name);
95 /* Look up a value in the symbol table section *msst which is in *me.
96 * If it is not found there, see if we can find it in *me's PLT. */
97 GElf_Word elfu_mSymtabLookupVal(ElfuElf *me, ElfuScn *msst, GElf_Word entry)
106 assert(!CIRCLEQ_EMPTY(&msst->symtab.syms));
108 sym = CIRCLEQ_FIRST(&msst->symtab.syms);
109 for (i = 1; i < entry; i++) {
110 sym = CIRCLEQ_NEXT(sym, elem);
112 symname = ELFU_SYMSTR(msst, sym->name);
119 ElfuScn *newscn = elfu_mScnByOldscn(me, sym->scnptr);
121 return newscn->shdr.sh_addr + sym->value;
122 } else if (sym->shndx == SHN_UNDEF) {
123 /* Look the symbol up in .rel.plt. If it cannot be found there then
124 * .rel.dyn may need to be expanded with a COPY relocation so the
125 * dynamic linker fixes up the (TODO). */
126 return pltLookupVal(me, symname);
127 } else if (sym->shndx == SHN_ABS) {
130 ELFU_WARN("symtabLookupVal: Symbol binding COMMON is not supported, using 0.\n");
136 assert(elfu_mScnByOldscn(me, sym->scnptr));
137 return elfu_mScnByOldscn(me, sym->scnptr)->shdr.sh_addr;
139 ELFU_WARN("symtabLookupVal: Symbol type FILE is not supported, using 0.\n");
142 ELFU_WARN("symtabLookupVal: Unknown symbol type %d for %s.\n", sym->type, symname);
148 /* Look up a value in the symbol table section *msst which is in *me. */
149 GElf_Word elfu_mSymtabLookupAddrByName(ElfuElf *me, ElfuScn *msst, char *name)
156 assert(strlen(name) > 0);
157 assert(!CIRCLEQ_EMPTY(&msst->symtab.syms));
159 CIRCLEQ_FOREACH(sym, &msst->symtab.syms, elem) {
160 char *symname = ELFU_SYMSTR(msst, sym->name);
162 if (!strcmp(symname, name)) {
176 GElf_Addr a = sym->value;
177 a += me->ehdr.e_type == ET_REL ? sym->scnptr->shdr.sh_addr : 0;
179 } else if (sym->shndx == SHN_UNDEF) {
181 } else if (sym->shndx == SHN_ABS) {
184 ELFU_WARN("elfu_mSymtabLookupAddrByName: Symbol binding COMMON is not supported, using 0.\n");
195 /* Convert symtab from memory model to elfclass specific format */
196 void elfu_mSymtabFlatten(ElfuElf *me)
201 elfu_mLayoutAuto(me);
203 /* Update section indexes and count symbols */
204 CIRCLEQ_FOREACH(sym, &me->symtab->symtab.syms, elem) {
206 sym->shndx = elfu_mScnIndex(me, sym->scnptr);
212 /* Copy symbols to elfclass-specific format */
213 if (me->elfclass == ELFCLASS32) {
214 size_t newsize = (numsyms + 1) * sizeof(Elf32_Sym);
217 if (me->symtab->databuf) {
218 free(me->symtab->databuf);
220 me->symtab->databuf = malloc(newsize);
221 assert(me->symtab->databuf);
223 me->symtab->shdr.sh_size = newsize;
224 memset(me->symtab->databuf, 0, newsize);
227 CIRCLEQ_FOREACH(sym, &me->symtab->symtab.syms, elem) {
228 Elf32_Sym *es = ((Elf32_Sym*)me->symtab->databuf) + i;
230 es->st_name = sym->name;
231 es->st_value = sym->value;
232 es->st_size = sym->size;
233 es->st_info = ELF32_ST_INFO(sym->bind, sym->type);
234 es->st_other = sym->other;
235 es->st_shndx = sym->shndx;
239 } else if (me->elfclass == ELFCLASS64) {
240 size_t newsize = (numsyms + 1) * sizeof(Elf64_Sym);
243 if (me->symtab->databuf) {
244 free(me->symtab->databuf);
246 me->symtab->databuf = malloc(newsize);
247 assert(me->symtab->databuf);
249 me->symtab->shdr.sh_size = newsize;
250 memset(me->symtab->databuf, 0, newsize);
253 CIRCLEQ_FOREACH(sym, &me->symtab->symtab.syms, elem) {
254 Elf64_Sym *es = ((Elf64_Sym*)me->symtab->databuf) + i;
256 es->st_name = sym->name;
257 es->st_value = sym->value;
258 es->st_size = sym->size;
259 es->st_info = ELF64_ST_INFO(sym->bind, sym->type);
260 es->st_other = sym->other;
261 es->st_shndx = sym->shndx;
266 /* Unknown elfclass */
270 elfu_mLayoutAuto(me);