Guess where unknown functions are in .rel.plt
authornorly <ny-git@enpas.org>
Sun, 2 Jun 2013 03:05:30 +0000 (04:05 +0100)
committernorly <ny-git@enpas.org>
Mon, 3 Jun 2013 01:08:46 +0000 (02:08 +0100)
include/libelfu/types.h
src/model/fromFile.c
src/model/layout.c
src/model/reladd.c
src/model/relocate.c

index 2a0fcf37293919a1fb3ef32f61829b5a7a5e3a97..b216e53a7ee03364dfa312d83cea2cfb7ef8fe16 100644 (file)
@@ -61,6 +61,7 @@ typedef struct ElfuSym {
   unsigned char other;
 
   ElfuScn *scnptr;
+  int shndx;
 
   CIRCLEQ_ENTRY(ElfuSym) elem;
 } ElfuSym;
index 84ec14325b610e7b9c68606b43d2c05169b2de52..23105e60a76f541a4dc251bca53c0dfa4f0a69b1 100644 (file)
@@ -52,12 +52,14 @@ static ElfuSymtab* symtabFromScn32(ElfuScn *ms, ElfuScn**origScnArr)
       case SHN_ABS:
       case SHN_COMMON:
         sym->scnptr = NULL;
+        sym->shndx = cursym->st_shndx;
         break;
       default:
         sym->scnptr = origScnArr[cursym->st_shndx - 1];
         break;
     }
 
+
     CIRCLEQ_INSERT_TAIL(&st->syms, sym, elem);
   }
 
@@ -404,6 +406,7 @@ ElfuElf* elfu_mFromElf(Elf *e)
 
       switch (ms->shdr.sh_type) {
         case SHT_SYMTAB:
+        case SHT_DYNSYM:
           if (me->elfclass == ELFCLASS32) {
             ms->symtab = symtabFromScn32(ms, secArray);
           } else if (me->elfclass == ELFCLASS64) {
index d5d49d874962ced66f5b7e5ded553f104df51d03..e4b3fb13aab028d93b4e24fecbc66a93fc17a3f7 100644 (file)
@@ -82,6 +82,12 @@ GElf_Addr elfu_mLayoutGetSpaceInPhdr(ElfuElf *me, GElf_Word size,
 
   assert(!(w && x));
 
+  /* Treat read-only data as executable.
+   * That's what the GNU toolchain does on x86. */
+  if (!w && !x) {
+    x = 1;
+  }
+
   /* Find first and last LOAD PHDRs.
    * Don't compare p_memsz - segments don't overlap in memory. */
   CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
index a3ccc99d5689ec4b20786a0cfa195ed626d8a249..80f106fd7dab9ae352e425eff89ba9f2737a53c9 100644 (file)
@@ -111,10 +111,10 @@ static ElfuScn* insertSection(ElfuElf *me, ElfuElf *mrel, ElfuScn *oldscn)
 
     return newscn;
   } else {
-      ELFU_WARN("insertSection: Skipping section %s with flags %jd (type %d).\n",
+      ELFU_WARN("insertSection: Skipping non-memory section %s (type %d flags %jd).\n",
                 elfu_mScnName(mrel, oldscn),
-                oldscn->shdr.sh_flags,
-                oldscn->shdr.sh_type);
+                oldscn->shdr.sh_type,
+                oldscn->shdr.sh_flags);
       goto ERROR;
   }
 
index 1b4f9ffdb4f710fa0e5675e4362d8ecb644f5e2e..972bda32bbff6af9809671a2822fe5e4dce1de1f 100644 (file)
@@ -1,8 +1,86 @@
 #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 *metarget, char *name)
+{
+  ElfuScn *relplt;
+  ElfuScn *plt;
+  ElfuRel *rel;
+  GElf_Word j;
+
+  relplt = elfu_mScnForall(metarget, subFindByName, ".rel.plt", NULL);
+  if (!relplt) {
+    ELFU_WARN("dynsymLookupVal: Could not find .rel.plt section in destination ELF.\n");
+    return 0;
+  }
+
+  plt = elfu_mScnForall(metarget, subFindByName, ".plt", NULL);
+  if (!plt) {
+    ELFU_WARN("dynsymLookupVal: Could not find .plt section in destination ELF.\n");
+    return 0;
+  }
+
+
+  /* Look up name */
+  assert(relplt->reltab);
+  assert(relplt->linkptr);
+  assert(relplt->linkptr->symtab);
+  j = 0;
+  CIRCLEQ_FOREACH(rel, &relplt->reltab->rels, elem) {
+    GElf_Word i;
+    ElfuSym *sym;
+
+    j++;
+
+    if (rel->type != R_386_JMP_SLOT) {
+      continue;
+    }
+
+    sym = CIRCLEQ_FIRST(&relplt->linkptr->symtab->syms);
+    for (i = 1; i < rel->sym; i++) {
+      sym = CIRCLEQ_NEXT(sym, elem);
+    }
+
+    if (!sym->name) {
+      continue;
+    }
+
+    if (!strcmp(sym->name, 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 %jx (PLT entry #%d).\n", name, addr, j);
+      return addr;
+    }
+  }
+
+  ELFU_WARN("dynsymLookupVal: Could not find symbol '%s' in destination ELF.\n", name);
+
+  return 0;
+}
+
+
 static GElf_Word symtabLookupVal(ElfuElf *metarget, ElfuScn *msst, GElf_Word entry)
 {
   GElf_Word i;
@@ -26,9 +104,16 @@ static GElf_Word symtabLookupVal(ElfuElf *metarget, ElfuScn *msst, GElf_Word ent
       if (sym->scnptr) {
         assert(elfu_mScnByOldscn(metarget, sym->scnptr));
         return elfu_mScnByOldscn(metarget, sym->scnptr)->shdr.sh_addr + sym->value;
+      } else if (sym->shndx == SHN_UNDEF) {
+        /* Look the symbol up in .dyn.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(metarget, sym->name);
+      } else if (sym->shndx == SHN_ABS) {
+        return sym->value;
       } else {
-        // TODO: UNDEF, ABS, or COMMON
-        ELFU_WARN("symtabLookupVal: Returning 0 for UNDEF, ABS, or COMMON symbol.\n");
+        ELFU_WARN("symtabLookupVal: Symbol binding COMMON is not supported, using 0.\n");
+        return 0;
       }
       break;
     case STT_SECTION:
@@ -36,11 +121,10 @@ static GElf_Word symtabLookupVal(ElfuElf *metarget, ElfuScn *msst, GElf_Word ent
       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;
+      ELFU_WARN("symtabLookupVal: Symbol type FILE is not supported, using 0.\n");
+      return 0;
     default:
-      ELFU_WARN("symtabLookupVal: Unknown symbol type %d.\n", sym->type);
+      ELFU_WARN("symtabLookupVal: Unknown symbol type %d for %s.\n", sym->type, sym->name);
       return 0;
   }
 }