From: norly Date: Sat, 15 Jun 2013 15:27:28 +0000 (+0100) Subject: Merge symbol tables. (Not fully ELF conformant) X-Git-Url: https://git.enpas.org/?p=centaur.git;a=commitdiff_plain;h=5868bb32246367139f0d17a989650964f90a7958 Merge symbol tables. (Not fully ELF conformant) Also, remove that nameptr member from symbols. It just *had* to cause trouble. Symbols are simply appended to the target's symbol table, which means that LOCAL symbols are not inserted at the beginning and we are thus ignoring an ELF spec. Might change that in the future, it's good enough for now and it's sure not to break anything with the old symbols. The code currently assumes that the target *has* a symbol table. We'll have to fix that, and also remove undefined and duplicate symbols. --- 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 +#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 -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;