diff options
author | norly <ny-git@enpas.org> | 2013-06-15 16:27:28 +0100 |
---|---|---|
committer | norly <ny-git@enpas.org> | 2013-06-15 16:32:15 +0100 |
commit | 5868bb32246367139f0d17a989650964f90a7958 (patch) | |
tree | 7601bc12cfe88cb3c180c42fe1e3d1ee293c3559 /src/modelops/reladd.c | |
parent | 3c14755015340e48ae68aa874f672e7c9d289832 (diff) |
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.
Diffstat (limited to 'src/modelops/reladd.c')
-rw-r--r-- | src/modelops/reladd.c | 101 |
1 files changed, 98 insertions, 3 deletions
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); |