summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/elfops/check.c5
-rw-r--r--src/model/clone.c3
-rw-r--r--src/model/dump.c4
-rw-r--r--src/model/fromFile.c161
-rw-r--r--src/model/reladd.c43
-rw-r--r--src/model/relocate.c85
-rw-r--r--src/model/section.c45
-rw-r--r--src/model/toFile.c6
8 files changed, 318 insertions, 34 deletions
diff --git a/src/elfops/check.c b/src/elfops/check.c
index 2c7f040..6e56bae 100644
--- a/src/elfops/check.c
+++ b/src/elfops/check.c
@@ -24,6 +24,11 @@ int elfu_eCheck(Elf *e)
goto ERROR;
}
+ if (ehdr.e_machine != EM_386) {
+ ELFU_WARN("Sorry, only x86-32 ELF files are supported at the moment.\n");
+ goto ERROR;
+ }
+
if (elf_getphdrnum(e, &numPhdr)) {
ELFU_WARNELF("elf_getphdrnum");
goto ERROR;
diff --git a/src/model/clone.c b/src/model/clone.c
index 644647c..ca4b38f 100644
--- a/src/model/clone.c
+++ b/src/model/clone.c
@@ -34,5 +34,8 @@ ElfuScn* elfu_mCloneScn(ElfuScn *ms)
newscn->oldptr = ms;
+ ms->symtab = NULL;
+ ms->reltab = NULL;
+
return newscn;
}
diff --git a/src/model/dump.c b/src/model/dump.c
index 5f0642a..27556f9 100644
--- a/src/model/dump.c
+++ b/src/model/dump.c
@@ -185,7 +185,7 @@ void elfu_mDumpEhdr(ElfuElf *me)
-static int subScnDump(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
+static void* subScnDump(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
{
(void) aux1;
(void) aux2;
@@ -193,7 +193,7 @@ static int subScnDump(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
printf(" [%4d] ", elfu_mScnIndex(me, ms));
elfu_mDumpScn(me, ms);
- return 0;
+ return NULL;
}
diff --git a/src/model/fromFile.c b/src/model/fromFile.c
index 11a7fb5..84ec143 100644
--- a/src/model/fromFile.c
+++ b/src/model/fromFile.c
@@ -5,6 +5,120 @@
#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 ElfuSymtab* symtabFromScn32(ElfuScn *ms, ElfuScn**origScnArr)
+{
+ ElfuSymtab *st;
+ size_t i;
+
+ assert(ms);
+ assert(ms->data.d_buf);
+ assert(origScnArr);
+
+
+ st = malloc(sizeof(*st));
+ if (!st) {
+ ELFU_WARN("elfu_mSymtabFromScn32: malloc() failed for st.\n");
+ goto ERROR;
+ }
+
+ CIRCLEQ_INIT(&st->syms);
+
+
+ for (i = 1; (i + 1) * sizeof(Elf32_Sym) <= ms->shdr.sh_size; i++) {
+ Elf32_Sym *cursym = &(((Elf32_Sym*)ms->data.d_buf)[i]);
+ ElfuSym *sym = malloc(sizeof(*sym));
+ assert(sym);
+
+ sym->name = 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;
+
+ switch (cursym->st_shndx) {
+ case SHN_UNDEF:
+ case SHN_ABS:
+ case SHN_COMMON:
+ sym->scnptr = NULL;
+ break;
+ default:
+ sym->scnptr = origScnArr[cursym->st_shndx - 1];
+ break;
+ }
+
+ CIRCLEQ_INSERT_TAIL(&st->syms, sym, elem);
+ }
+
+
+ return st;
+
+ ERROR:
+ if (st) {
+ free(st);
+ }
+ return NULL;
+}
+
+
+static ElfuReltab* reltabFromScn32(ElfuScn *ms)
+{
+ ElfuReltab *rt;
+ size_t i;
+
+ assert(ms);
+ assert(ms->data.d_buf);
+
+
+ rt = malloc(sizeof(*rt));
+ if (!rt) {
+ ELFU_WARN("elfu_mReltabFromScn32: malloc() failed for rt.\n");
+ goto ERROR;
+ }
+
+ CIRCLEQ_INIT(&rt->rels);
+
+
+ for (i = 0; (i + 1) * sizeof(Elf32_Rel) <= ms->shdr.sh_size; i++) {
+ Elf32_Rel *currel = &(((Elf32_Rel*)ms->data.d_buf)[i]);
+ ElfuRel *rel;
+
+ rel = malloc(sizeof(*rel));
+ assert(rel);
+
+ rel->offset = currel->r_offset;
+
+ rel->sym = ELF32_R_SYM(currel->r_info);
+ rel->type = ELF32_R_TYPE(currel->r_info);
+
+ rel->addendUsed = 0;
+ rel->addend = 0;
+
+ CIRCLEQ_INSERT_TAIL(&rt->rels, rel, elem);
+ }
+
+
+ return rt;
+
+ ERROR:
+ if (rt) {
+ free(rt);
+ }
+ return NULL;
+}
+
+
static int cmpScnOffs(const void *ms1, const void *ms2)
{
assert(ms1);
@@ -139,6 +253,9 @@ static ElfuScn* modelFromSection(Elf_Scn *scn)
ms->oldptr = NULL;
+ ms->symtab = NULL;
+ ms->reltab = NULL;
+
return ms;
@@ -257,7 +374,7 @@ ElfuElf* elfu_mFromElf(Elf *e)
}
- /* Find sh_link dependencies */
+ /* Find sh_link and sh_info dependencies (needs sections in original order) */
for (i = 0; i < numShdr - 1; i++) {
ElfuScn *ms = secArray[i];
@@ -281,6 +398,48 @@ ElfuElf* elfu_mFromElf(Elf *e)
}
+ /* Parse symtabs (needs sections in original order) */
+ for (i = 0; i < numShdr - 1; i++) {
+ ElfuScn *ms = secArray[i];
+
+ switch (ms->shdr.sh_type) {
+ case SHT_SYMTAB:
+ if (me->elfclass == ELFCLASS32) {
+ ms->symtab = symtabFromScn32(ms, secArray);
+ } else if (me->elfclass == ELFCLASS64) {
+ // TODO
+ }
+ assert(ms->symtab);
+ break;
+ }
+ }
+
+
+ /* Parse relocations */
+ for (i = 0; i < numShdr - 1; i++) {
+ ElfuScn *ms = secArray[i];
+
+ switch (ms->shdr.sh_type) {
+ case SHT_REL:
+ if (me->elfclass == ELFCLASS32) {
+ ms->reltab = reltabFromScn32(ms);
+ } else if (me->elfclass == ELFCLASS64) {
+ // TODO
+ }
+ assert(ms->reltab);
+ break;
+ case SHT_RELA:
+ if (me->elfclass == ELFCLASS32) {
+ // TODO
+ } else if (me->elfclass == ELFCLASS64) {
+ // TODO
+ }
+ assert(ms->reltab);
+ break;
+ }
+ }
+
+
/* Sort sections by file offset */
qsort(secArray, numShdr - 1, sizeof(*secArray), cmpScnOffs);
diff --git a/src/model/reladd.c b/src/model/reladd.c
index 665f20a..a3ccc99 100644
--- a/src/model/reladd.c
+++ b/src/model/reladd.c
@@ -126,7 +126,7 @@ static ElfuScn* insertSection(ElfuElf *me, ElfuElf *mrel, ElfuScn *oldscn)
}
-int subScnAdd1(ElfuElf *mrel, ElfuScn *ms, void *aux1, void *aux2)
+static void* subScnAdd1(ElfuElf *mrel, ElfuScn *ms, void *aux1, void *aux2)
{
(void)aux2;
ElfuElf *me = (ElfuElf*)aux1;
@@ -143,13 +143,19 @@ int subScnAdd1(ElfuElf *mrel, ElfuScn *ms, void *aux1, void *aux2)
ms->shdr.sh_type);
}
break;
+ case SHT_NOBITS: /* 8 */
+ /* Expand this to SHT_PROGBITS, then insert as such. */
+
+ // TODO
+
+ break;
}
- return 0;
+ return NULL;
}
-int subScnAdd2(ElfuElf *mrel, ElfuScn *ms, void *aux1, void *aux2)
+static void* subScnAdd2(ElfuElf *mrel, ElfuScn *ms, void *aux1, void *aux2)
{
(void)aux2;
ElfuElf *me = (ElfuElf*)aux1;
@@ -160,34 +166,35 @@ int subScnAdd2(ElfuElf *mrel, ElfuScn *ms, void *aux1, void *aux2)
case SHT_PROGBITS: /* 1 */
break;
+
+ case SHT_REL: /* 9 */
+ /* Relocate. */
+ elfu_mRelocate32(me, elfu_mScnByOldscn(me, ms->infoptr), ms);
+ break;
+
+ case SHT_RELA: /* 4 */
+ // TODO: Needs a parser
+ //elfu_mRelocate(elfu_mScnByOldscn(me, ms->infoptr), ms);
+
case SHT_SYMTAB: /* 2 */
- case SHT_DYNSYM: /* 11 */
/* Merge with the existing table. Take care of string tables also. */
case SHT_STRTAB: /* 3 */
/* May have to be merged with the existing string table for
* the symbol table. */
- case SHT_RELA: /* 4 */
- case SHT_REL: /* 9 */
- /* Possibly append this in memory to the section model
- * that it describes. */
-
- case SHT_NOBITS: /* 8 */
- /* Expand this to SHT_PROGBITS, then insert as such. */
-
+ /* The next section types either do not occur in .o files, or are
+ * not strictly necessary to process here. */
+ case SHT_NOTE: /* 7 */
case SHT_HASH: /* 5 */
case SHT_DYNAMIC: /* 6 */
case SHT_SHLIB: /* 10 */
- case SHT_SYMTAB_SHNDX: /* 18 */
-
- /* Don't care about the next ones yet. I've never seen
- * them and they can be implemented when necessary. */
- case SHT_NOTE: /* 7 */
+ case SHT_DYNSYM: /* 11 */
case SHT_INIT_ARRAY: /* 14 */
case SHT_FINI_ARRAY: /* 15 */
case SHT_PREINIT_ARRAY: /* 16 */
case SHT_GROUP: /* 17 */
+ case SHT_SYMTAB_SHNDX: /* 18 */
case SHT_NUM: /* 19 */
default:
ELFU_WARN("mReladd: Skipping section %s (type %d).\n",
@@ -195,7 +202,7 @@ int subScnAdd2(ElfuElf *mrel, ElfuScn *ms, void *aux1, void *aux2)
ms->shdr.sh_type);
}
- return 0;
+ return NULL;
}
diff --git a/src/model/relocate.c b/src/model/relocate.c
new file mode 100644
index 0000000..1b4f9ff
--- /dev/null
+++ b/src/model/relocate.c
@@ -0,0 +1,85 @@
+#include <assert.h>
+#include <stdlib.h>
+#include <libelfu/libelfu.h>
+
+
+static GElf_Word symtabLookupVal(ElfuElf *metarget, ElfuScn *msst, GElf_Word entry)
+{
+ GElf_Word i;
+ ElfuSym *sym;
+
+ assert(metarget);
+ assert(msst);
+ assert(msst->symtab);
+ assert(entry > 0);
+ assert(!CIRCLEQ_EMPTY(&msst->symtab->syms));
+
+ sym = CIRCLEQ_FIRST(&msst->symtab->syms);
+ for (i = 1; i < entry; i++) {
+ sym = CIRCLEQ_NEXT(sym, elem);
+ }
+
+ 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;
+ } else {
+ // TODO: UNDEF, ABS, or COMMON
+ ELFU_WARN("symtabLookupVal: Returning 0 for UNDEF, ABS, or COMMON symbol.\n");
+ }
+ break;
+ case STT_SECTION:
+ assert(sym->scnptr);
+ assert(elfu_mScnByOldscn(metarget, sym->scnptr));
+ return elfu_mScnByOldscn(metarget, sym->scnptr)->shdr.sh_addr;
+ case STT_FILE:
+ // TODO
+ ELFU_WARN("symtabLookupVal: Returning 0 for FILE symbol.\n");
+ break;
+ default:
+ ELFU_WARN("symtabLookupVal: Unknown symbol type %d.\n", sym->type);
+ return 0;
+ }
+}
+
+void elfu_mRelocate32(ElfuElf *metarget, ElfuScn *mstarget, ElfuScn *msrt)
+{
+ ElfuRel *rel;
+
+ assert(mstarget);
+ assert(msrt);
+
+ ELFU_DEBUG("Relocating in section of type %d size %jx\n",
+ mstarget->shdr.sh_type,
+ mstarget->shdr.sh_size);
+
+ CIRCLEQ_FOREACH(rel, &msrt->reltab->rels, elem) {
+ Elf32_Word *dest = (Elf32_Word*)(((char*)(mstarget->data.d_buf)) + rel->offset);
+ Elf32_Word a = rel->addendUsed ? rel->addend : *dest;
+ Elf32_Addr p = mstarget->shdr.sh_addr + rel->offset;
+ Elf32_Addr s = symtabLookupVal(metarget, msrt->linkptr, rel->sym);
+ Elf32_Word newval = *dest;
+
+ switch(rel->type) {
+ case R_386_NONE:
+ ELFU_DEBUG("Skipping relocation: R_386_NONE");
+ break;
+ case R_386_32:
+ ELFU_DEBUG("Relocation: R_386_32");
+ newval = s + a;
+ break;
+ case R_386_PC32:
+ ELFU_DEBUG("Relocation: R_386_PC32");
+ newval = s + a - p;
+ break;
+
+ default:
+ ELFU_DEBUG("Skipping relocation: Unknown type %d", rel->type);
+ }
+ ELFU_DEBUG(", overwriting %x with %x.\n", *dest, newval);
+ *dest = newval;
+ }
+}
diff --git a/src/model/section.c b/src/model/section.c
index 4b8b230..a96377c 100644
--- a/src/model/section.c
+++ b/src/model/section.c
@@ -5,7 +5,7 @@
/* Meta-functions */
-int elfu_mScnForall(ElfuElf *me, SectionHandlerFunc f, void *aux1, void *aux2)
+void* elfu_mScnForall(ElfuElf *me, SectionHandlerFunc f, void *aux1, void *aux2)
{
ElfuPhdr *mp;
ElfuScn *ms;
@@ -18,7 +18,7 @@ int elfu_mScnForall(ElfuElf *me, SectionHandlerFunc f, void *aux1, void *aux2)
}
CIRCLEQ_FOREACH(ms, &mp->childScnList, elemChildScn) {
- int rv = f(me, ms, aux1, aux2);
+ void *rv = f(me, ms, aux1, aux2);
if (rv) {
return rv;
@@ -27,14 +27,14 @@ int elfu_mScnForall(ElfuElf *me, SectionHandlerFunc f, void *aux1, void *aux2)
}
CIRCLEQ_FOREACH(ms, &me->orphanScnList, elemChildScn) {
- int rv = f(me, ms, aux1, aux2);
+ void *rv = f(me, ms, aux1, aux2);
if (rv) {
return rv;
}
}
- return 0;
+ return NULL;
}
@@ -42,18 +42,19 @@ int elfu_mScnForall(ElfuElf *me, SectionHandlerFunc f, void *aux1, void *aux2)
/* Counting */
-static int subCounter(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
+static void* subCounter(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
{
size_t *i = (size_t*)aux1;
ElfuScn *otherScn = (ElfuScn*)aux2;
if (ms == otherScn) {
- return 1;
+ return ms;
}
*i += 1;
- return 0;
+ /* Continue */
+ return NULL;
}
@@ -70,7 +71,7 @@ size_t elfu_mScnCount(ElfuElf *me)
}
-/* Returns the section index equivalent to the model flattened to ELF */
+/* Returns the index a section would have in the flattened ELF */
size_t elfu_mScnIndex(ElfuElf *me, ElfuScn *ms)
{
/* NULL section *is* counted */
@@ -87,6 +88,29 @@ size_t elfu_mScnIndex(ElfuElf *me, ElfuScn *ms)
}
+static void* subOldscn(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
+{
+ ElfuScn *otherScn = (ElfuScn*)aux1;
+ (void)aux2;
+
+ if (ms->oldptr == otherScn) {
+ return ms;
+ }
+
+ /* Continue */
+ return NULL;
+}
+
+/* Returns the section with oldscn == oldscn */
+ElfuScn* elfu_mScnByOldscn(ElfuElf *me, ElfuScn *oldscn)
+{
+ assert(me);
+ assert(oldscn);
+
+ return elfu_mScnForall(me, subOldscn, oldscn, NULL);
+}
+
+
/* Convenience */
@@ -108,7 +132,7 @@ char* elfu_mScnName(ElfuElf *me, ElfuScn *ms)
}
-static int subScnsToArray(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
+static void* subScnsToArray(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
{
ElfuScn **arr = (ElfuScn**)aux1;
size_t *i = (size_t*)aux2;
@@ -116,7 +140,8 @@ static int subScnsToArray(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
arr[(*i)] = ms;
*i += 1;
- return 0;
+ /* Continue */
+ return NULL;
}
static int cmpScnOffs(const void *ms1, const void *ms2)
diff --git a/src/model/toFile.c b/src/model/toFile.c
index eaf6ce5..da06f4a 100644
--- a/src/model/toFile.c
+++ b/src/model/toFile.c
@@ -31,7 +31,7 @@ static void modelToPhdrs(ElfuElf *me, Elf *e)
-static int modelToSection(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
+static void* modelToSection(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
{
(void) me;
(void) aux2;
@@ -41,7 +41,7 @@ static int modelToSection(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
scnOut = elf_newscn(e);
if (!scnOut) {
ELFU_WARNELF("elf_newscn");
- return 1;
+ return (void*)-1;
}
@@ -72,7 +72,7 @@ static int modelToSection(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
dataOut->d_version = ms->data.d_version;
}
- return 0;
+ return NULL;
}