From d217921268e5b2d9e38023c25e55dc315b8e3263 Mon Sep 17 00:00:00 2001 From: norly Date: Sat, 1 Jun 2013 17:42:36 +0100 Subject: [PATCH] Basic 32-bit SYMTAB and REL (not RELA) support --- include/libelfu/debug.h | 2 + include/libelfu/modelops.h | 14 ++-- include/libelfu/types.h | 49 +++++++++++ src/elfops/check.c | 5 ++ src/model/clone.c | 3 + src/model/dump.c | 4 +- src/model/fromFile.c | 161 ++++++++++++++++++++++++++++++++++++- src/model/reladd.c | 43 +++++----- src/model/relocate.c | 85 ++++++++++++++++++++ src/model/section.c | 45 ++++++++--- src/model/toFile.c | 6 +- 11 files changed, 378 insertions(+), 39 deletions(-) create mode 100644 src/model/relocate.c diff --git a/include/libelfu/debug.h b/include/libelfu/debug.h index 6b817b3..b9f9161 100644 --- a/include/libelfu/debug.h +++ b/include/libelfu/debug.h @@ -4,6 +4,8 @@ #include +#define ELFU_DEBUG(...) do { fprintf(stdout, __VA_ARGS__); } while(0) + #define ELFU_INFO(...) do { fprintf(stdout, __VA_ARGS__); } while(0) #define ELFU_WARN(...) do { fprintf(stderr, __VA_ARGS__); } while(0) diff --git a/include/libelfu/modelops.h b/include/libelfu/modelops.h index b56f133..3daef52 100644 --- a/include/libelfu/modelops.h +++ b/include/libelfu/modelops.h @@ -11,11 +11,12 @@ size_t elfu_mPhdrCount(ElfuElf *me); void elfu_mPhdrUpdateChildOffsets(ElfuPhdr *mp); -typedef int (SectionHandlerFunc)(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2); -int elfu_mScnForall(ElfuElf *me, SectionHandlerFunc f, void *aux1, void *aux2); -size_t elfu_mScnCount(ElfuElf *me); -size_t elfu_mScnIndex(ElfuElf *me, ElfuScn *ms); -char* elfu_mScnName(ElfuElf *me, ElfuScn *ms); +typedef void* (SectionHandlerFunc)(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2); + void* elfu_mScnForall(ElfuElf *me, SectionHandlerFunc f, void *aux1, void *aux2); + size_t elfu_mScnCount(ElfuElf *me); + size_t elfu_mScnIndex(ElfuElf *me, ElfuScn *ms); + ElfuScn* elfu_mScnByOldscn(ElfuElf *me, ElfuScn *oldscn); + char* elfu_mScnName(ElfuElf *me, ElfuScn *ms); ElfuScn** elfu_mScnSortedByOffset(ElfuElf *me, size_t *count); @@ -25,6 +26,9 @@ GElf_Addr elfu_mLayoutGetSpaceInPhdr(ElfuElf *me, GElf_Word size, int elfu_mLayoutAuto(ElfuElf *me); +void elfu_mRelocate32(ElfuElf *metarget, ElfuScn *mstarget, ElfuScn *msrt); + + int elfu_mCheck(ElfuElf *me); ElfuScn* elfu_mCloneScn(ElfuScn *ms); diff --git a/include/libelfu/types.h b/include/libelfu/types.h index 177bbaf..2a0fcf3 100644 --- a/include/libelfu/types.h +++ b/include/libelfu/types.h @@ -17,6 +17,9 @@ typedef struct ElfuScn { struct ElfuScn *oldptr; + struct ElfuSymtab *symtab; + struct ElfuReltab *reltab; + CIRCLEQ_ENTRY(ElfuScn) elemChildScn; CIRCLEQ_ENTRY(ElfuScn) elem; } ElfuScn; @@ -44,4 +47,50 @@ typedef struct { } ElfuElf; + + + +typedef struct ElfuSym { + char *name; + + GElf_Addr value; + GElf_Word size; + + unsigned char bind; + unsigned char type; + unsigned char other; + + ElfuScn *scnptr; + + CIRCLEQ_ENTRY(ElfuSym) elem; +} ElfuSym; + + +typedef struct ElfuSymtab { + CIRCLEQ_HEAD(Syms, ElfuSym) syms; +} ElfuSymtab; + + + +typedef struct ElfuRel { + char *name; + + GElf_Addr offset; + GElf_Word info; + + GElf_Word sym; + unsigned char type; + + int addendUsed; + GElf_Sword addend; + + CIRCLEQ_ENTRY(ElfuRel) elem; +} ElfuRel; + + +typedef struct ElfuReltab { + CIRCLEQ_HEAD(Rels, ElfuRel) rels; +} ElfuReltab; + + #endif 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 +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; @@ -142,14 +142,20 @@ int subScnAdd1(ElfuElf *mrel, ElfuScn *ms, void *aux1, void *aux2) elfu_mScnName(mrel, ms), 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 +#include +#include + + +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; } -- 2.30.2