diff options
-rw-r--r-- | include/libelfu/modelops.h | 5 | ||||
-rw-r--r-- | include/libelfu/types.h | 1 | ||||
-rw-r--r-- | src/modelops/fromFile.c | 14 | ||||
-rw-r--r-- | src/modelops/reladd.c | 101 | ||||
-rw-r--r-- | src/modelops/relocate.c | 32 | ||||
-rw-r--r-- | src/modelops/toFile.c | 2 |
6 files changed, 126 insertions, 29 deletions
diff --git a/include/libelfu/modelops.h b/include/libelfu/modelops.h index 3daef52..eee7c13 100644 --- a/include/libelfu/modelops.h +++ b/include/libelfu/modelops.h @@ -7,6 +7,9 @@ #include <libelfu/types.h> +#define ELFU_SYMSTR(symtabscn, off) (((char*)(symtabscn)->linkptr->data.d_buf) + (off)) + + size_t elfu_mPhdrCount(ElfuElf *me); void elfu_mPhdrUpdateChildOffsets(ElfuPhdr *mp); @@ -42,6 +45,6 @@ void elfu_mDumpElf(ElfuElf *me); ElfuElf* elfu_mFromElf(Elf *e); void elfu_mToElf(ElfuElf *me, Elf *e); -void elfu_mReladd(ElfuElf *me, ElfuElf *mrel); +void elfu_mReladd(ElfuElf *me, const ElfuElf *mrel); #endif diff --git a/include/libelfu/types.h b/include/libelfu/types.h index 37e25fa..e4dd26c 100644 --- a/include/libelfu/types.h +++ b/include/libelfu/types.h @@ -9,7 +9,6 @@ typedef struct ElfuSym { GElf_Word name; - char *nameptr; GElf_Addr value; GElf_Word size; diff --git a/src/modelops/fromFile.c b/src/modelops/fromFile.c index c46dd6c..28ecb85 100644 --- a/src/modelops/fromFile.c +++ b/src/modelops/fromFile.c @@ -5,17 +5,6 @@ #include <libelfu/libelfu.h> -static char* symstr(ElfuScn *symtab, size_t off) -{ - assert(symtab); - assert(symtab->linkptr); - assert(symtab->linkptr->data.d_buf); - assert(off < symtab->linkptr->data.d_size); - - return &(((char*)symtab->linkptr->data.d_buf)[off]); -} - - static void parseSymtab32(ElfuScn *ms, ElfuScn**origScnArr) { size_t i; @@ -31,19 +20,18 @@ static void parseSymtab32(ElfuScn *ms, ElfuScn**origScnArr) assert(sym); sym->name = cursym->st_name; - sym->nameptr = symstr(ms, cursym->st_name); sym->value = cursym->st_value; sym->size = cursym->st_size; sym->bind = ELF32_ST_BIND(cursym->st_info); sym->type = ELF32_ST_TYPE(cursym->st_info); sym->other = cursym->st_other; + sym->shndx = cursym->st_shndx; switch (cursym->st_shndx) { case SHN_UNDEF: case SHN_ABS: case SHN_COMMON: sym->scnptr = NULL; - sym->shndx = cursym->st_shndx; break; default: sym->scnptr = origScnArr[cursym->st_shndx - 1]; diff --git a/src/modelops/reladd.c b/src/modelops/reladd.c index 2fdfb48..936c0bd 100644 --- a/src/modelops/reladd.c +++ b/src/modelops/reladd.c @@ -213,16 +213,111 @@ static void* subScnAdd2(ElfuElf *mrel, ElfuScn *ms, void *aux1, void *aux2) } -void elfu_mReladd(ElfuElf *me, ElfuElf *mrel) + +static void insertSymClone(ElfuElf *me, const ElfuScn *oldmsst, const ElfuSym *oldsym) +{ + GElf_Xword newsize; + void *newbuf; + ElfuScn *newscn = NULL; + ElfuSym *newsym; + char *oldsymname; + + assert(me); + assert(oldmsst); + assert(oldsym); + + /* If the old symbol pointed to a section, find its clone in the target */ + if (oldsym->scnptr) { + newscn = elfu_mScnByOldscn(me, oldsym->scnptr); + + /* If we didn't copy the section referenced, we won't + * copy this symbol either */ + if (!newscn) { + return; + } + } + + // TODO: Allocate symtab if none present + assert(me->symtab); + + /* Allocate memory for the cloned symbol */ + newsym = malloc(sizeof(*newsym)); + if (!newsym) { + ELFU_WARN("insertSymClone: malloc() failed for newsym.\n"); + goto ERROR; + } + + oldsymname = ELFU_SYMSTR(oldmsst, oldsym->name); + + /* Expand .strtab, append symbol name, link newsym to it */ + newsize = me->symtab->linkptr->shdr.sh_size + strlen(oldsymname) + 1; + newbuf = realloc(me->symtab->linkptr->data.d_buf, newsize); + if (!newbuf) { + ELFU_WARN("insertSymClone: realloc() failed for strtab.\n"); + goto ERROR; + } + + me->symtab->linkptr->data.d_buf = newbuf; + + newsym->name = me->symtab->linkptr->shdr.sh_size; + + strcpy(newbuf + newsym->name, oldsymname); + + me->symtab->linkptr->data.d_size = newsize; + me->symtab->linkptr->shdr.sh_size = newsize; + + + /* Copy all other fields */ + newsym->scnptr = newscn; + newsym->shndx = oldsym->shndx; /* If scnptr == NULL, this becomes relevant */ + newsym->bind = oldsym->bind; + newsym->other = oldsym->other; + newsym->size = oldsym->size; + newsym->type = oldsym->type; + newsym->value = oldsym->value; + + /* In executables, symbol addresses need to be in memory */ + if (newscn) { + newsym->value += newscn->shdr.sh_addr; + } + + /* Insert symbol */ + CIRCLEQ_INSERT_TAIL(&me->symtab->symtab.syms, newsym, elem); + + return; + + ERROR: + if (newsym) { + free(newsym); + } +} + +static void mergeSymtab(ElfuElf *me, const ElfuElf *mrel) +{ + ElfuSym *sym; + + assert(me); + assert(mrel); + + CIRCLEQ_FOREACH(sym, &mrel->symtab->symtab.syms, elem) { + insertSymClone(me, mrel->symtab, sym); + } +} + + + +void elfu_mReladd(ElfuElf *me, const ElfuElf *mrel) { assert(me); assert(mrel); /* For each section in object file, guess how to insert it */ - elfu_mScnForall(mrel, subScnAdd1, me, NULL); + elfu_mScnForall((ElfuElf*)mrel, subScnAdd1, me, NULL); + + mergeSymtab(me, mrel); /* Do relocations and other stuff */ - elfu_mScnForall(mrel, subScnAdd2, me, NULL); + elfu_mScnForall((ElfuElf*)mrel, subScnAdd2, me, NULL); /* Re-layout to accommodate new contents */ elfu_mLayoutAuto(me); diff --git a/src/modelops/relocate.c b/src/modelops/relocate.c index 0bd8ee8..ea84937 100644 --- a/src/modelops/relocate.c +++ b/src/modelops/relocate.c @@ -40,29 +40,36 @@ static GElf_Word pltLookupVal(ElfuElf *metarget, char *name) } - /* 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++; + /* 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 (rel->type != R_386_JMP_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->nameptr) { - continue; - } - - if (!strcmp(sym->nameptr, 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 @@ -83,6 +90,7 @@ static GElf_Word symtabLookupVal(ElfuElf *metarget, ElfuScn *msst, GElf_Word ent { GElf_Word i; ElfuSym *sym; + char *symname; assert(metarget); assert(msst); @@ -93,19 +101,21 @@ static GElf_Word symtabLookupVal(ElfuElf *metarget, ElfuScn *msst, GElf_Word ent 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->nameptr); + return pltLookupVal(metarget, symname); } else if (sym->shndx == SHN_ABS) { return sym->value; } else { @@ -121,7 +131,7 @@ static GElf_Word symtabLookupVal(ElfuElf *metarget, ElfuScn *msst, GElf_Word ent 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->nameptr); + ELFU_WARN("symtabLookupVal: Unknown symbol type %d for %s.\n", sym->type, symname); return 0; } } diff --git a/src/modelops/toFile.c b/src/modelops/toFile.c index 66109df..434130e 100644 --- a/src/modelops/toFile.c +++ b/src/modelops/toFile.c @@ -11,6 +11,7 @@ static void flattenSymtab(ElfuElf *me) elfu_mLayoutAuto(me); + /* Update section indexes and count symbols */ CIRCLEQ_FOREACH(sym, &me->symtab->symtab.syms, elem) { if (sym->scnptr) { sym->shndx = elfu_mScnIndex(me, sym->scnptr); @@ -19,6 +20,7 @@ static void flattenSymtab(ElfuElf *me) numsyms++; } + /* Copy symbols to elfclass-specific format */ if (me->elfclass == ELFCLASS32) { size_t newsize = (numsyms + 1) * sizeof(Elf32_Sym); size_t i; |