]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Resuscitate a linker that knows how to do relocations, so we can
authorJulian Seward <jseward@acm.org>
Sat, 12 Feb 2005 18:59:31 +0000 (18:59 +0000)
committerJulian Seward <jseward@acm.org>
Sat, 12 Feb 2005 18:59:31 +0000 (18:59 +0000)
actually run real programs.

git-svn-id: svn://svn.valgrind.org/vex/trunk@892

VEX/switchback/Makefile
VEX/switchback/linker.c [new file with mode: 0644]
VEX/switchback/linker.h [new file with mode: 0644]
VEX/switchback/switchback.c

index 545dcde05bdeeb95d2a6377d6350557713b863d0..b8072b59508c5af4df1c27c38a31d1f832cf8a7f 100644 (file)
@@ -1,6 +1,6 @@
 
-all: switchback.c
-       gcc -Wall -O -g -o switchback switchback.c ../libvex.a
+all: switchback.c linker.c linker.h
+       gcc -Wall -O -g -o switchback switchback.c linker.c ../libvex.a
 
 clean:
-       rm -f switchback switchback.o
+       rm -f switchback switchback.o linker.o
diff --git a/VEX/switchback/linker.c b/VEX/switchback/linker.c
new file mode 100644 (file)
index 0000000..7bf4468
--- /dev/null
@@ -0,0 +1,1313 @@
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <elf.h>
+#include <fcntl.h>
+#include <string.h>
+#include <malloc.h>
+
+#include "linker.h"
+
+#define IF_DEBUG(x,y) /* */
+static int debug_linker = 0;
+
+#define i386_TARGET_ARCH
+// #define arm_TARGET_ARCH
+
+#if !defined(i386_TARGET_ARCH) && !defined(arm_TARGET_ARCH)
+#  error "Must #define i386_TARGET_ARCH or arm_TARGET_ARCH"
+#endif
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+//
+// TYPES
+
+#define FALSE 0
+#define TRUE  1
+
+typedef enum { OBJECT_LOADED, OBJECT_RESOLVED } OStatus;
+
+
+#define N_FIXUP_PAGES 1
+
+
+/* Indication of section kinds for loaded objects.  Needed by
+   the GC for deciding whether or not a pointer on the stack
+   is a code pointer.
+*/
+typedef 
+   enum { SECTIONKIND_CODE_OR_RODATA,
+          SECTIONKIND_RWDATA,
+          SECTIONKIND_OTHER,
+          SECTIONKIND_NOINFOAVAIL } 
+   SectionKind;
+
+typedef 
+   struct _Section { 
+      void* start; 
+      void* end; 
+      SectionKind kind;
+      struct _Section* next;
+   } 
+   Section;
+
+typedef 
+   struct _ProddableBlock {
+      void* start;
+      int   size;
+      struct _ProddableBlock* next;
+   }
+   ProddableBlock;
+
+/* Top-level structure for an object module.  One of these is allocated
+ * for each object file in use.
+ */
+typedef struct _ObjectCode {
+    OStatus    status;
+    char*      fileName;
+    int        fileSize;
+    char*      formatName;            /* eg "ELF32", "DLL", "COFF", etc. */
+
+    /* An array containing ptrs to all the symbol names copied from
+       this object into the global symbol hash table.  This is so that
+       we know which parts of the latter mapping to nuke when this
+       object is removed from the system. */
+    char**     symbols;
+    int        n_symbols;
+
+    /* ptr to malloc'd lump of memory holding the obj file */
+    void*      image;
+
+    /* Fixup area for long-distance jumps. */
+    char*      fixup;
+    int        fixup_used;
+    int        fixup_size;
+
+    /* The section-kind entries for this object module.  Linked
+       list. */
+    Section* sections;
+
+    /* A private hash table for local symbols. */
+    /* HashTable* */ void* lochash;
+    
+    /* Allow a chain of these things */
+    struct _ObjectCode * next;
+
+    /* SANITY CHECK ONLY: a list of the only memory regions which may
+       safely be prodded during relocation.  Any attempt to prod
+       outside one of these is an error in the linker. */
+    ProddableBlock* proddables;
+
+} ObjectCode;
+
+/*
+ * Define a set of types which can be used for both ELF32 and ELF64
+ */
+
+#ifdef ELF_64BIT
+#define ELFCLASS    ELFCLASS64
+#define Elf_Addr    Elf64_Addr
+#define Elf_Word    Elf64_Word
+#define Elf_Sword   Elf64_Sword
+#define Elf_Ehdr    Elf64_Ehdr
+#define Elf_Phdr    Elf64_Phdr
+#define Elf_Shdr    Elf64_Shdr
+#define Elf_Sym     Elf64_Sym
+#define Elf_Rel     Elf64_Rel
+#define Elf_Rela    Elf64_Rela
+#define ELF_ST_TYPE ELF64_ST_TYPE
+#define ELF_ST_BIND ELF64_ST_BIND
+#define ELF_R_TYPE  ELF64_R_TYPE
+#define ELF_R_SYM   ELF64_R_SYM
+#else
+#define ELFCLASS    ELFCLASS32
+#define Elf_Addr    Elf32_Addr
+#define Elf_Word    Elf32_Word
+#define Elf_Sword   Elf32_Sword
+#define Elf_Ehdr    Elf32_Ehdr
+#define Elf_Phdr    Elf32_Phdr
+#define Elf_Shdr    Elf32_Shdr
+#define Elf_Sym     Elf32_Sym
+#define Elf_Rel     Elf32_Rel
+#define Elf_Rela    Elf32_Rela
+#ifndef ELF_ST_TYPE
+#define ELF_ST_TYPE ELF32_ST_TYPE
+#endif
+#ifndef ELF_ST_BIND
+#define ELF_ST_BIND ELF32_ST_BIND
+#endif
+#ifndef ELF_R_TYPE
+#define ELF_R_TYPE  ELF32_R_TYPE
+#endif
+#ifndef ELF_R_SYM
+#define ELF_R_SYM   ELF32_R_SYM
+#endif
+#endif
+
+
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+//
+// PARANOIA
+
+/* -----------------------------------------------------------------------
+ * Sanity checking.  For each ObjectCode, maintain a list of address ranges
+ * which may be prodded during relocation, and abort if we try and write
+ * outside any of these.
+ */
+static void addProddableBlock ( ObjectCode* oc, void* start, int size )
+{
+   ProddableBlock* pb
+      = malloc(sizeof(ProddableBlock));
+   if (debug_linker)
+      fprintf(stderr, "aPB oc=%p %p %d   (%p .. %p)\n", oc, start, size,
+             start, ((char*)start)+size-1 );
+   assert(size > 0);
+   pb->start      = start;
+   pb->size       = size;
+   pb->next       = oc->proddables;
+   oc->proddables = pb;
+}
+
+static void checkProddableBlock ( ObjectCode* oc, void* addr )
+{
+   ProddableBlock* pb;
+   for (pb = oc->proddables; pb != NULL; pb = pb->next) {
+      char* s = (char*)(pb->start);
+      char* e = s + pb->size - 1;
+      char* a = (char*)addr;
+      /* Assumes that the biggest fixup involves a 4-byte write.  This
+         probably needs to be changed to 8 (ie, +7) on 64-bit
+         plats. */
+      if (a >= s && (a+3) <= e) return;
+   }
+   fprintf(stderr,
+           "checkProddableBlock: invalid fixup %p in runtime linker\n",
+           addr);
+   exit(1);
+}
+
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+//
+// String->Addr mappings
+
+typedef 
+   struct { char* mp_name; void* mp_addr; } 
+   Maplet;
+
+typedef
+   struct {
+      int sm_size;
+      int sm_used;
+      Maplet* maplets;
+   }
+   StringMap;
+
+static StringMap* new_StringMap ( void )
+{
+   StringMap* sm = malloc(sizeof(StringMap));
+   sm->sm_size = 10;
+   sm->sm_used = 0;
+   sm->maplets = malloc(10 * sizeof(Maplet));
+   return sm;
+}
+
+static void delete_StringMap ( StringMap* sm )
+{
+   assert(sm->maplets != NULL);
+   free(sm->maplets);
+   sm->maplets = NULL;
+   free(sm);
+}
+
+static void ensure_StringMap ( StringMap* sm )
+{
+   int i;
+   Maplet* mp2;
+   assert(sm->maplets != NULL);
+   if (sm->sm_used < sm->sm_size)
+     return;
+   sm->sm_size *= 2;
+   mp2 = malloc(sm->sm_size * sizeof(Maplet));
+   for (i = 0; i < sm->sm_used; i++)
+      mp2[i] = sm->maplets[i];
+   free(sm->maplets);
+   sm->maplets = mp2;
+}
+
+static void* search_StringMap ( StringMap* sm, char* name )
+{
+   int i;
+   for (i = 0; i < sm->sm_used; i++)
+      if (0 == strcmp(name, sm->maplets[i].mp_name))
+         return sm->maplets[i].mp_addr;
+   return NULL;
+}
+
+static void addto_StringMap ( StringMap* sm, char* name, void* addr )
+{
+   ensure_StringMap(sm);
+   sm->maplets[sm->sm_used].mp_name = name;
+   sm->maplets[sm->sm_used].mp_addr = addr;
+   sm->sm_used++;
+}
+
+static void paranoid_addto_StringMap ( StringMap* sm, char* name, void* addr )
+{
+   if (search_StringMap(sm,name) != NULL) {
+      fprintf(stderr, "paranoid_addto_StringMap(%s,%p)\n", name, addr);
+      exit(1);
+   }
+   addto_StringMap(sm,name,addr);
+}
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+//
+// Top-level linker control.
+
+StringMap*  global_symbol_table = NULL;
+ObjectCode* global_object_list = NULL;
+
+static void initLinker ( void )
+{
+   if (global_symbol_table != NULL)
+      return;
+   global_symbol_table = new_StringMap();
+}
+
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+//
+// SYMBOL TABLE(s)
+
+/* -----------------------------------------------------------------
+ * lookup a symbol in the global symbol table
+ */
+static 
+void * lookupSymbol( char *lbl )
+{
+   void *val;
+   initLinker() ;
+   assert(global_symbol_table != NULL);
+   val = search_StringMap(global_symbol_table, lbl);
+   return val;
+}
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+//
+// HELPERS
+
+/*
+ * Generic ELF functions
+ */
+
+static char *
+findElfSection ( void* objImage, Elf_Word sh_type )
+{
+   char* ehdrC = (char*)objImage;
+   Elf_Ehdr* ehdr = (Elf_Ehdr*)ehdrC;
+   Elf_Shdr* shdr = (Elf_Shdr*)(ehdrC + ehdr->e_shoff);
+   char* sh_strtab = ehdrC + shdr[ehdr->e_shstrndx].sh_offset;
+   char* ptr = NULL;
+   int i;
+
+   for (i = 0; i < ehdr->e_shnum; i++) {
+      if (shdr[i].sh_type == sh_type
+          /* Ignore the section header's string table. */
+          && i != ehdr->e_shstrndx
+         /* Ignore string tables named .stabstr, as they contain
+             debugging info. */
+          && 0 != memcmp(".stabstr", sh_strtab + shdr[i].sh_name, 8)
+         ) {
+         ptr = ehdrC + shdr[i].sh_offset;
+         break;
+      }
+   }
+   return ptr;
+}
+
+#ifdef arm_TARGET_ARCH
+static
+char* alloc_fixup_bytes ( ObjectCode* oc, int nbytes )
+{
+   char* res;
+   assert(nbytes % 4 == 0);
+   assert(nbytes > 0);
+   res = &(oc->fixup[oc->fixup_used]);
+   oc->fixup_used += nbytes;
+   if (oc->fixup_used >= oc->fixup_size) {
+     fprintf(stderr, "fixup area too small for %s\n", oc->fileName);
+     exit(1);
+   }
+   return res;
+}
+#endif
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+//
+// RESOLVE
+
+static
+void* lookup_magic_hacks ( char* sym )
+{
+   if (0==strcmp(sym, "printf")) return (void*)(&printf);
+   return NULL;
+}
+
+#ifdef arm_TARGET_ARCH
+static
+void arm_notify_new_code ( char* start, int length )
+{
+  __asm __volatile ("mov r1, %0\n\t"
+                    "mov r2, %1\n\t"
+                    "mov r3, %2\n\t"
+                    "swi 0x9f0002\n\t"
+                    : 
+                    : "ir" (start), "ir" (length), "ir" (0) );
+}
+
+
+static
+void gen_armle_goto ( char* fixup, char* dstP )
+{
+  Elf_Word w = (Elf_Word)dstP;
+  /* 
+   2                    .text
+   3 0000 04F01FE5              ldr     pc, value
+   4 0004 44332211      value:  .word   0x11223344
+   */
+  fprintf(stderr,"at %p generating jump to %p\n", fixup, dstP );
+  fixup[0] = 0x04; fixup[1] = 0xF0; fixup[2] = 0x1F; fixup[3] = 0xE5;
+  fixup[4] = w & 0xFF; w >>= 8;
+  fixup[5] = w & 0xFF; w >>= 8;
+  fixup[6] = w & 0xFF; w >>= 8;
+  fixup[7] = w & 0xFF; w >>= 8;
+  arm_notify_new_code(fixup, 8);
+}
+#endif /* arm_TARGET_ARCH */
+
+
+
+/* Do ELF relocations which lack an explicit addend.  All x86-linux
+   relocations appear to be of this form. */
+static int
+do_Elf_Rel_relocations ( ObjectCode* oc, char* ehdrC,
+                         Elf_Shdr* shdr, int shnum,
+                         Elf_Sym*  stab, char* strtab )
+{
+   int j;
+   char *symbol = NULL;
+   Elf_Word* targ;
+   Elf_Rel*  rtab = (Elf_Rel*) (ehdrC + shdr[shnum].sh_offset);
+   int         nent = shdr[shnum].sh_size / sizeof(Elf_Rel);
+   int target_shndx = shdr[shnum].sh_info;
+   int symtab_shndx = shdr[shnum].sh_link;
+
+   stab  = (Elf_Sym*) (ehdrC + shdr[ symtab_shndx ].sh_offset);
+   targ  = (Elf_Word*)(ehdrC + shdr[ target_shndx ].sh_offset);
+   IF_DEBUG(linker,belch( "relocations for section %d using symtab %d",
+                          target_shndx, symtab_shndx ));
+
+   for (j = 0; j < nent; j++) {
+      Elf_Addr offset = rtab[j].r_offset;
+      Elf_Addr info   = rtab[j].r_info;
+
+      Elf_Addr  P  = ((Elf_Addr)targ) + offset;
+      Elf_Word* pP = (Elf_Word*)P;
+      Elf_Addr  A  = *pP;
+      Elf_Addr  S;
+      Elf_Addr  value;
+
+      IF_DEBUG(linker,belch( "Rel entry %3d is raw(%6p %6p)",
+                             j, (void*)offset, (void*)info ));
+      if (!info) {
+         IF_DEBUG(linker,belch( " ZERO" ));
+         S = 0;
+      } else {
+         Elf_Sym sym = stab[ELF_R_SYM(info)];
+        /* First see if it is a local symbol. */
+         if (ELF_ST_BIND(sym.st_info) == STB_LOCAL) {
+            /* Yes, so we can get the address directly from the ELF symbol
+               table. */
+            symbol = sym.st_name==0 ? "(noname)" : strtab+sym.st_name;
+            S = (Elf_Addr)
+                (ehdrC + shdr[ sym.st_shndx ].sh_offset
+                       + stab[ELF_R_SYM(info)].st_value);
+
+        } else {
+            /* No, so look up the name in our global table. */
+            symbol = strtab + sym.st_name;
+            S = (Elf_Addr)lookupSymbol( symbol );
+        }
+         if (!S) {
+            S = (Elf_Addr)lookup_magic_hacks(symbol);
+         }
+         if (!S) {
+            fprintf(stderr,"%s: unknown symbol `%s'\n", 
+                           oc->fileName, symbol);
+           return 0;
+         }
+         if (debug_linker>1) 
+            fprintf(stderr, "\n`%s' resolves to %p\n", symbol, (void*)S );
+      }
+
+      if (debug_linker>1)
+         fprintf(stderr, "Reloc: P = %p   S = %p   A = %p\n",
+                            (void*)P, (void*)S, (void*)A );
+      checkProddableBlock ( oc, pP );
+
+      value = S + A;
+
+      switch (ELF_R_TYPE(info)) {
+#        ifdef i386_TARGET_ARCH
+         case R_386_32:   *pP = value;     break;
+         case R_386_PC32: *pP = value - P; break;
+#        endif
+#        ifdef arm_TARGET_ARCH
+         case R_ARM_PC24: {
+           Elf_Word w, delta, deltaTop8;
+           /* Generate a jump sequence into the fixup area
+              and branch to that instead. */
+           char* fixup = alloc_fixup_bytes(oc, 8);
+            /* First of all, figure out where we're really trying to
+               jump to. */
+            // compensate for pc+8 bias
+            Elf_Word real_dst = (A & 0x00FFFFFF) + 2;
+           // sign-extend 24-to-32 of real_dst
+            if (real_dst & 0x00800000) 
+               real_dst |= 0xFF000000;
+            else
+               real_dst &= 0x00FFFFFF;
+
+            real_dst <<= 2;
+           real_dst += S;
+
+           gen_armle_goto(fixup, (char*)real_dst);
+
+           /* Delta is in bytes .. */
+            delta = (((Elf_Word)fixup) - ((Elf_Word)pP) - 8);
+            deltaTop8 = (delta >> 24) & 0xFF;
+            if (deltaTop8 != 0 && deltaTop8 != 0xFF) {
+             fprintf(stderr,"R_ARM_PC24: out of range delta 0x%x for %s\n",
+                     delta, symbol);
+             exit(1);
+           }
+            delta >>= 2;
+           w = *pP;
+            w &= 0xFF000000;
+            w |= (0x00FFFFFF & delta );
+            *pP = w;
+           break;
+         }
+         case R_ARM_ABS32:
+           *pP = value;
+           break;
+#        endif
+         default:
+            fprintf(stderr,
+                    "%s: unhandled ELF relocation(Rel) type %d\n\n",
+                   oc->fileName, ELF_R_TYPE(info));
+            return 0;
+      }
+
+   }
+   return 1;
+}
+
+/* Do ELF relocations for which explicit addends are supplied.
+   sparc-solaris relocations appear to be of this form. */
+static int
+do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
+                          Elf_Shdr* shdr, int shnum,
+                          Elf_Sym*  stab, char* strtab )
+{
+   int j;
+   char *symbol;
+   Elf_Addr targ;
+   Elf_Rela* rtab = (Elf_Rela*) (ehdrC + shdr[shnum].sh_offset);
+   int         nent = shdr[shnum].sh_size / sizeof(Elf_Rela);
+   int target_shndx = shdr[shnum].sh_info;
+   int symtab_shndx = shdr[shnum].sh_link;
+
+   stab  = (Elf_Sym*) (ehdrC + shdr[ symtab_shndx ].sh_offset);
+   targ  = (Elf_Addr) (ehdrC + shdr[ target_shndx ].sh_offset);
+   IF_DEBUG(linker,belch( "relocations for section %d using symtab %d",
+                          target_shndx, symtab_shndx ));
+
+   for (j = 0; j < nent; j++) {
+#if defined(DEBUG) || defined(sparc_TARGET_ARCH) || defined(ia64_TARGET_ARCH)
+      /* This #ifdef only serves to avoid unused-var warnings. */
+      Elf_Addr  offset = rtab[j].r_offset;
+      Elf_Addr  P      = targ + offset;
+#endif
+      Elf_Addr  info   = rtab[j].r_info;
+      Elf_Addr  A      = rtab[j].r_addend;
+      Elf_Addr  S;
+      Elf_Addr  value;
+#     if defined(sparc_TARGET_ARCH)
+      Elf_Word* pP = (Elf_Word*)P;
+      Elf_Word  w1, w2;
+#     elif defined(ia64_TARGET_ARCH)
+      Elf64_Xword *pP = (Elf64_Xword *)P;
+      Elf_Addr addr;
+#     endif
+
+      IF_DEBUG(linker,belch( "Rel entry %3d is raw(%6p %6p %6p)   ",
+                             j, (void*)offset, (void*)info,
+                                (void*)A ));
+      if (!info) {
+         IF_DEBUG(linker,belch( " ZERO" ));
+         S = 0;
+      } else {
+         Elf_Sym sym = stab[ELF_R_SYM(info)];
+        /* First see if it is a local symbol. */
+         if (ELF_ST_BIND(sym.st_info) == STB_LOCAL) {
+            /* Yes, so we can get the address directly from the ELF symbol
+               table. */
+            symbol = sym.st_name==0 ? "(noname)" : strtab+sym.st_name;
+            S = (Elf_Addr)
+                (ehdrC + shdr[ sym.st_shndx ].sh_offset
+                       + stab[ELF_R_SYM(info)].st_value);
+#ifdef ELF_FUNCTION_DESC
+           /* Make a function descriptor for this function */
+            if (S && ELF_ST_TYPE(sym.st_info) == STT_FUNC) {
+               S = allocateFunctionDesc(S + A);
+                      A = 0;
+            }
+#endif
+        } else {
+            /* No, so look up the name in our global table. */
+            symbol = strtab + sym.st_name;
+            S = (Elf_Addr)lookupSymbol( symbol );
+
+#ifdef ELF_FUNCTION_DESC
+           /* If a function, already a function descriptor - we would
+              have to copy it to add an offset. */
+            if (S && (ELF_ST_TYPE(sym.st_info) == STT_FUNC) && (A != 0))
+               belch("%s: function %s with addend %p", oc->fileName, symbol, (void *)A);
+#endif
+        }
+         if (!S) {
+          fprintf(stderr,"%s: unknown symbol `%s'\n", oc->fileName, symbol);
+          return 0;
+         }
+         IF_DEBUG(linker,belch( "`%s' resolves to %p\n", symbol, (void*)S ));
+      }
+
+      IF_DEBUG(linker,fprintf ( stderr, "Reloc: P = %p   S = %p   A = %p\n",
+                                        (void*)P, (void*)S, (void*)A ));
+      /* checkProddableBlock ( oc, (void*)P ); */
+
+      value = S + A;
+
+      switch (ELF_R_TYPE(info)) {
+#        if defined(sparc_TARGET_ARCH)
+         case R_SPARC_WDISP30:
+            w1 = *pP & 0xC0000000;
+            w2 = (Elf_Word)((value - P) >> 2);
+            ASSERT((w2 & 0xC0000000) == 0);
+            w1 |= w2;
+            *pP = w1;
+            break;
+         case R_SPARC_HI22:
+            w1 = *pP & 0xFFC00000;
+            w2 = (Elf_Word)(value >> 10);
+            ASSERT((w2 & 0xFFC00000) == 0);
+            w1 |= w2;
+            *pP = w1;
+            break;
+         case R_SPARC_LO10:
+            w1 = *pP & ~0x3FF;
+            w2 = (Elf_Word)(value & 0x3FF);
+            ASSERT((w2 & ~0x3FF) == 0);
+            w1 |= w2;
+            *pP = w1;
+            break;
+         /* According to the Sun documentation:
+            R_SPARC_UA32
+            This relocation type resembles R_SPARC_32, except it refers to an
+            unaligned word. That is, the word to be relocated must be treated
+            as four separate bytes with arbitrary alignment, not as a word
+            aligned according to the architecture requirements.
+
+            (JRS: which means that freeloading on the R_SPARC_32 case
+            is probably wrong, but hey ...)
+         */
+         case R_SPARC_UA32:
+         case R_SPARC_32:
+            w2 = (Elf_Word)value;
+            *pP = w2;
+            break;
+#        elif defined(ia64_TARGET_ARCH)
+        case R_IA64_DIR64LSB:
+        case R_IA64_FPTR64LSB:
+           *pP = value;
+           break;
+        case R_IA64_PCREL64LSB:
+           *pP = value - P;
+           break;
+        case R_IA64_SEGREL64LSB:
+           addr = findElfSegment(ehdrC, value);
+           *pP = value - addr;
+           break;
+        case R_IA64_GPREL22:
+           ia64_reloc_gprel22(P, value);
+           break;
+        case R_IA64_LTOFF22:
+        case R_IA64_LTOFF22X:
+        case R_IA64_LTOFF_FPTR22:
+           addr = allocateGOTEntry(value);
+           ia64_reloc_gprel22(P, addr);
+           break;
+        case R_IA64_PCREL21B:
+           ia64_reloc_pcrel21(P, S, oc);
+           break;
+        case R_IA64_LDXMOV:
+           /* This goes with R_IA64_LTOFF22X and points to the load to
+            * convert into a move.  We don't implement relaxation. */
+           break;
+#        endif
+         default:
+            fprintf(stderr,
+                    "%s: unhandled ELF relocation(RelA) type %d\n",
+                   oc->fileName, ELF_R_TYPE(info));
+            return 0;
+      }
+
+   }
+   return 1;
+}
+
+
+static int
+ocResolve_ELF ( ObjectCode* oc )
+{
+   char *strtab;
+   int   shnum, ok;
+   Elf_Sym*  stab  = NULL;
+   char*     ehdrC = (char*)(oc->image);
+   Elf_Ehdr* ehdr  = (Elf_Ehdr*) ehdrC;
+   Elf_Shdr* shdr  = (Elf_Shdr*) (ehdrC + ehdr->e_shoff);
+   char* sh_strtab = ehdrC + shdr[ehdr->e_shstrndx].sh_offset;
+
+   /* first find "the" symbol table */
+   stab = (Elf_Sym*) findElfSection ( ehdrC, SHT_SYMTAB );
+
+   /* also go find the string table */
+   strtab = findElfSection ( ehdrC, SHT_STRTAB );
+
+   if (stab == NULL || strtab == NULL) {
+      fprintf(stderr,"%s: can't find string or symbol table\n", oc->fileName);
+      return 0;
+   }
+
+   /* Process the relocation sections. */
+   for (shnum = 0; shnum < ehdr->e_shnum; shnum++) {
+
+      /* Skip sections called ".rel.stab".  These appear to contain
+         relocation entries that, when done, make the stabs debugging
+         info point at the right places.  We ain't interested in all
+         dat jazz, mun. */
+      if (0 == memcmp(".rel.stab", sh_strtab + shdr[shnum].sh_name, 9))
+         continue;
+
+      if (shdr[shnum].sh_type == SHT_REL ) {
+         ok = do_Elf_Rel_relocations ( oc, ehdrC, shdr,
+                                       shnum, stab, strtab );
+         if (!ok) return ok;
+      }
+      else
+      if (shdr[shnum].sh_type == SHT_RELA) {
+         ok = do_Elf_Rela_relocations ( oc, ehdrC, shdr,
+                                        shnum, stab, strtab );
+         if (!ok) return ok;
+      }
+   }
+
+   /* Free the local symbol table; we won't need it again. */
+   delete_StringMap(oc->lochash);
+   oc->lochash = NULL;
+
+   return 1;
+}
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+//
+// VERIFY
+
+static int
+ocVerifyImage_ELF ( ObjectCode* oc )
+{
+   Elf_Shdr* shdr;
+   Elf_Sym*  stab;
+   int i, j, nent, nstrtab, nsymtabs;
+   char* sh_strtab;
+   char* strtab;
+
+   char*     ehdrC = (char*)(oc->image);
+   Elf_Ehdr* ehdr  = (Elf_Ehdr*)ehdrC;
+
+   if (ehdr->e_ident[EI_MAG0] != ELFMAG0 ||
+       ehdr->e_ident[EI_MAG1] != ELFMAG1 ||
+       ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
+       ehdr->e_ident[EI_MAG3] != ELFMAG3) {
+      fprintf(stderr,"%s: not an ELF object\n", oc->fileName);
+      return 0;
+   }
+
+   if (ehdr->e_ident[EI_CLASS] != ELFCLASS) {
+      fprintf(stderr,"%s: unsupported ELF format\n", oc->fileName);
+      return 0;
+   }
+
+   if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) {
+      if (debug_linker)
+         fprintf(stderr, "Is little-endian\n" );
+   } else
+   if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) {
+       if (debug_linker)
+          fprintf(stderr, "Is big-endian\n" );
+   } else {
+       fprintf(stderr,"%s: unknown endiannness\n", oc->fileName);
+       return 0;
+   }
+
+   if (ehdr->e_type != ET_REL) {
+      fprintf(stderr,"%s: not a relocatable object (.o) file\n", oc->fileName);
+      return 0;
+   }
+   if (debug_linker)
+      fprintf(stderr, "Is a relocatable object (.o) file\n" );
+
+   if (debug_linker)
+      fprintf(stderr, "Architecture is " );
+   switch (ehdr->e_machine) {
+      case EM_386:   if (debug_linker) fprintf(stderr, "x86\n" ); break;
+      case EM_SPARC: if (debug_linker) fprintf(stderr, "sparc\n" ); break;
+      case EM_ARM:   if (debug_linker) fprintf(stderr, "arm\n" ); break;
+#ifdef EM_IA_64
+      case EM_IA_64: if (debug_linker) fprintf(stderr, "ia64\n" ); break;
+#endif
+      default:       if (debug_linker) fprintf(stderr, "unknown\n" );
+                     fprintf(stderr,"%s: unknown architecture\n", oc->fileName);
+                     return 0;
+   }
+
+   if (debug_linker>1) fprintf(stderr,
+             "\nSection header table: start %d, n_entries %d, ent_size %d\n",
+             ehdr->e_shoff, ehdr->e_shnum, ehdr->e_shentsize  );
+
+   assert (ehdr->e_shentsize == sizeof(Elf_Shdr));
+
+   shdr = (Elf_Shdr*) (ehdrC + ehdr->e_shoff);
+
+   if (ehdr->e_shstrndx == SHN_UNDEF) {
+      fprintf(stderr,"%s: no section header string table\n", oc->fileName);
+      return 0;
+   } else {
+      if (debug_linker>1) 
+         fprintf(stderr, "Section header string table is section %d\n",
+                          ehdr->e_shstrndx);
+      sh_strtab = ehdrC + shdr[ehdr->e_shstrndx].sh_offset;
+   }
+
+   for (i = 0; i < ehdr->e_shnum; i++) {
+      if (debug_linker>1) fprintf(stderr, "%2d:  ", i );
+      if (debug_linker>1) fprintf(stderr, "type=%2d  ", (int)shdr[i].sh_type );
+      if (debug_linker>1) fprintf(stderr, "size=%4d  ", (int)shdr[i].sh_size );
+      if (debug_linker>1) fprintf(stderr, "offs=%4d  ", (int)shdr[i].sh_offset );
+      if (debug_linker>1) fprintf(stderr, "  (%p .. %p)  ",
+               ehdrC + shdr[i].sh_offset,
+                     ehdrC + shdr[i].sh_offset + shdr[i].sh_size - 1);
+
+      if (shdr[i].sh_type == SHT_REL) {
+         if (debug_linker>1) fprintf(stderr, "Rel  " );
+      } else if (shdr[i].sh_type == SHT_RELA) {
+         if (debug_linker>1) fprintf(stderr, "RelA " );
+      } else {
+         if (debug_linker>1) fprintf(stderr,"     ");
+      }
+      if (sh_strtab) {
+         if (debug_linker>1) fprintf(stderr, "sname=%s\n", 
+             sh_strtab + shdr[i].sh_name );
+      }
+   }
+
+   if (debug_linker>1) fprintf(stderr, "\nString tables\n" );
+   strtab = NULL;
+   nstrtab = 0;
+   for (i = 0; i < ehdr->e_shnum; i++) {
+      if (shdr[i].sh_type == SHT_STRTAB
+          /* Ignore the section header's string table. */
+          && i != ehdr->e_shstrndx
+         /* Ignore string tables named .stabstr, as they contain
+             debugging info. */
+          && 0 != memcmp(".stabstr", sh_strtab + shdr[i].sh_name, 8)
+         ) {
+         if (debug_linker>1) 
+            fprintf(stderr,"   section %d is a normal string table\n", i );
+         strtab = ehdrC + shdr[i].sh_offset;
+         nstrtab++;
+      }
+   }
+   if (nstrtab != 1) {
+      fprintf(stderr,"%s: no string tables, or too many\n", oc->fileName);
+      return 0;
+   }
+
+   nsymtabs = 0;
+   if (debug_linker>1) fprintf(stderr, "\nSymbol tables\n" );
+   for (i = 0; i < ehdr->e_shnum; i++) {
+      if (shdr[i].sh_type != SHT_SYMTAB) continue;
+      if (debug_linker>1) fprintf(stderr, "section %d is a symbol table\n", i );
+      nsymtabs++;
+      stab = (Elf_Sym*) (ehdrC + shdr[i].sh_offset);
+      nent = shdr[i].sh_size / sizeof(Elf_Sym);
+      if (debug_linker>1) fprintf(stderr,  
+            "   number of entries is apparently %d (%d rem)\n",
+               nent,
+               shdr[i].sh_size % sizeof(Elf_Sym)
+             );
+      if (0 != shdr[i].sh_size % sizeof(Elf_Sym)) {
+         fprintf(stderr,"%s: non-integral number of symbol table entries\n", 
+                        oc->fileName);
+         return 0;
+      }
+      for (j = 0; j < nent; j++) {
+         if (debug_linker>1) fprintf(stderr, "   %2d  ", j );
+         if (debug_linker>1) fprintf(stderr, "  sec=%-5d  size=%-3d  val=%5p  ",
+                             (int)stab[j].st_shndx,
+                             (int)stab[j].st_size,
+                             (char*)stab[j].st_value );
+
+         if (debug_linker>1) fprintf(stderr, "type=" );
+         switch (ELF_ST_TYPE(stab[j].st_info)) {
+            case STT_NOTYPE:  if (debug_linker>1) fprintf(stderr, "notype " ); break;
+            case STT_OBJECT:  if (debug_linker>1) fprintf(stderr, "object " ); break;
+            case STT_FUNC  :  if (debug_linker>1) fprintf(stderr, "func   " ); break;
+            case STT_SECTION: if (debug_linker>1) fprintf(stderr, "section" ); break;
+            case STT_FILE:    if (debug_linker>1) fprintf(stderr, "file   " ); break;
+            default:          if (debug_linker>1) fprintf(stderr, "?      " ); break;
+         }
+         if (debug_linker>1) fprintf(stderr, "  " );
+
+         if (debug_linker>1) fprintf(stderr, "bind=" );
+         switch (ELF_ST_BIND(stab[j].st_info)) {
+            case STB_LOCAL :  if (debug_linker>1) fprintf(stderr, "local " ); break;
+            case STB_GLOBAL:  if (debug_linker>1) fprintf(stderr, "global" ); break;
+            case STB_WEAK  :  if (debug_linker>1) fprintf(stderr, "weak  " ); break;
+            default:          if (debug_linker>1) fprintf(stderr, "?     " ); break;
+         }
+         if (debug_linker>1) fprintf(stderr, "  " );
+
+         if (debug_linker>1) fprintf(stderr, "name=%s\n", strtab + stab[j].st_name );
+      }
+   }
+
+   if (nsymtabs == 0) {
+      fprintf(stderr,"%s: didn't find any symbol tables\n", oc->fileName);
+      return 0;
+   }
+
+   return 1;
+}
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+//
+// GETNAMES
+
+static int
+ocGetNames_ELF ( ObjectCode* oc )
+{
+   int i, j, k, nent;
+   Elf_Sym* stab;
+
+   char*     ehdrC     = (char*)(oc->image);
+   Elf_Ehdr* ehdr      = (Elf_Ehdr*)ehdrC;
+   char*     strtab    = findElfSection ( ehdrC, SHT_STRTAB );
+   Elf_Shdr* shdr      = (Elf_Shdr*) (ehdrC + ehdr->e_shoff);
+
+   char*     sh_strtab = ehdrC + shdr[ehdr->e_shstrndx].sh_offset;
+   char*     sec_name;
+
+   assert(global_symbol_table != NULL);
+
+   if (!strtab) {
+      fprintf(stderr,"%s: no strtab\n", oc->fileName);
+      return 0;
+   }
+
+   k = 0;
+   for (i = 0; i < ehdr->e_shnum; i++) {
+      /* Figure out what kind of section it is.  Logic derived from
+         Figure 1.14 ("Special Sections") of the ELF document
+         ("Portable Formats Specification, Version 1.1"). */
+      Elf_Shdr    hdr    = shdr[i];
+      SectionKind kind   = SECTIONKIND_OTHER;
+      int         is_bss = FALSE;
+
+      if (hdr.sh_type == SHT_PROGBITS
+          && (hdr.sh_flags & SHF_ALLOC) && (hdr.sh_flags & SHF_EXECINSTR)) {
+         /* .text-style section */
+         kind = SECTIONKIND_CODE_OR_RODATA;
+      }
+      else
+      if (hdr.sh_type == SHT_PROGBITS
+          && (hdr.sh_flags & SHF_ALLOC) && (hdr.sh_flags & SHF_WRITE)) {
+         /* .data-style section */
+         kind = SECTIONKIND_RWDATA;
+      }
+      else
+      if (hdr.sh_type == SHT_PROGBITS
+          && (hdr.sh_flags & SHF_ALLOC) && !(hdr.sh_flags & SHF_WRITE)) {
+         /* .rodata-style section */
+         kind = SECTIONKIND_CODE_OR_RODATA;
+      }
+      else
+      if (hdr.sh_type == SHT_NOBITS
+          && (hdr.sh_flags & SHF_ALLOC) && (hdr.sh_flags & SHF_WRITE)) {
+         /* .bss-style section */
+         kind = SECTIONKIND_RWDATA;
+         is_bss = TRUE;
+      }
+
+      if (is_bss && shdr[i].sh_size > 0) {
+         /* This is a non-empty .bss section.  Allocate zeroed space for
+            it, and set its .sh_offset field such that
+            ehdrC + .sh_offset == addr_of_zeroed_space.  */
+         char* zspace = calloc(1, shdr[i].sh_size);
+         shdr[i].sh_offset = ((char*)zspace) - ((char*)ehdrC);
+        /*
+         fprintf(stderr, "BSS section at 0x%x, size %d\n",
+                         zspace, shdr[i].sh_size);
+        */
+      }
+
+      /* When loading objects compiled with -g, it seems there are
+        relocations in various debug-info sections.  So we'd better
+        tell addProddableBlock to allow those bits to be prodded. */
+      //fprintf(stderr, "ZZZZZZZZZZ %s\n", sh_strtab + hdr.sh_name);
+      sec_name = sh_strtab + shdr[i].sh_name;
+      if (kind == SECTIONKIND_OTHER
+          && (0 == strcmp(".debug_info", sec_name)
+              || 0 == strcmp(".debug_line", sec_name)
+              || 0 == strcmp(".debug_pubnames", sec_name)
+              || 0 == strcmp(".debug_aranges", sec_name)
+              || 0 == strcmp(".debug_frame", sec_name))) {
+         kind = SECTIONKIND_CODE_OR_RODATA;
+      }
+
+      /* fill in the section info */
+      if (kind != SECTIONKIND_OTHER && shdr[i].sh_size > 0) {
+         addProddableBlock(oc, ehdrC + shdr[i].sh_offset, shdr[i].sh_size);
+         //addSection(oc, kind, ehdrC + shdr[i].sh_offset,
+         //               ehdrC + shdr[i].sh_offset + shdr[i].sh_size - 1);
+      }
+
+      if (shdr[i].sh_type != SHT_SYMTAB) continue;
+
+      /* copy stuff into this module's object symbol table */
+      stab = (Elf_Sym*) (ehdrC + shdr[i].sh_offset);
+      nent = shdr[i].sh_size / sizeof(Elf_Sym);
+
+      oc->n_symbols = nent;
+      oc->symbols = malloc(oc->n_symbols * sizeof(char*));
+
+      for (j = 0; j < nent; j++) {
+
+         char  isLocal = FALSE; /* avoids uninit-var warning */
+         char* ad      = NULL;
+         char* nm      = strtab + stab[j].st_name;
+         int   secno   = stab[j].st_shndx;
+
+        /* Figure out if we want to add it; if so, set ad to its
+            address.  Otherwise leave ad == NULL. */
+
+         if (secno == SHN_COMMON) {
+            isLocal = FALSE;
+            ad = calloc(1, stab[j].st_size);
+           /*
+            fprintf(stderr, "COMMON symbol, size %d name %s\n",
+                            stab[j].st_size, nm);
+           */
+           /* Pointless to do addProddableBlock() for this area,
+               since the linker should never poke around in it. */
+        }
+         else
+         if ( ( ELF_ST_BIND(stab[j].st_info)==STB_GLOBAL
+                || ELF_ST_BIND(stab[j].st_info)==STB_LOCAL
+              )
+              /* and not an undefined symbol */
+              && stab[j].st_shndx != SHN_UNDEF
+             /* and not in a "special section" */
+              && stab[j].st_shndx < SHN_LORESERVE
+              &&
+             /* and it's a not a section or string table or anything silly */
+              ( ELF_ST_TYPE(stab[j].st_info)==STT_FUNC ||
+                ELF_ST_TYPE(stab[j].st_info)==STT_OBJECT ||
+                ELF_ST_TYPE(stab[j].st_info)==STT_NOTYPE
+              )
+            ) {
+           /* Section 0 is the undefined section, hence > and not >=. */
+            assert(secno > 0 && secno < ehdr->e_shnum);
+           /*
+            if (shdr[secno].sh_type == SHT_NOBITS) {
+               fprintf(stderr, "   BSS symbol, size %d off %d name %s\n",
+                               stab[j].st_size, stab[j].st_value, nm);
+            }
+            */
+            ad = ehdrC + shdr[ secno ].sh_offset + stab[j].st_value;
+            if (ELF_ST_BIND(stab[j].st_info)==STB_LOCAL) {
+               isLocal = TRUE;
+            } else {
+#ifdef ELF_FUNCTION_DESC
+               /* dlsym() and the initialisation table both give us function
+               * descriptors, so to be consistent we store function descriptors
+               * in the symbol table */
+               if (ELF_ST_TYPE(stab[j].st_info) == STT_FUNC)
+                   ad = (char *)allocateFunctionDesc((Elf_Addr)ad);
+#endif
+               if (debug_linker) 
+                   fprintf(stderr, "addOTabName(GLOB): %10p  %s %s\n",
+                                      ad, oc->fileName, nm );
+               isLocal = FALSE;
+            }
+         }
+
+         /* And the decision is ... */
+
+         if (ad != NULL) {
+            assert(nm != NULL);
+           oc->symbols[j] = nm;
+            /* Acquire! */
+            if (isLocal) {
+               /* Ignore entirely. */
+            } else {
+             //ghciInsertStrHashTable(oc->fileName, global_symbol_table, nm, ad);
+             paranoid_addto_StringMap(global_symbol_table, nm, ad);
+            }
+         } else {
+            /* Skip. */
+            if (debug_linker>1) fprintf(stderr, "skipping `%s'\n",
+                                   strtab + stab[j].st_name );
+            /*
+            fprintf(stderr,
+                    "skipping   bind = %d,  type = %d,  shndx = %d   `%s'\n",
+                    (int)ELF_ST_BIND(stab[j].st_info),
+                    (int)ELF_ST_TYPE(stab[j].st_info),
+                    (int)stab[j].st_shndx,
+                    strtab + stab[j].st_name
+                   );
+            */
+            oc->symbols[j] = NULL;
+         }
+
+      }
+   }
+
+   return 1;
+}
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+//
+// TOP-LEVEL CONTROL OF THE LINKER
+
+
+/* ---------------------------------------------------------------------
+ * Load an obj (populate the global symbol table, but don't resolve yet)
+ *
+ * Returns: 1 if ok, 0 on error.
+ */
+static
+int loadObj( char *path )
+{
+   ObjectCode* oc;
+   struct stat st;
+   int r;
+   int fd, pagesize;
+   char* p;
+
+   initLinker();
+
+   fprintf(stderr, "==== loadObj %s ====\n", path );
+
+   /* Check that we haven't already loaded this object.  */
+   {
+       ObjectCode *o;
+       int is_dup = 0;
+       for (o = global_object_list; o; o = o->next) {
+          if (0 == strcmp(o->fileName, path))
+             is_dup = 1;
+       }
+       if (is_dup) {
+        fprintf(stderr,
+            "\n\n"
+            "GHCi runtime linker: warning: looks like you're trying to load the\n"
+            "same object file twice:\n"
+            "   %s\n"
+            , path);
+        exit(1);
+       }
+   }
+
+   oc = malloc(sizeof(ObjectCode));
+
+   oc->formatName = "ELF";
+
+   r = stat(path, &st);
+   if (r == -1) { return 0; }
+
+   /* sigh, strdup() isn't a POSIX function, so do it the long way */
+   oc->fileName = malloc( strlen(path)+1 );
+   strcpy(oc->fileName, path);
+
+   oc->fileSize          = st.st_size;
+   oc->symbols           = NULL;
+   oc->sections          = NULL;
+   oc->lochash           = new_StringMap();
+   oc->proddables        = NULL;
+   oc->fixup             = NULL;
+   oc->fixup_used        = 0;
+   oc->fixup_size        = 0;
+
+   /* chain it onto the list of objects */
+   oc->next              = global_object_list;
+   global_object_list    = oc;
+
+   fd = open(path, O_RDONLY);
+   if (fd == -1) {
+      fprintf(stderr,"loadObj: can't open `%s'\n", path);
+      exit(1);
+   }
+
+   /* Allocate a 1-page area just prior to the image, so we can put
+      fixup code fragments there.  Used for doing R_ARM_PC24
+      relocations for jump distances > 64M. */
+
+   pagesize = getpagesize();
+   p = memalign(pagesize, N_FIXUP_PAGES * pagesize
+                          + oc->fileSize);
+
+   if (p == NULL) {
+      fprintf(stderr,"loadObj: failed to allocate space for `%s'\n", path);
+      exit(1);
+   }
+
+   oc->fixup = p;
+   oc->fixup_size = N_FIXUP_PAGES * pagesize;
+   oc->fixup_used = 0;
+   oc->image = &(p[ oc->fixup_size ]);
+
+   r = read(fd, oc->image, oc->fileSize);
+   if (r != oc->fileSize) {
+      fprintf(stderr,"loadObj: failed to read `%s'\n", path);
+      exit(1);
+   }
+
+   fprintf(stderr, "loaded %s at %p (fixup = %p)\n", 
+                   oc->fileName, oc->image, oc->fixup );
+
+   close(fd);
+
+   /* verify the in-memory image */
+   r = ocVerifyImage_ELF ( oc );
+   if (!r) { return r; }
+
+   /* build the symbol list for this image */
+   r = ocGetNames_ELF ( oc );
+   if (!r) { return r; }
+
+   /* loaded, but not resolved yet */
+   oc->status = OBJECT_LOADED;
+
+   return 1;
+}
+
+
+
+/* ---------------------------------------------------------------------------
+ * resolve all the currently unlinked objects in memory
+ *
+ * Returns: 1 if ok, 0 on error.
+ */
+static
+int resolveObjs( void )
+{
+    ObjectCode *oc;
+    int r;
+
+    initLinker();
+
+    for (oc = global_object_list; oc; oc = oc->next) {
+       if (oc->status != OBJECT_RESOLVED) {
+           r = ocResolve_ELF ( oc );
+           if (!r) { return r; }
+           oc->status = OBJECT_RESOLVED;
+       }
+    }
+    return 1;
+}
+
+
+/* ---------------------------------------------------------------------------
+ * Top-level linker.
+ */
+
+/* Load and link a bunch of .o's, and return the address of
+   'entry'.  Or NULL if something borks.
+*/
+void* linker_top_level_LINK ( int n_object_names, char** object_names )
+{
+   int   r, i;
+   void* mainp;
+
+   initLinker();
+   for (i = 0; i < n_object_names; i++) {
+      //fprintf(stderr, "linkloop %d %s\n", i, object_names[i] );
+      r = loadObj( object_names[i] );
+      if (r != 1) return NULL;
+   }
+   r = resolveObjs();
+   if (r != 1) return NULL;
+   mainp = search_StringMap ( global_symbol_table, "entry" );
+   if (mainp == NULL) return NULL;
+   printf("switchback: Linker: success!\n");
+   return mainp;
+}
+
+
diff --git a/VEX/switchback/linker.h b/VEX/switchback/linker.h
new file mode 100644 (file)
index 0000000..6b6c54b
--- /dev/null
@@ -0,0 +1,3 @@
+
+extern
+void* linker_top_level_LINK ( int n_object_names, char** object_names );
index 82ff8e248d7ea3382a834fe513d35d8e69140e2c..126ebb91694a4e770e857370a61c08104d53e0fb 100644 (file)
@@ -3,11 +3,10 @@
 
 Compile test file (eg test_hello.c) to a .o
 
