EXEOBJS := $(patsubst %.c, $(BUILDDIR)/%.o, $(EXESRCS))
INCLUDES := $(patsubst %, -I%, $(INCLUDEDIR) $(SRCDIR)) $(shell pkg-config --cflags-only-I $(LIBRARIES))
-CFLAGS := -g -Wall -pedantic -Wno-variadic-macros -fPIC $(shell pkg-config --cflags-only-other $(LIBRARIES))
+CFLAGS := -g -Wall -std=gnu99 -pedantic -fPIC $(shell pkg-config --cflags-only-other $(LIBRARIES))
LDFLAGS := $(shell pkg-config --libs $(LIBRARIES))
#include <libelfu/types.h>
-#define ELFU_SYMSTR(symtabscn, off) (((char*)(symtabscn)->linkptr->data.d_buf) + (off))
+#define ELFU_SYMSTR(symtabscn, off) ((symtabscn)->linkptr->databuf + (off))
GElf_Word elfu_mSymtabLookupVal(ElfuElf *me, ElfuScn *msst, GElf_Word entry);
ElfuScn* elfu_mScnByOldscn(ElfuElf *me, ElfuScn *oldscn);
char* elfu_mScnName(ElfuElf *me, ElfuScn *ms);
ElfuScn** elfu_mScnSortedByOffset(ElfuElf *me, size_t *count);
+ElfuScn* elfu_mScnAlloc();
GElf_Addr elfu_mLayoutGetSpaceInPhdr(ElfuElf *me, GElf_Word size,
typedef struct ElfuScn {
GElf_Shdr shdr;
- Elf_Data data;
-
struct ElfuScn *linkptr;
struct ElfuScn *infoptr;
+ char *databuf;
struct ElfuScn *oldptr;
--- /dev/null
+#include <assert.h>
+#include <libelfu/libelfu.h>
+
+
+size_t elfu_mPhdrCount(ElfuElf *me)
+{
+ ElfuPhdr *mp;
+ size_t i = 0;
+
+ assert(me);
+
+ CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
+ i++;
+ }
+
+ return i;
+}
+
+
+
+void elfu_mPhdrUpdateChildOffsets(ElfuPhdr *mp)
+{
+ ElfuScn *ms;
+ ElfuPhdr *mpc;
+
+ assert(mp);
+ assert(mp->phdr.p_type == PT_LOAD);
+
+ CIRCLEQ_FOREACH(mpc, &mp->childPhdrList, elemChildPhdr) {
+ mpc->phdr.p_offset = mp->phdr.p_offset + (mpc->phdr.p_vaddr - mp->phdr.p_vaddr);
+ }
+
+ CIRCLEQ_FOREACH(ms, &mp->childScnList, elemChildScn) {
+ ms->shdr.sh_offset = mp->phdr.p_offset + (ms->shdr.sh_addr - mp->phdr.p_vaddr);
+ }
+}
--- /dev/null
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libelfu/libelfu.h>
+
+
+/* Meta-functions */
+
+void* elfu_mScnForall(ElfuElf *me, SectionHandlerFunc f, void *aux1, void *aux2)
+{
+ ElfuPhdr *mp;
+ ElfuScn *ms;
+
+ // TODO: Sort PHDRs by offset before interating
+
+ CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
+ if (mp->phdr.p_type != PT_LOAD) {
+ continue;
+ }
+
+ CIRCLEQ_FOREACH(ms, &mp->childScnList, elemChildScn) {
+ void *rv = f(me, ms, aux1, aux2);
+
+ if (rv) {
+ return rv;
+ }
+ }
+ }
+
+ CIRCLEQ_FOREACH(ms, &me->orphanScnList, elemChildScn) {
+ void *rv = f(me, ms, aux1, aux2);
+
+ if (rv) {
+ return rv;
+ }
+ }
+
+ return NULL;
+}
+
+
+
+
+/* Counting */
+
+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 ms;
+ }
+
+ *i += 1;
+
+ /* Continue */
+ return NULL;
+}
+
+
+size_t elfu_mScnCount(ElfuElf *me)
+{
+ /* NULL section *is not* counted */
+ size_t i = 0;
+
+ assert(me);
+
+ elfu_mScnForall(me, subCounter, &i, NULL);
+
+ return i;
+}
+
+
+/* Returns the index a section would have in the flattened ELF */
+size_t elfu_mScnIndex(ElfuElf *me, ElfuScn *ms)
+{
+ /* NULL section *is* counted */
+ size_t i = 1;
+
+ assert(me);
+ assert(ms);
+
+ elfu_mScnForall(me, subCounter, &i, ms);
+
+ /* If this assertion is broken then ms is not a section in me. */
+ assert(i <= elfu_mScnCount(me));
+ return i;
+}
+
+
+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 */
+
+char* elfu_mScnName(ElfuElf *me, ElfuScn *ms)
+{
+ assert(me);
+ assert(ms);
+
+ if (!me->shstrtab) {
+ return NULL;
+ }
+
+ if (!me->shstrtab->databuf) {
+ return NULL;
+ }
+
+ return &me->shstrtab->databuf[ms->shdr.sh_name];
+}
+
+
+static void* subScnsToArray(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
+{
+ ElfuScn **arr = (ElfuScn**)aux1;
+ size_t *i = (size_t*)aux2;
+
+ arr[(*i)] = ms;
+ *i += 1;
+
+ /* Continue */
+ return NULL;
+}
+
+static int cmpScnOffs(const void *ms1, const void *ms2)
+{
+ ElfuScn *s1;
+ ElfuScn *s2;
+
+ assert(ms1);
+ assert(ms2);
+
+ s1 = *(ElfuScn**)ms1;
+ s2 = *(ElfuScn**)ms2;
+
+ assert(s1);
+ assert(s2);
+
+
+ if (s1->shdr.sh_offset < s2->shdr.sh_offset) {
+ return -1;
+ } else if (s1->shdr.sh_offset == s2->shdr.sh_offset) {
+ return 0;
+ } else /* if (s1->shdr.sh_offset > s2->shdr.sh_offset) */ {
+ return 1;
+ }
+}
+
+ElfuScn** elfu_mScnSortedByOffset(ElfuElf *me, size_t *count)
+{
+ size_t numSecs;
+ ElfuScn **sortedSecs;
+ size_t i;
+
+ assert(me);
+
+ /* Sort sections by offset in file */
+ numSecs = elfu_mScnCount(me);
+ sortedSecs = malloc(numSecs * sizeof(*sortedSecs));
+ if (!sortedSecs) {
+ ELFU_WARN("elfu_mScnSortedByOffset: Failed to allocate memory.\n");
+ return NULL;
+ }
+
+ i = 0;
+ elfu_mScnForall(me, subScnsToArray, sortedSecs, &i);
+ assert(i == numSecs);
+
+ qsort(sortedSecs, numSecs, sizeof(*sortedSecs), cmpScnOffs);
+
+ *count = numSecs;
+
+ return sortedSecs;
+}
+
+
+
+/*
+ * Allocation, destruction
+ */
+
+ElfuScn* elfu_mScnAlloc()
+{
+ ElfuScn *ms;
+
+ ms = malloc(sizeof(ElfuScn));
+ if (!ms) {
+ ELFU_WARN("mScnCreate: malloc() failed for ElfuScn.\n");
+ return NULL;
+ }
+
+ memset(ms, 0, sizeof(*ms));
+
+ CIRCLEQ_INIT(&ms->symtab.syms);
+ CIRCLEQ_INIT(&ms->reltab.rels);
+
+ return ms;
+}
--- /dev/null
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libelfu/libelfu.h>
+
+
+static void* subFindByName(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
+{
+ char *name = (char*)aux1;
+ (void)aux2;
+
+ if (elfu_mScnName(me, ms)) {
+ if (!strcmp(elfu_mScnName(me, ms), name)) {
+ return ms;
+ }
+ }
+
+ /* Continue */
+ return NULL;
+}
+
+/* Hazard a guess where a function may be found in the PLT */
+static GElf_Word pltLookupVal(ElfuElf *me, char *name)
+{
+ ElfuScn *relplt;
+ ElfuScn *plt;
+ ElfuRel *rel;
+ GElf_Word j;
+
+ relplt = elfu_mScnForall(me, subFindByName, ".rel.plt", NULL);
+ if (!relplt) {
+ ELFU_WARN("dynsymLookupVal: Could not find .rel.plt section in destination ELF.\n");
+ return 0;
+ }
+
+ plt = elfu_mScnForall(me, subFindByName, ".plt", NULL);
+ if (!plt) {
+ ELFU_WARN("dynsymLookupVal: Could not find .plt section in destination ELF.\n");
+ return 0;
+ }
+
+
+ /* 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 ((me->elfclass == ELFCLASS32 && rel->type != R_386_JMP_SLOT)
+ || (me->elfclass == ELFCLASS64 && rel->type != R_X86_64_JUMP_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);
+ }
+
+ 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
+ * the number of bytes the machine code in a PLT entry take. */
+ GElf_Addr addr = plt->shdr.sh_addr + (16 * j);
+ ELFU_DEBUG("dynsymLookupVal: Guessing symbol '%s' is in destination memory at %x (PLT entry #%u).\n", name, (unsigned)addr, j);
+ return addr;
+ }
+ }
+
+ ELFU_WARN("dynsymLookupVal: Could not find symbol '%s' in destination ELF.\n", name);
+
+ return 0;
+}
+
+
+
+/* Look up a value in the symbol table section *msst which is in *me.
+ * If it is not found there, see if we can find it in *me's PLT. */
+GElf_Word elfu_mSymtabLookupVal(ElfuElf *me, ElfuScn *msst, GElf_Word entry)
+{
+ GElf_Word i;
+ ElfuSym *sym;
+ char *symname;
+
+ assert(me);
+ assert(msst);
+ 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);
+ }
+ symname = ELFU_SYMSTR(msst, sym->name);
+
+ switch (sym->type) {
+ case STT_NOTYPE:
+ case STT_OBJECT:
+ case STT_FUNC:
+ if (sym->scnptr) {
+ ElfuScn *newscn = elfu_mScnByOldscn(me, sym->scnptr);
+ assert(newscn);
+ return newscn->shdr.sh_addr + sym->value;
+ } else if (sym->shndx == SHN_UNDEF) {
+ /* 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(me, symname);
+ } else if (sym->shndx == SHN_ABS) {
+ return sym->value;
+ } else {
+ ELFU_WARN("symtabLookupVal: Symbol binding COMMON is not supported, using 0.\n");
+ return 0;
+ }
+ break;
+ case STT_SECTION:
+ assert(sym->scnptr);
+ assert(elfu_mScnByOldscn(me, sym->scnptr));
+ return elfu_mScnByOldscn(me, sym->scnptr)->shdr.sh_addr;
+ case STT_FILE:
+ 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, symname);
+ return 0;
+ }
+}
+
+
+/* Look up a value in the symbol table section *msst which is in *me. */
+GElf_Word elfu_mSymtabLookupAddrByName(ElfuElf *me, ElfuScn *msst, char *name)
+{
+ ElfuSym *sym;
+
+ assert(me);
+ assert(msst);
+ assert(name);
+ assert(strlen(name) > 0);
+ assert(!CIRCLEQ_EMPTY(&msst->symtab.syms));
+
+ CIRCLEQ_FOREACH(sym, &msst->symtab.syms, elem) {
+ char *symname = ELFU_SYMSTR(msst, sym->name);
+
+ if (!strcmp(symname, name)) {
+ goto SYMBOL_FOUND;
+ }
+ }
+ return 0;
+
+
+ SYMBOL_FOUND:
+
+ switch (sym->type) {
+ case STT_NOTYPE:
+ case STT_OBJECT:
+ case STT_FUNC:
+ if (sym->scnptr) {
+ GElf_Addr a = sym->value;
+ a += me->ehdr.e_type == ET_REL ? sym->scnptr->shdr.sh_addr : 0;
+ return a;
+ } else if (sym->shndx == SHN_UNDEF) {
+ return 0;
+ } else if (sym->shndx == SHN_ABS) {
+ return sym->value;
+ } else {
+ ELFU_WARN("elfu_mSymtabLookupAddrByName: Symbol binding COMMON is not supported, using 0.\n");
+ return 0;
+ }
+ break;
+ default:
+ return 0;
+ }
+}
+
+
+
+/* Convert symtab from memory model to elfclass specific format */
+void elfu_mSymtabFlatten(ElfuElf *me)
+{
+ ElfuSym *sym;
+ size_t numsyms = 0;
+
+ 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);
+ }
+
+ numsyms++;
+ }
+
+ /* Copy symbols to elfclass-specific format */
+ if (me->elfclass == ELFCLASS32) {
+ size_t newsize = (numsyms + 1) * sizeof(Elf32_Sym);
+ size_t i;
+
+ if (me->symtab->databuf) {
+ free(me->symtab->databuf);
+ }
+ me->symtab->databuf = malloc(newsize);
+ assert(me->symtab->databuf);
+
+ me->symtab->shdr.sh_size = newsize;
+ memset(me->symtab->databuf, 0, newsize);
+
+ i = 1;
+ CIRCLEQ_FOREACH(sym, &me->symtab->symtab.syms, elem) {
+ Elf32_Sym *es = ((Elf32_Sym*)me->symtab->databuf) + i;
+
+ es->st_name = sym->name;
+ es->st_value = sym->value;
+ es->st_size = sym->size;
+ es->st_info = ELF32_ST_INFO(sym->bind, sym->type);
+ es->st_other = sym->other;
+ es->st_shndx = sym->shndx;
+
+ i++;
+ }
+ } else if (me->elfclass == ELFCLASS64) {
+ size_t newsize = (numsyms + 1) * sizeof(Elf64_Sym);
+ size_t i;
+
+ if (me->symtab->databuf) {
+ free(me->symtab->databuf);
+ }
+ me->symtab->databuf = malloc(newsize);
+ assert(me->symtab->databuf);
+
+ me->symtab->shdr.sh_size = newsize;
+ memset(me->symtab->databuf, 0, newsize);
+
+ i = 1;
+ CIRCLEQ_FOREACH(sym, &me->symtab->symtab.syms, elem) {
+ Elf64_Sym *es = ((Elf64_Sym*)me->symtab->databuf) + i;
+
+ es->st_name = sym->name;
+ es->st_value = sym->value;
+ es->st_size = sym->size;
+ es->st_info = ELF64_ST_INFO(sym->bind, sym->type);
+ es->st_other = sym->other;
+ es->st_shndx = sym->shndx;
+
+ i++;
+ }
+ } else {
+ /* Unknown elfclass */
+ assert(0);
+ }
+
+ elfu_mLayoutAuto(me);
+}
assert(ms);
- newscn = malloc(sizeof(ElfuScn));
+ newscn = elfu_mScnAlloc();
if (!newscn) {
ELFU_WARN("elfu_nCloneScn: Could not allocate memory for new ElfuScn.\n");
return NULL;
}
newscn->shdr = ms->shdr;
- newscn->data = ms->data;
- if (ms->data.d_buf) {
- void *newbuf = malloc(ms->data.d_size);
+
+ if (ms->databuf) {
+ void *newbuf = malloc(ms->shdr.sh_size);
if (!newbuf) {
ELFU_WARN("elfu_nCloneScn: Could not allocate memory for new data buffer.\n");
free(newscn);
return NULL;
}
- memcpy(newbuf, ms->data.d_buf, ms->data.d_size);
- newscn->data.d_buf = newbuf;
+ memcpy(newbuf, ms->databuf, ms->shdr.sh_size);
+ newscn->databuf = newbuf;
}
- newscn->linkptr = NULL;
- newscn->infoptr = NULL;
-
newscn->oldptr = ms;
- CIRCLEQ_INIT(&ms->symtab.syms);
- CIRCLEQ_INIT(&ms->reltab.rels);
-
return newscn;
}
(unsigned)to);
*(Elf32_Word*)(detourcode + 1) = to - from - 5;
- memcpy((char*)ms->data.d_buf + scnoffset, detourcode, 5);
+ memcpy(ms->databuf + scnoffset, detourcode, 5);
}
size_t i;
assert(ms);
- assert(ms->data.d_buf);
+ assert(ms->databuf);
assert(origScnArr);
/* Parse symbols from their elfclass-specific format */
if (me->elfclass == ELFCLASS32) {
for (i = 1; (i + 1) * sizeof(Elf32_Sym) <= ms->shdr.sh_size; i++) {
- Elf32_Sym *cursym = ((Elf32_Sym*)ms->data.d_buf) + i;
+ Elf32_Sym *cursym = ((Elf32_Sym*)ms->databuf) + i;
ElfuSym *newsym = malloc(sizeof(*sym));
assert(newsym);
newsym->other = cursym->st_other;
newsym->shndx = cursym->st_shndx;
-
-
CIRCLEQ_INSERT_TAIL(&ms->symtab.syms, newsym, elem);
}
} else if (me->elfclass == ELFCLASS64) {
for (i = 1; (i + 1) * sizeof(Elf64_Sym) <= ms->shdr.sh_size; i++) {
- Elf64_Sym *cursym = ((Elf64_Sym*)ms->data.d_buf) + i;
+ Elf64_Sym *cursym = ((Elf64_Sym*)ms->databuf) + i;
ElfuSym *newsym = malloc(sizeof(*sym));
assert(newsym);
newsym->other = cursym->st_other;
newsym->shndx = cursym->st_shndx;
-
-
CIRCLEQ_INSERT_TAIL(&ms->symtab.syms, newsym, elem);
}
} else {
size_t i;
assert(ms);
- assert(ms->data.d_buf);
+ assert(ms->databuf);
for (i = 0; (i + 1) * sizeof(Elf32_Rel) <= ms->shdr.sh_size; i++) {
- Elf32_Rel *currel = &(((Elf32_Rel*)ms->data.d_buf)[i]);
+ Elf32_Rel *currel = &(((Elf32_Rel*)ms->databuf)[i]);
ElfuRel *rel;
rel = malloc(sizeof(*rel));
size_t i;
assert(ms);
- assert(ms->data.d_buf);
+ assert(ms->databuf);
for (i = 0; (i + 1) * sizeof(Elf64_Rela) <= ms->shdr.sh_size; i++) {
- Elf64_Rela *currel = &(((Elf64_Rela*)ms->data.d_buf)[i]);
+ Elf64_Rela *currel = &(((Elf64_Rela*)ms->databuf)[i]);
ElfuRel *rel;
rel = malloc(sizeof(*rel));
assert(scn);
- ms = malloc(sizeof(ElfuScn));
+ ms = elfu_mScnAlloc();
if (!ms) {
- ELFU_WARN("modelFromSection: malloc() failed for ElfuScn.\n");
goto ERROR;
}
-
+ /* Copy SHDR */
assert(gelf_getshdr(scn, &ms->shdr) == &ms->shdr);
-
/* Copy each data part in source segment */
- ms->data.d_align = 1;
- ms->data.d_buf = NULL;
- ms->data.d_off = 0;
- ms->data.d_type = ELF_T_BYTE;
- ms->data.d_size = ms->shdr.sh_size;
- ms->data.d_version = elf_version(EV_NONE);
- if (ms->shdr.sh_type != SHT_NOBITS
- && ms->shdr.sh_size > 0) {
+ if (SCNFILESIZE(&ms->shdr) > 0) {
Elf_Data *data;
- ms->data.d_buf = malloc(ms->shdr.sh_size);
- if (!ms->data.d_buf) {
+ ms->databuf = malloc(ms->shdr.sh_size);
+ if (!ms->databuf) {
ELFU_WARN("modelFromSection: malloc() failed for data buffer (%x bytes).\n", (unsigned)ms->shdr.sh_size);
goto ERROR;
}
data = elf_rawdata(scn, NULL);
assert(data);
- ms->data.d_align = data->d_align;
- ms->data.d_type = data->d_type;
- ms->data.d_version = data->d_version;
+ /* elf_rawdata() always returns ELF_T_BYTE */
+ assert(data->d_type == ELF_T_BYTE);
while (data) {
if (data->d_off + data->d_size > ms->shdr.sh_size) {
ELFU_WARN("modelFromSection: libelf delivered a bogus data blob. Skipping\n");
} else {
- memcpy((char*)ms->data.d_buf + data->d_off, data->d_buf, data->d_size);
+ memcpy((char*)ms->databuf + data->d_off, data->d_buf, data->d_size);
}
data = elf_rawdata(scn, data);
}
}
- ms->linkptr = NULL;
- ms->infoptr = NULL;
-
- ms->oldptr = NULL;
-
- CIRCLEQ_INIT(&ms->symtab.syms);
- CIRCLEQ_INIT(&ms->reltab.rels);
-
-
return ms;
ERROR:
if (ms->shdr.sh_offset == endOff) {
assert(ms->shdr.sh_type == SHT_NOBITS);
assert(ms->shdr.sh_size == nobitsize);
- ms->data.d_buf = malloc(ms->shdr.sh_size);
- memset(ms->data.d_buf, '\0', ms->shdr.sh_size);
- if (!ms->data.d_buf) {
+ ms->databuf = malloc(ms->shdr.sh_size);
+ memset(ms->databuf, '\0', ms->shdr.sh_size);
+ if (!ms->databuf) {
ELFU_WARN("mExpandNobits: Could not allocate %u bytes for NOBITS expansion. Data may be inconsistent.\n",
(unsigned)ms->shdr.sh_size);
assert(0);
goto ERROR;
}
- ms->data.d_align = 1;
- ms->data.d_off = 0;
- ms->data.d_type = ELF_T_BYTE;
- ms->data.d_size = ms->shdr.sh_size;
- ms->data.d_version = elf_version(EV_NONE);
-
ms->shdr.sh_type = SHT_PROGBITS;
ms->shdr.sh_addr = endAddr;
}
+++ /dev/null
-#include <assert.h>
-#include <libelfu/libelfu.h>
-
-
-size_t elfu_mPhdrCount(ElfuElf *me)
-{
- ElfuPhdr *mp;
- size_t i = 0;
-
- assert(me);
-
- CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
- i++;
- }
-
- return i;
-}
-
-
-
-void elfu_mPhdrUpdateChildOffsets(ElfuPhdr *mp)
-{
- ElfuScn *ms;
- ElfuPhdr *mpc;
-
- assert(mp);
- assert(mp->phdr.p_type == PT_LOAD);
-
- CIRCLEQ_FOREACH(mpc, &mp->childPhdrList, elemChildPhdr) {
- mpc->phdr.p_offset = mp->phdr.p_offset + (mpc->phdr.p_vaddr - mp->phdr.p_vaddr);
- }
-
- CIRCLEQ_FOREACH(ms, &mp->childScnList, elemChildScn) {
- ms->shdr.sh_offset = mp->phdr.p_offset + (ms->shdr.sh_addr - mp->phdr.p_vaddr);
- }
-}
assert(ms);
assert(ms->shdr.sh_type != SHT_NOBITS);
- assert(ms->data.d_buf);
+ assert(ms->databuf);
- newbuf = realloc(ms->data.d_buf, ms->shdr.sh_size + len);
+ newbuf = realloc(ms->databuf, ms->shdr.sh_size + len);
if (!newbuf) {
ELFU_WARN("appendData: malloc() failed for newbuf.\n");
return 1;
}
- ms->data.d_buf = newbuf;
+ ms->databuf = newbuf;
memcpy(newbuf + ms->shdr.sh_size, buf, len);
ms->shdr.sh_size += len;
- ms->data.d_size += len;
- assert(ms->shdr.sh_size == ms->data.d_size);
+ assert(ms->shdr.sh_size == ms->shdr.sh_size);
return 0;
}
if (newscn->shdr.sh_type == SHT_NOBITS) {
/* Expand this to SHT_PROGBITS, then insert as such. */
- assert(!newscn->data.d_buf);
+ assert(!newscn->databuf);
- newscn->data.d_buf = malloc(newscn->shdr.sh_size);
- if (!newscn->data.d_buf) {
+ newscn->databuf = malloc(newscn->shdr.sh_size);
+ if (!newscn->databuf) {
goto ERROR;
}
- newscn->data.d_size = newscn->shdr.sh_size;
newscn->shdr.sh_type = SHT_PROGBITS;
}
/* 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);
+ newbuf = realloc(me->symtab->linkptr->databuf, newsize);
if (!newbuf) {
ELFU_WARN("insertSymClone: realloc() failed for strtab.\n");
goto ERROR;
}
- me->symtab->linkptr->data.d_buf = newbuf;
+ me->symtab->linkptr->databuf = 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;
(unsigned)mstarget->shdr.sh_size);
CIRCLEQ_FOREACH(rel, &msrt->reltab.rels, elem) {
- Elf32_Word *dest32 = (Elf32_Word*)(((char*)(mstarget->data.d_buf)) + rel->offset);
- Elf64_Word *dest64 = (Elf64_Word*)(((char*)(mstarget->data.d_buf)) + rel->offset);
+ Elf32_Word *dest32 = (Elf32_Word*)(mstarget->databuf + rel->offset);
+ Elf64_Word *dest64 = (Elf64_Word*)(mstarget->databuf + rel->offset);
if (metarget->elfclass == ELFCLASS32) {
+++ /dev/null
-#include <assert.h>
-#include <stdlib.h>
-#include <libelfu/libelfu.h>
-
-
-/* Meta-functions */
-
-void* elfu_mScnForall(ElfuElf *me, SectionHandlerFunc f, void *aux1, void *aux2)
-{
- ElfuPhdr *mp;
- ElfuScn *ms;
-
- // TODO: Sort PHDRs by offset before interating
-
- CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
- if (mp->phdr.p_type != PT_LOAD) {
- continue;
- }
-
- CIRCLEQ_FOREACH(ms, &mp->childScnList, elemChildScn) {
- void *rv = f(me, ms, aux1, aux2);
-
- if (rv) {
- return rv;
- }
- }
- }
-
- CIRCLEQ_FOREACH(ms, &me->orphanScnList, elemChildScn) {
- void *rv = f(me, ms, aux1, aux2);
-
- if (rv) {
- return rv;
- }
- }
-
- return NULL;
-}
-
-
-
-
-/* Counting */
-
-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 ms;
- }
-
- *i += 1;
-
- /* Continue */
- return NULL;
-}
-
-
-size_t elfu_mScnCount(ElfuElf *me)
-{
- /* NULL section *is not* counted */
- size_t i = 0;
-
- assert(me);
-
- elfu_mScnForall(me, subCounter, &i, NULL);
-
- return i;
-}
-
-
-/* Returns the index a section would have in the flattened ELF */
-size_t elfu_mScnIndex(ElfuElf *me, ElfuScn *ms)
-{
- /* NULL section *is* counted */
- size_t i = 1;
-
- assert(me);
- assert(ms);
-
- elfu_mScnForall(me, subCounter, &i, ms);
-
- /* If this assertion is broken then ms is not a section in me. */
- assert(i <= elfu_mScnCount(me));
- return i;
-}
-
-
-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 */
-
-char* elfu_mScnName(ElfuElf *me, ElfuScn *ms)
-{
- assert(me);
- assert(ms);
-
- if (!me->shstrtab) {
- return NULL;
- }
-
- if (!me->shstrtab->data.d_buf) {
- return NULL;
- }
-
- return &((char*)me->shstrtab->data.d_buf)[ms->shdr.sh_name];
-}
-
-
-static void* subScnsToArray(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
-{
- ElfuScn **arr = (ElfuScn**)aux1;
- size_t *i = (size_t*)aux2;
-
- arr[(*i)] = ms;
- *i += 1;
-
- /* Continue */
- return NULL;
-}
-
-static int cmpScnOffs(const void *ms1, const void *ms2)
-{
- ElfuScn *s1;
- ElfuScn *s2;
-
- assert(ms1);
- assert(ms2);
-
- s1 = *(ElfuScn**)ms1;
- s2 = *(ElfuScn**)ms2;
-
- assert(s1);
- assert(s2);
-
-
- if (s1->shdr.sh_offset < s2->shdr.sh_offset) {
- return -1;
- } else if (s1->shdr.sh_offset == s2->shdr.sh_offset) {
- return 0;
- } else /* if (s1->shdr.sh_offset > s2->shdr.sh_offset) */ {
- return 1;
- }
-}
-
-ElfuScn** elfu_mScnSortedByOffset(ElfuElf *me, size_t *count)
-{
- size_t numSecs;
- ElfuScn **sortedSecs;
- size_t i;
-
- assert(me);
-
- /* Sort sections by offset in file */
- numSecs = elfu_mScnCount(me);
- sortedSecs = malloc(numSecs * sizeof(*sortedSecs));
- if (!sortedSecs) {
- ELFU_WARN("elfu_mScnSortedByOffset: Failed to allocate memory.\n");
- return NULL;
- }
-
- i = 0;
- elfu_mScnForall(me, subScnsToArray, sortedSecs, &i);
- assert(i == numSecs);
-
- qsort(sortedSecs, numSecs, sizeof(*sortedSecs), cmpScnOffs);
-
- *count = numSecs;
-
- return sortedSecs;
-}
+++ /dev/null
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include <libelfu/libelfu.h>
-
-
-static void* subFindByName(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
-{
- char *name = (char*)aux1;
- (void)aux2;
-
- if (elfu_mScnName(me, ms)) {
- if (!strcmp(elfu_mScnName(me, ms), name)) {
- return ms;
- }
- }
-
- /* Continue */
- return NULL;
-}
-
-/* Hazard a guess where a function may be found in the PLT */
-static GElf_Word pltLookupVal(ElfuElf *me, char *name)
-{
- ElfuScn *relplt;
- ElfuScn *plt;
- ElfuRel *rel;
- GElf_Word j;
-
- relplt = elfu_mScnForall(me, subFindByName, ".rel.plt", NULL);
- if (!relplt) {
- ELFU_WARN("dynsymLookupVal: Could not find .rel.plt section in destination ELF.\n");
- return 0;
- }
-
- plt = elfu_mScnForall(me, subFindByName, ".plt", NULL);
- if (!plt) {
- ELFU_WARN("dynsymLookupVal: Could not find .plt section in destination ELF.\n");
- return 0;
- }
-
-
- /* 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 ((me->elfclass == ELFCLASS32 && rel->type != R_386_JMP_SLOT)
- || (me->elfclass == ELFCLASS64 && rel->type != R_X86_64_JUMP_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);
- }
-
- 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
- * the number of bytes the machine code in a PLT entry take. */
- GElf_Addr addr = plt->shdr.sh_addr + (16 * j);
- ELFU_DEBUG("dynsymLookupVal: Guessing symbol '%s' is in destination memory at %x (PLT entry #%u).\n", name, (unsigned)addr, j);
- return addr;
- }
- }
-
- ELFU_WARN("dynsymLookupVal: Could not find symbol '%s' in destination ELF.\n", name);
-
- return 0;
-}
-
-
-
-/* Look up a value in the symbol table section *msst which is in *me.
- * If it is not found there, see if we can find it in *me's PLT. */
-GElf_Word elfu_mSymtabLookupVal(ElfuElf *me, ElfuScn *msst, GElf_Word entry)
-{
- GElf_Word i;
- ElfuSym *sym;
- char *symname;
-
- assert(me);
- assert(msst);
- 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);
- }
- symname = ELFU_SYMSTR(msst, sym->name);
-
- switch (sym->type) {
- case STT_NOTYPE:
- case STT_OBJECT:
- case STT_FUNC:
- if (sym->scnptr) {
- ElfuScn *newscn = elfu_mScnByOldscn(me, sym->scnptr);
- assert(newscn);
- return newscn->shdr.sh_addr + sym->value;
- } else if (sym->shndx == SHN_UNDEF) {
- /* 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(me, symname);
- } else if (sym->shndx == SHN_ABS) {
- return sym->value;
- } else {
- ELFU_WARN("symtabLookupVal: Symbol binding COMMON is not supported, using 0.\n");
- return 0;
- }
- break;
- case STT_SECTION:
- assert(sym->scnptr);
- assert(elfu_mScnByOldscn(me, sym->scnptr));
- return elfu_mScnByOldscn(me, sym->scnptr)->shdr.sh_addr;
- case STT_FILE:
- 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, symname);
- return 0;
- }
-}
-
-
-/* Look up a value in the symbol table section *msst which is in *me. */
-GElf_Word elfu_mSymtabLookupAddrByName(ElfuElf *me, ElfuScn *msst, char *name)
-{
- ElfuSym *sym;
-
- assert(me);
- assert(msst);
- assert(name);
- assert(strlen(name) > 0);
- assert(!CIRCLEQ_EMPTY(&msst->symtab.syms));
-
- CIRCLEQ_FOREACH(sym, &msst->symtab.syms, elem) {
- char *symname = ELFU_SYMSTR(msst, sym->name);
-
- if (!strcmp(symname, name)) {
- goto SYMBOL_FOUND;
- }
- }
- return 0;
-
-
- SYMBOL_FOUND:
-
- switch (sym->type) {
- case STT_NOTYPE:
- case STT_OBJECT:
- case STT_FUNC:
- if (sym->scnptr) {
- GElf_Addr a = sym->value;
- a += me->ehdr.e_type == ET_REL ? sym->scnptr->shdr.sh_addr : 0;
- return a;
- } else if (sym->shndx == SHN_UNDEF) {
- return 0;
- } else if (sym->shndx == SHN_ABS) {
- return sym->value;
- } else {
- ELFU_WARN("elfu_mSymtabLookupAddrByName: Symbol binding COMMON is not supported, using 0.\n");
- return 0;
- }
- break;
- default:
- return 0;
- }
-}
-
-
-
-/* Convert symtab from memory model to elfclass specific format */
-void elfu_mSymtabFlatten(ElfuElf *me)
-{
- ElfuSym *sym;
- size_t numsyms = 0;
-
- 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);
- }
-
- numsyms++;
- }
-
- /* Copy symbols to elfclass-specific format */
- if (me->elfclass == ELFCLASS32) {
- size_t newsize = (numsyms + 1) * sizeof(Elf32_Sym);
- size_t i;
-
- if (me->symtab->data.d_buf) {
- free(me->symtab->data.d_buf);
- }
- me->symtab->data.d_buf = malloc(newsize);
- assert(me->symtab->data.d_buf);
-
- me->symtab->data.d_size = newsize;
- me->symtab->shdr.sh_size = newsize;
- memset(me->symtab->data.d_buf, 0, newsize);
-
- i = 1;
- CIRCLEQ_FOREACH(sym, &me->symtab->symtab.syms, elem) {
- Elf32_Sym *es = ((Elf32_Sym*)me->symtab->data.d_buf) + i;
-
- es->st_name = sym->name;
- es->st_value = sym->value;
- es->st_size = sym->size;
- es->st_info = ELF32_ST_INFO(sym->bind, sym->type);
- es->st_other = sym->other;
- es->st_shndx = sym->shndx;
-
- i++;
- }
- } else if (me->elfclass == ELFCLASS64) {
- size_t newsize = (numsyms + 1) * sizeof(Elf64_Sym);
- size_t i;
-
- if (me->symtab->data.d_buf) {
- free(me->symtab->data.d_buf);
- }
- me->symtab->data.d_buf = malloc(newsize);
- assert(me->symtab->data.d_buf);
-
- me->symtab->data.d_size = newsize;
- me->symtab->shdr.sh_size = newsize;
- memset(me->symtab->data.d_buf, 0, newsize);
-
- i = 1;
- CIRCLEQ_FOREACH(sym, &me->symtab->symtab.syms, elem) {
- Elf64_Sym *es = ((Elf64_Sym*)me->symtab->data.d_buf) + i;
-
- es->st_name = sym->name;
- es->st_value = sym->value;
- es->st_size = sym->size;
- es->st_info = ELF64_ST_INFO(sym->bind, sym->type);
- es->st_other = sym->other;
- es->st_shndx = sym->shndx;
-
- i++;
- }
- } else {
- /* Unknown elfclass */
- assert(0);
- }
-
- elfu_mLayoutAuto(me);
-}
/* Data */
- if (ms->data.d_buf) {
+ if (ms->databuf) {
Elf_Data *dataOut = elf_newdata(scnOut);
if (!dataOut) {
ELFU_WARNELF("elf_newdata");
}
- dataOut->d_align = ms->data.d_align;
- dataOut->d_buf = ms->data.d_buf;
- dataOut->d_off = ms->data.d_off;
- dataOut->d_type = ms->data.d_type;
- dataOut->d_size = ms->data.d_size;
- dataOut->d_version = ms->data.d_version;
+ dataOut->d_align = 1;
+ dataOut->d_buf = ms->databuf;
+ dataOut->d_off = 0;
+ dataOut->d_type = ELF_T_BYTE;
+ dataOut->d_size = ms->shdr.sh_size;
+ dataOut->d_version = elf_version(EV_NONE);
}
return NULL;