Lookup dynamically linked global variables.
authornorly <ny-git@enpas.org>
Thu, 27 Jun 2013 00:00:17 +0000 (01:00 +0100)
committernorly <ny-git@enpas.org>
Thu, 27 Jun 2013 00:02:36 +0000 (01:02 +0100)
This works ONLY in position-dependent executables.

Processing position-independent code includes generating and inserting
code that finds out the current instruction address. That's beyond the
scope of editing normal executables, which are usually
position-dependent unless requested otherwise.

include/libelfu/modelops.h
src/libelfu/modelops/dynlookup.c
src/libelfu/modelops/relocate.c

index 3ebf0a3344188f0bfa71347648195bac0de91c84..e9ea9eebfa043487f911baad2d0fab99504e0830 100644 (file)
@@ -54,6 +54,7 @@ int elfu_mLayoutAuto(ElfuElf *me);
 
 
 int elfu_mDynLookupPltAddrByName(ElfuElf *me, char *name, GElf_Addr *result);
+int elfu_mDynLookupReldynAddrByName(ElfuElf *me, char *name, GElf_Addr *result);
 
 
 int elfu_mRelocate(ElfuElf *metarget, ElfuScn *mstarget, ElfuScn *msrt);
index a2cd3ae7a84eaedbe3aa7f79184bb1d3cee8ae59..e20adfea0446714c2a8b67253df421cd1bed10b7 100644 (file)
@@ -91,3 +91,60 @@ int elfu_mDynLookupPltAddrByName(ElfuElf *me, char *name, GElf_Addr *result)
 
   return -1;
 }
+
+
+
+/* Hazard a guess where a global variable may be found in .bss,
+ * based on dynamic linking information in .rel.dyn */
+int elfu_mDynLookupReldynAddrByName(ElfuElf *me, char *name, GElf_Addr *result)
+{
+  ElfuScn *reldyn;
+  ElfuRel *rel;
+  GElf_Word j;
+
+  reldyn = elfu_mScnForall(me, subFindByName, ".rel.dyn", NULL);
+  if (!reldyn) {
+    /* x86-64 uses .rela.dyn instead */
+    reldyn = elfu_mScnForall(me, subFindByName, ".rela.dyn", NULL);
+  }
+  if (!reldyn) {
+    ELFU_WARN("elfu_mDynLookupReldynAddrByName: Could not find .rel.dyn section in destination ELF.\n");
+    return -1;
+  }
+
+
+  assert(reldyn->linkptr);
+  j = 0;
+  CIRCLEQ_FOREACH(rel, &reldyn->reltab.rels, elem) {
+    ElfuSym *sym;
+    char *symname;
+
+    j++;
+
+    /* We only consider COPY relocations for global variables here.
+     * Technically, these relocations write the variables' contents
+     * to .bss. */
+    if ((me->elfclass == ELFCLASS32 && rel->type != R_386_COPY)
+        || (me->elfclass == ELFCLASS64 && rel->type != R_X86_64_COPY)) {
+      continue;
+    }
+
+    /* Get the (rel->sym)-th symbol from the symbol table that
+     * .rel.dyn points to. */
+    sym = elfu_mSymtabIndexToSym(reldyn->linkptr, rel->sym);
+    assert(sym);
+
+    symname = elfu_mSymtabSymToName(reldyn->linkptr, sym);
+    if (!strcmp(symname, name)) {
+      GElf_Addr addr = rel->offset;
+      ELFU_DEBUG("elfu_mDynLookupReldynAddrByName: Guessing symbol '%s' is in destination memory at %x (PLT entry #%u).\n", name, (unsigned)addr, j);
+      *result = addr;
+      return 0;
+    }
+  }
+
+  ELFU_WARN("elfu_mDynLookupReldynAddrByName: Could not find or use symbol '%s' in destination ELF.\n", name);
+  ELFU_WARN("      NOTE: Only R_*_COPY relocations are resolved to global variables.\n");
+
+  return -1;
+}
index 7f78524acf962b9af6ce1736376fde770bdbe7dd..94598e607a85e1e7db3b795e0851a76c4338ea32 100644 (file)
@@ -36,8 +36,11 @@ int elfu_mRelocate(ElfuElf *metarget, ElfuScn *mstarget, ElfuScn *msrt)
         haveSymval = !elfu_mDynLookupPltAddrByName(metarget,
                                      elfu_mSymtabSymToName(msrt->linkptr, sym),
                                      &s);
-      } else if (sym->shndx == SHN_COMMON) {
-        // TODO: Lookup in .rel.dyn
+        if (!haveSymval) {
+          haveSymval = !elfu_mDynLookupReldynAddrByName(metarget,
+                                       elfu_mSymtabSymToName(msrt->linkptr, sym),
+                                       &s);
+        }
       }
     }