-It must have an entry point called "entry" immediately preceded by the
-bytes 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88, so the entry point can
-be found.
+It must have an entry point called "entry", which expects to 
+take a single argument which is a function pointer (to "serviceFn").
 
-It must have ***NO RELOCATIONS*** -  objdump -r file.o shows none
+Test file may not reference any other symbols.
 
 */
 
@@ -22,7 +21,7 @@ It must have ***NO RELOCATIONS*** -  objdump -r file.o shows none
 #include "../pub/libvex_guest_x86.h"
 #include "../pub/libvex_guest_amd64.h"
 #include "../pub/libvex.h"
-
+#include "linker.h"
 
 static Int n_bbs_done = 0;
 
@@ -77,8 +76,8 @@ HWord sb_helper1 = 0;
 HWord sb_helper2 = 0;
 
 /* translation cache */
-#define N_TRANS_CACHE 100000
-#define N_TRANS_TABLE 1000
+#define N_TRANS_CACHE 1000000
+#define N_TRANS_TABLE 10000
 
 ULong trans_cache[N_TRANS_CACHE];
 VexGuestExtents trans_table [N_TRANS_TABLE];
@@ -394,48 +393,15 @@ int main ( Int argc, HChar** argv )
       return 1;
    }
 
-   imageSz = (Int)buf.st_size;
-   printf("stopAfter = %d\n", stopAfter);
-   printf("file size is %d\n", imageSz);
-
-   /* Get the file aboard and find the entry point */
-   image = malloc(imageSz);
-   assert(image);
-
-   f = fopen(oname, "r");
-   assert(f);
-   n = fread(image, 1, imageSz, f);
-   assert(n == imageSz);
-   fclose(f);
-
-   assert(imageSz > 12);
-   entry = NULL;
-   for (n = 0; n < imageSz - 8; n++) {
-     if (image[n+0] == 0x11 
-         && image[n+1] == 0x22
-         && image[n+2] == 0x33
-         && image[n+3] == 0x44
-         && image[n+4] == 0x55
-         && image[n+5] == 0x66
-         && image[n+6] == 0x77
-         && image[n+7] == 0x88
-        ) {
-       entry = &image[n+8];
-       break;
-     }
-   }
+   entry = linker_top_level_LINK( 1, &argv[1] );
 
    if (!entry) {
       printf("switchback: can't find entry point\n");
       exit(1);
    }
 
-   printf("switchback: entry bytes are: ");
-   for (i = 0; i < 4; i++)
-     printf("0x%02x ", (Int)entry[i]);
-
    LibVEX_default_VexControl(&vcon);
-   vcon.guest_max_insns=1; //50;
+   vcon.guest_max_insns=1;
    vcon.guest_chase_thresh=0;
    LibVEX_Init( failure_exit, log_bytes, 1, False, &vcon );
    LibVEX_Guest_initialise(&gst);