Basic 32-bit SYMTAB and REL (not RELA) support
authornorly <ny-git@enpas.org>
Sat, 1 Jun 2013 16:42:36 +0000 (17:42 +0100)
committernorly <ny-git@enpas.org>
Mon, 3 Jun 2013 01:08:46 +0000 (02:08 +0100)
include/libelfu/debug.h
include/libelfu/modelops.h
include/libelfu/types.h
src/elfops/check.c
src/model/clone.c
src/model/dump.c
src/model/fromFile.c
src/model/reladd.c
src/model/relocate.c [new file with mode: 0644]
src/model/section.c
src/model/toFile.c

index 6b817b3ca07b53db2450519aaa0e0e275a1182be..b9f9161f7ac30f9f813e6c21d10b2012e1f4e1dd 100644 (file)
@@ -4,6 +4,8 @@
 #include <stdio.h>
 
 
+#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)
index b56f13314cddd1b2d678ab6133a1fac3d9166593..3daef5285fa8162c3ce0b9b82e4d3afc0f3e68c7 100644 (file)
@@ -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);
index 177bbafbb4e58f1cd43b7527378d6dca6c9749a6..2a0fcf37293919a1fb3ef32f61829b5a7a5e3a97 100644 (file)
@@ -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
index 2c7f040910dee5e28421e0a389867687ed867a86..6e56bae96b92008b2fe2f9cd383f8733f2abb327 100644 (file)
@@ -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;
index 644647cc7aa6bfecd67b2ed46ee64f6f5580f795..ca4b38fa1aa21198b8bf2ff0b82795401fd0a5ac 100644 (file)
@@ -34,5 +34,8 @@ ElfuScn* elfu_mCloneScn(ElfuScn *ms)
 
   newscn->oldptr = ms;
 
+  ms->symtab = NULL;
+  ms->reltab = NULL;
+
   return newscn;
 }
index 5f0642a8fc53717a98161a12f0286d809973011a..27556f9ebc80d57bf0e1dc36e83617d969e6e5a6 100644 (file)
@@ -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;
 }
 
 
index 11a7fb5c4646ae47262d4e0184cce93d9a05a2bb..84ec14325b610e7b9c68606b43d2c05169b2de52 100644 (file)
@@ -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);
 
index 665f20a97f3efcd2e21dc9af688cf3a5c14153e8..a3ccc99d5689ec4b20786a0cfa195ed626d8a249 100644 (file)
@@ -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 (file)
index 0000000..1b4f9ff
--- /dev/null
@@ -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;
+  }
+}
index 4b8b230baf2294b1d0a4ee76d413af8fb66c5c8f..a96377ca21f00d1b4d8b8d26c6be244c3a8da492 100644 (file)
@@ -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)
index eaf6ce50c5f649a6b557407270997c86b079c228..da06f4a07af8c2608c2ef637ddf3f7e5ef5c5414 100644 (file)
@@ -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;
 }