FIX: loading package ghc in GHCi (added a couple of missing symbols)
[ghc-hetmet.git] / rts / Linker.c
index 2c9b07e..d8d61a0 100644 (file)
@@ -10,7 +10,7 @@
 #include "PosixSource.h"
 #endif
 
-/* Linux needs _GNU_SOURCE to get RTLD_DEFAULT from <dlfcn.h> and 
+/* Linux needs _GNU_SOURCE to get RTLD_DEFAULT from <dlfcn.h> and
    MREMAP_MAYMOVE from <sys/mman.h>.
  */
 #ifdef __linux__
@@ -25,8 +25,8 @@
 #include "LinkerInternals.h"
 #include "RtsUtils.h"
 #include "Schedule.h"
-#include "Storage.h"
 #include "Sparks.h"
+#include "RtsTypeable.h"
 
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #if defined(powerpc_HOST_ARCH)
 #  include <mach-o/ppc/reloc.h>
 #endif
+#if defined(x86_64_HOST_ARCH)
+#  include <mach-o/x86_64/reloc.h>
+#endif
 #endif
 
 /* Hash table mapping symbol names to Symbol */
 static /*Str*/HashTable *symhash;
 
-typedef struct {
-  void *addr;
-} rootEntry;
-
 /* Hash table mapping symbol names to StgStablePtr */
 static /*Str*/HashTable *stablehash;
-rootEntry *root_ptr_table = NULL;
-static rootEntry *root_ptr_free = NULL;
-
-static unsigned int RPT_size = 0;
 
 /* List of currently loaded objects */
 ObjectCode *objects = NULL;    /* initially empty */
@@ -111,7 +106,7 @@ static int ocVerifyImage_ELF    ( ObjectCode* oc );
 static int ocGetNames_ELF       ( ObjectCode* oc );
 static int ocResolve_ELF        ( ObjectCode* oc );
 #if defined(powerpc_HOST_ARCH)
-static int ocAllocateJumpIslands_ELF ( ObjectCode* oc );
+static int ocAllocateSymbolExtras_ELF ( ObjectCode* oc );
 #endif
 #elif defined(OBJFORMAT_PEi386)
 static int ocVerifyImage_PEi386 ( ObjectCode* oc );
@@ -123,13 +118,15 @@ static int ocGetNames_MachO       ( ObjectCode* oc );
 static int ocResolve_MachO        ( ObjectCode* oc );
 
 static int machoGetMisalignment( FILE * );
+#if defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH)
+static int ocAllocateSymbolExtras_MachO ( ObjectCode* oc );
+#endif
 #ifdef powerpc_HOST_ARCH
-static int ocAllocateJumpIslands_MachO ( ObjectCode* oc );
 static void machoInitSymbolsWithoutUnderscore( void );
 #endif
 #endif
 
-#if defined(x86_64_HOST_ARCH)
+#if defined(x86_64_HOST_ARCH) && defined(OBJFORMAT_ELF)
 static void*x86_64_high_symbol( char *lbl, void *addr );
 #endif
 
@@ -259,6 +256,12 @@ typedef struct _RtsSymbolVal {
 #define RTS_MINGW_EXTRA_SYMS
 #endif
 
+#if HAVE_GETTIMEOFDAY
+#define RTS_MINGW_GETTIMEOFDAY_SYM Sym(gettimeofday)
+#else
+#define RTS_MINGW_GETTIMEOFDAY_SYM /**/
+#endif
+
 /* These are statically linked from the mingw libraries into the ghc
    executable, so we have to employ this hack. */
 #define RTS_MINGW_ONLY_SYMBOLS                  \
@@ -342,6 +345,7 @@ typedef struct _RtsSymbolVal {
       Sym(readdir)                              \
       Sym(rewinddir)                            \
       RTS_MINGW_EXTRA_SYMS                      \
+      RTS_MINGW_GETTIMEOFDAY_SYM               \
       Sym(closedir)
 #endif
 
@@ -405,7 +409,11 @@ typedef struct _RtsSymbolVal {
 #define RTS_USER_SIGNALS_SYMBOLS \
    SymX(setIOManagerPipe)
 #else
-#define RTS_USER_SIGNALS_SYMBOLS /* nothing */
+#define RTS_USER_SIGNALS_SYMBOLS \
+   SymX(sendIOManagerEvent) \
+   SymX(readIOManagerEvent) \
+   SymX(getIOManagerEvent) \
+   SymX(console_handler)
 #endif
 
 #ifdef TABLES_NEXT_TO_CODE
@@ -461,7 +469,6 @@ typedef struct _RtsSymbolVal {
       SymX(stg_block_1)                                \
       SymX(stg_block_takemvar)                 \
       SymX(stg_block_putmvar)                  \
-      SymX(stg_seq_frame_info)                 \
       MAIN_CAP_SYM                              \
       SymX(MallocFailHook)                     \
       SymX(OnExitHook)                         \
@@ -487,6 +494,7 @@ typedef struct _RtsSymbolVal {
       SymX(catchzh_fast)                       \
       SymX(catchRetryzh_fast)                  \
       SymX(catchSTMzh_fast)                    \
+      SymX(checkzh_fast)                        \
       SymX(closure_flags)                       \
       SymX(cmp_thread)                         \
       SymX(cmpIntegerzh_fast)                  \
@@ -508,6 +516,7 @@ typedef struct _RtsSymbolVal {
       SymX(forkOS_createThread)                        \
       SymX(freeHaskellFunctionPtr)             \
       SymX(freeStablePtr)                      \
+      SymX(getOrSetTypeableStore)              \
       SymX(gcdIntegerzh_fast)                  \
       SymX(gcdIntegerIntzh_fast)               \
       SymX(gcdIntzh_fast)                      \
@@ -523,6 +532,8 @@ typedef struct _RtsSymbolVal {
       SymX(hs_free_stable_ptr)                 \
       SymX(hs_free_fun_ptr)                    \
       SymX(initLinker)                         \
+      SymX(unpackClosurezh_fast)                \
+      SymX(getApStackValzh_fast)                \
       SymX(int2Integerzh_fast)                 \
       SymX(integer2Intzh_fast)                 \
       SymX(integer2Wordzh_fast)                        \
@@ -553,6 +564,7 @@ typedef struct _RtsSymbolVal {
       SymX(newMVarzh_fast)                     \
       SymX(newMutVarzh_fast)                   \
       SymX(newTVarzh_fast)                     \
+      SymX(noDuplicatezh_fast)                 \
       SymX(atomicModifyMutVarzh_fast)          \
       SymX(newPinnedByteArrayzh_fast)          \
       SymX(newSpark)                           \
@@ -700,19 +712,14 @@ typedef struct _RtsSymbolVal {
       SymX(xorIntegerzh_fast)                  \
       SymX(yieldzh_fast)                        \
       SymX(stg_interp_constr_entry)             \
-      SymX(stg_interp_constr1_entry)            \
-      SymX(stg_interp_constr2_entry)            \
-      SymX(stg_interp_constr3_entry)            \
-      SymX(stg_interp_constr4_entry)            \
-      SymX(stg_interp_constr5_entry)            \
-      SymX(stg_interp_constr6_entry)            \
-      SymX(stg_interp_constr7_entry)            \
-      SymX(stg_interp_constr8_entry)            \
       SymX(allocateExec)                       \
       SymX(freeExec)                           \
       SymX(getAllocations)                      \
       SymX(revertCAFs)                          \
       SymX(RtsFlags)                            \
+      SymX(rts_breakpoint_io_action)           \
+      SymX(rts_stop_next_breakpoint)           \
+      SymX(rts_stop_on_exception)              \
       RTS_USER_SIGNALS_SYMBOLS
 
 #ifdef SUPPORT_LONG_LONGS
@@ -795,6 +802,7 @@ static RtsSymbolVal rtsSyms[] = {
       RTS_POSIX_ONLY_SYMBOLS
       RTS_MINGW_ONLY_SYMBOLS
       RTS_CYGWIN_ONLY_SYMBOLS
+      RTS_DARWIN_ONLY_SYMBOLS
       RTS_LIBGCC_SYMBOLS
 #if defined(darwin_HOST_OS) && defined(i386_HOST_ARCH)
       // dyld stub code contains references to this,
@@ -806,97 +814,11 @@ static RtsSymbolVal rtsSyms[] = {
 };
 
 
-/* -----------------------------------------------------------------------------
- * Utilities for handling root pointers.
- * -------------------------------------------------------------------------- */
-
-
-#define INIT_RPT_SIZE 64
-
-STATIC_INLINE void
-initFreeList(rootEntry *table, nat n, rootEntry *free)
-{
-  rootEntry *p;
-
-  for (p = table + n - 1; p >= table; p--) {
-    p->addr   = (P_)free;
-    free = p;
-  }
-  root_ptr_free = table;
-}
-
-static void
-initRootPtrTable(void)
-{
-  if (RPT_size > 0)
-    return;
-
-  RPT_size = INIT_RPT_SIZE;
-  root_ptr_table = stgMallocBytes(RPT_size * sizeof(rootEntry),
-                                    "initRootPtrTable");
-
-  initFreeList(root_ptr_table,INIT_RPT_SIZE,NULL);
-}
-
-
-static void
-enlargeRootPtrTable(void)
-{
-  nat old_RPT_size = RPT_size;
-
-  // 2nd and subsequent times
-  RPT_size *= 2;
-  root_ptr_table =
-    stgReallocBytes(root_ptr_table,
-                    RPT_size * sizeof(rootEntry),
-                    "enlargeRootPtrTable");
-
-  initFreeList(root_ptr_table + old_RPT_size, old_RPT_size, NULL);
-}
-
-static void
-addRootObject(void *addr)
-{
-  StgWord rt;
-  initRootPtrTable();
-  if (root_ptr_free == NULL) {
-    enlargeRootPtrTable();
-  }
-
-  rt = root_ptr_free - root_ptr_table;
-  root_ptr_free  = (rootEntry*)(root_ptr_free->addr);
-  root_ptr_table[rt].addr = addr;
-}
-
-/* -----------------------------------------------------------------------------
- * Treat root pointers as roots for the garbage collector.
- * -------------------------------------------------------------------------- */
-
-void
-markRootPtrTable(evac_fn evac)
-{
-  rootEntry *p, *end_root_ptr_table;
-  StgPtr q;
-
-  end_root_ptr_table = &root_ptr_table[RPT_size];
-
-  for (p = root_ptr_table; p < end_root_ptr_table; p++) {
-    q = p->addr;
-
-    if (q && (q < (P_)root_ptr_table || q >= (P_)end_root_ptr_table)) {
-        evac((StgClosure **)p->addr);
-    }
-  }
-}
-
-/* -----------------------------------------------------------------------------
- * End of utilities for handling root pointers.
- * -------------------------------------------------------------------------- */
-
 
 /* -----------------------------------------------------------------------------
  * Insert symbols into hash tables, checking for duplicates.
  */
+
 static void ghciInsertStrHashTable ( char* obj_name,
                                      HashTable *table,
                                      char* key,
@@ -926,8 +848,6 @@ static void ghciInsertStrHashTable ( char* obj_name,
    );
    exit(1);
 }
-
-
 /* -----------------------------------------------------------------------------
  * initialize the object linker
  */
@@ -939,11 +859,6 @@ static int linker_init_done = 0 ;
 static void *dl_prog_handle;
 #endif
 
-/* dlopen(NULL,..) doesn't work so we grab libc explicitly */
-#if defined(openbsd_HOST_OS)
-static void *dl_libc_handle;
-#endif
-
 void
 initLinker( void )
 {
@@ -973,9 +888,6 @@ initLinker( void )
     dl_prog_handle = RTLD_DEFAULT;
 #   else
     dl_prog_handle = dlopen(NULL, RTLD_LAZY);
-#   if defined(openbsd_HOST_OS)
-    dl_libc_handle = dlopen("libc.so", RTLD_LAZY);
-#   endif
 #   endif /* RTLD_DEFAULT */
 #   endif
 }
@@ -1126,10 +1038,7 @@ lookupSymbol( char *lbl )
 
     if (val == NULL) {
 #       if defined(OBJFORMAT_ELF)
-#      if defined(openbsd_HOST_OS)
-       val = dlsym(dl_prog_handle, lbl);
-       return (val != NULL) ? val : dlsym(dl_libc_handle,lbl);
-#      elif defined(x86_64_HOST_ARCH)
+#      if defined(x86_64_HOST_ARCH)
        val = dlsym(dl_prog_handle, lbl);
        if (val >= (void *)0x80000000) {
            void *new_val;
@@ -1139,7 +1048,7 @@ lookupSymbol( char *lbl )
        } else {
            return val;
        }
-#      else /* not openbsd */
+#      else
        return dlsym(dl_prog_handle, lbl);
 #      endif
 #       elif defined(OBJFORMAT_MACHO)
@@ -1259,13 +1168,12 @@ loadObj( char *path )
    void *map_addr = NULL;
 #else
    FILE *f;
-   int misalignment;
 #endif
    initLinker();
 
    /* debugBelch("loadObj %s\n", path ); */
 
-   /* Check that we haven't already loaded this object. 
+   /* Check that we haven't already loaded this object.
       Ignore requests to load multiple times */
    {
        ObjectCode *o;
@@ -1355,7 +1263,7 @@ loadObj( char *path )
 #define EXTRA_MAP_FLAGS 0
 #endif
 
-   oc->image = mmap(map_addr, n, PROT_EXEC|PROT_READ|PROT_WRITE, 
+   oc->image = mmap(map_addr, n, PROT_EXEC|PROT_READ|PROT_WRITE,
                    MAP_PRIVATE|EXTRA_MAP_FLAGS, fd, 0);
    if (oc->image == MAP_FAILED)
       barf("loadObj: can't map `%s'", path);
@@ -1369,7 +1277,12 @@ loadObj( char *path )
    if (!f)
        barf("loadObj: can't read `%s'", path);
 
-#ifdef darwin_HOST_OS
+#   if defined(mingw32_HOST_OS)
+       // TODO: We would like to use allocateExec here, but allocateExec
+       //       cannot currently allocate blocks large enough.
+    oc->image = VirtualAlloc(NULL, oc->fileSize, MEM_RESERVE | MEM_COMMIT,
+                             PAGE_EXECUTE_READWRITE);
+#   elif defined(darwin_HOST_OS)
     // In a Mach-O .o file, all sections can and will be misaligned
     // if the total size of the headers is not a multiple of the
     // desired alignment. This is fine for .o files that only serve
@@ -1379,28 +1292,25 @@ loadObj( char *path )
     // We calculate the correct alignment from the header before
     // reading the file, and then we misalign oc->image on purpose so
     // that the actual sections end up aligned again.
-   misalignment = machoGetMisalignment(f);
-   oc->misalignment = misalignment;
-#else
-   misalignment = 0;
-#endif
+   oc->misalignment = machoGetMisalignment(f);
+   oc->image = stgMallocBytes(oc->fileSize + oc->misalignment, "loadObj(image)");
+   oc->image += oc->misalignment;
+#  else
+   oc->image = stgMallocBytes(oc->fileSize, "loadObj(image)");
+#  endif
 
-   oc->image = stgMallocBytes(oc->fileSize + misalignment, "loadObj(image)");
-   oc->image += misalignment;
-   
    n = fread ( oc->image, 1, oc->fileSize, f );
    if (n != oc->fileSize)
       barf("loadObj: error whilst reading `%s'", path);
 
    fclose(f);
-
 #endif /* USE_MMAP */
 
-#  if defined(OBJFORMAT_MACHO) && defined(powerpc_HOST_ARCH)
-   r = ocAllocateJumpIslands_MachO ( oc );
+#  if defined(OBJFORMAT_MACHO) && (defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH))
+   r = ocAllocateSymbolExtras_MachO ( oc );
    if (!r) { return r; }
 #  elif defined(OBJFORMAT_ELF) && defined(powerpc_HOST_ARCH)
-   r = ocAllocateJumpIslands_ELF ( oc );
+   r = ocAllocateSymbolExtras_ELF ( oc );
    if (!r) { return r; }
 #endif
 
@@ -1500,9 +1410,13 @@ unloadObj( char *path )
                prev->next = oc->next;
            }
 
-           /* We're going to leave this in place, in case there are
-              any pointers from the heap into it: */
-           /* stgFree(oc->image); */
+           // We're going to leave this in place, in case there are
+           // any pointers from the heap into it:
+               // #ifdef mingw32_HOST_OS
+               //  VirtualFree(oc->image);
+               // #else
+           //  stgFree(oc->image);
+           // #endif
            stgFree(oc->fileName);
            stgFree(oc->symbols);
            stgFree(oc->sections);
@@ -1570,28 +1484,36 @@ static void addSection ( ObjectCode* oc, SectionKind kind,
 
 
 /* --------------------------------------------------------------------------
- * PowerPC specifics (jump islands)
- * ------------------------------------------------------------------------*/
+ * Symbol Extras.
+ * This is about allocating a small chunk of memory for every symbol in the
+ * object file. We make sure that the SymboLExtras are always "in range" of
+ * limited-range PC-relative instructions on various platforms by allocating
+ * them right next to the object code itself.
+ */
 
-#if defined(powerpc_HOST_ARCH)
+#if defined(powerpc_HOST_ARCH) || (defined(x86_64_HOST_ARCH) \
+                                    && defined(darwin_TARGET_OS))
 
 /*
-  ocAllocateJumpIslands
-  
+  ocAllocateSymbolExtras
+
   Allocate additional space at the end of the object file image to make room
-  for jump islands.
+  for jump islands (powerpc, x86_64) and GOT entries (x86_64).
   
   PowerPC relative branch instructions have a 24 bit displacement field.
   As PPC code is always 4-byte-aligned, this yields a +-32MB range.
   If a particular imported symbol is outside this range, we have to redirect
   the jump to a short piece of new code that just loads the 32bit absolute
   address and jumps there.
-  This function just allocates space for one 16 byte ppcJumpIsland for every
-  undefined symbol in the object file. The code for the islands is filled in by
-  makeJumpIsland below.
+  On x86_64, PC-relative jumps and PC-relative accesses to the GOT are limited
+  to 32 bits (+-2GB).
+  
+  This function just allocates space for one SymbolExtra for every
+  undefined symbol in the object file. The code for the jump islands is
+  filled in by makeSymbolExtra below.
 */
 
-static int ocAllocateJumpIslands( ObjectCode* oc, int count, int first )
+static int ocAllocateSymbolExtras( ObjectCode* oc, int count, int first )
 {
 #ifdef USE_MMAP
   int pagesize, n, m;
@@ -1609,12 +1531,12 @@ static int ocAllocateJumpIslands( ObjectCode* oc, int count, int first )
 
 #ifdef USE_MMAP
     #ifndef linux_HOST_OS /* mremap is a linux extension */
-        #error ocAllocateJumpIslands doesnt want USE_MMAP to be defined
+        #error ocAllocateSymbolExtras doesnt want USE_MMAP to be defined
     #endif
 
     pagesize = getpagesize();
     n = ROUND_UP( oc->fileSize, pagesize );
-    m = ROUND_UP( aligned + sizeof (ppcJumpIsland) * count, pagesize );
+    m = ROUND_UP( aligned + sizeof (SymbolExtra) * count, pagesize );
 
     /* If we have a half-page-size file and map one page of it then
      * the part of the page after the size of the file remains accessible.
@@ -1653,52 +1575,66 @@ static int ocAllocateJumpIslands( ObjectCode* oc, int count, int first )
     oc->image -= misalignment;
     oc->image = stgReallocBytes( oc->image,
                                  misalignment + 
-                                 aligned + sizeof (ppcJumpIsland) * count,
-                                 "ocAllocateJumpIslands" );
+                                 aligned + sizeof (SymbolExtra) * count,
+                                 "ocAllocateSymbolExtras" );
     oc->image += misalignment;
 #endif /* USE_MMAP */
 
-    oc->jump_islands = (ppcJumpIsland *) (oc->image + aligned);
-    memset( oc->jump_islands, 0, sizeof (ppcJumpIsland) * count );
+    oc->symbol_extras = (SymbolExtra *) (oc->image + aligned);
+    memset( oc->symbol_extras, 0, sizeof (SymbolExtra) * count );
   }
   else
-    oc->jump_islands = NULL;
+    oc->symbol_extras = NULL;
 
-  oc->island_start_symbol = first;
-  oc->n_islands = count;
+  oc->first_symbol_extra = first;
+  oc->n_symbol_extras = count;
 
   return 1;
 }
 
-static unsigned long makeJumpIsland( ObjectCode* oc,
+static SymbolExtra* makeSymbolExtra( ObjectCode* oc,
                                      unsigned long symbolNumber,
                                      unsigned long target )
 {
-  ppcJumpIsland *island;
+  SymbolExtra *extra;
 
-  if( symbolNumber < oc->island_start_symbol ||
-      symbolNumber - oc->island_start_symbol > oc->n_islands)
-    return 0;
+  ASSERT( symbolNumber >= oc->first_symbol_extra
+        && symbolNumber - oc->first_symbol_extra < oc->n_symbol_extras);
 
-  island = &oc->jump_islands[symbolNumber - oc->island_start_symbol];
+  extra = &oc->symbol_extras[symbolNumber - oc->first_symbol_extra];
 
+#ifdef powerpc_HOST_ARCH
   // lis r12, hi16(target)
-  island->lis_r12     = 0x3d80;
-  island->hi_addr     = target >> 16;
+  extra->jumpIsland.lis_r12     = 0x3d80;
+  extra->jumpIsland.hi_addr     = target >> 16;
 
   // ori r12, r12, lo16(target)
-  island->ori_r12_r12 = 0x618c;
-  island->lo_addr     = target & 0xffff;
+  extra->jumpIsland.ori_r12_r12 = 0x618c;
+  extra->jumpIsland.lo_addr     = target & 0xffff;
 
   // mtctr r12
-  island->mtctr_r12   = 0x7d8903a6;
+  extra->jumpIsland.mtctr_r12   = 0x7d8903a6;
 
   // bctr
-  island->bctr        = 0x4e800420;
+  extra->jumpIsland.bctr        = 0x4e800420;
+#endif
+#ifdef x86_64_HOST_ARCH
+        // jmp *-14(%rip)
+  static uint8_t jmp[] = { 0xFF, 0x25, 0xF2, 0xFF, 0xFF, 0xFF };
+  extra->addr = target;
+  memcpy(extra->jumpIsland, jmp, 6);
+#endif
     
-  return (unsigned long) island;
+  return extra;
 }
 
+#endif
+
+/* --------------------------------------------------------------------------
+ * PowerPC specifics (instruction cache flushing)
+ * ------------------------------------------------------------------------*/
+
+#ifdef powerpc_TARGET_ARCH
 /*
    ocFlushInstructionCache
 
@@ -1709,7 +1645,7 @@ static unsigned long makeJumpIsland( ObjectCode* oc,
 
 static void ocFlushInstructionCache( ObjectCode *oc )
 {
-    int n = (oc->fileSize + sizeof( ppcJumpIsland ) * oc->n_islands + 3) / 4;
+    int n = (oc->fileSize + sizeof( SymbolExtra ) * oc->n_symbol_extras + 3) / 4;
     unsigned long *p = (unsigned long *) oc->image;
 
     while( n-- )
@@ -2501,14 +2437,14 @@ ocResolve_PEi386 ( ObjectCode* oc )
                    + sym->Value);
          } else {
             copyName ( sym->Name, strtab, symbol, 1000-1 );
-            (void*)S = lookupLocalSymbol( oc, symbol );
+            S = (UInt32) lookupLocalSymbol( oc, symbol );
             if ((void*)S != NULL) goto foundit;
-            (void*)S = lookupSymbol( symbol );
+            S = (UInt32) lookupSymbol( symbol );
             if ((void*)S != NULL) goto foundit;
             zapTrailingAtSign ( symbol );
-            (void*)S = lookupLocalSymbol( oc, symbol );
+            S = (UInt32) lookupLocalSymbol( oc, symbol );
             if ((void*)S != NULL) goto foundit;
-            (void*)S = lookupSymbol( symbol );
+            S = (UInt32) lookupSymbol( symbol );
             if ((void*)S != NULL) goto foundit;
            /* Newline first because the interactive linker has printed "linking..." */
             errorBelch("\n%s: unknown symbol `%s'", oc->fileName, symbol);
@@ -3292,7 +3228,6 @@ do_Elf_Rel_relocations ( ObjectCode* oc, char* ehdrC,
               S = (Elf_Addr)S_tmp;
             } else {
               stableVal = deRefStablePtr( stablePtr );
-              addRootObject((void*)P);
               S_tmp = stableVal;
               S = (Elf_Addr)S_tmp;
             }
@@ -3507,12 +3442,13 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
 
             if( delta << 6 >> 6 != delta )
             {
-               value = makeJumpIsland( oc, ELF_R_SYM(info), value );
+               value = (Elf_Addr) (&makeSymbolExtra( oc, ELF_R_SYM(info), value )
+                                        ->jumpIsland);
                delta = value - P;
 
                if( value == 0 || delta << 6 >> 6 != delta )
                {
-                  barf( "Unable to make ppcJumpIsland for #%d",
+                  barf( "Unable to make SymbolExtra for #%d",
                         ELF_R_SYM(info) );
                   return 0;
                }
@@ -3711,7 +3647,7 @@ ia64_reloc_pcrel21(Elf_Addr target, Elf_Addr value, ObjectCode *oc)
 
 #ifdef powerpc_HOST_ARCH
 
-static int ocAllocateJumpIslands_ELF( ObjectCode *oc )
+static int ocAllocateSymbolExtras_ELF( ObjectCode *oc )
 {
   Elf_Ehdr *ehdr;
   Elf_Shdr* shdr;
@@ -3738,7 +3674,7 @@ static int ocAllocateJumpIslands_ELF( ObjectCode *oc )
     return 0;
   }
 
-  return ocAllocateJumpIslands( oc, shdr[i].sh_size / sizeof( Elf_Sym ), 0 );
+  return ocAllocateSymbolExtras( oc, shdr[i].sh_size / sizeof( Elf_Sym ), 0 );
 }
 
 #endif /* powerpc */
@@ -3761,8 +3697,15 @@ static int ocAllocateJumpIslands_ELF( ObjectCode *oc )
   *) add still more sanity checks.
 */
 
+#if x86_64_HOST_ARCH || powerpc64_HOST_ARCH
+#define mach_header mach_header_64
+#define segment_command segment_command_64
+#define section section_64
+#define nlist nlist_64
+#endif
+
 #ifdef powerpc_HOST_ARCH
-static int ocAllocateJumpIslands_MachO(ObjectCode* oc)
+static int ocAllocateSymbolExtras_MachO(ObjectCode* oc)
 {
     struct mach_header *header = (struct mach_header *) oc->image;
     struct load_command *lc = (struct load_command *) (header + 1);
@@ -3797,20 +3740,52 @@ static int ocAllocateJumpIslands_MachO(ObjectCode* oc)
                 }
             }
             if(max >= min)
-                return ocAllocateJumpIslands(oc, max - min + 1, min);
+                return ocAllocateSymbolExtras(oc, max - min + 1, min);
 
             break;
         }
         
         lc = (struct load_command *) ( ((char *)lc) + lc->cmdsize );
     }
-    return ocAllocateJumpIslands(oc,0,0);
+    return ocAllocateSymbolExtras(oc,0,0);
 }
 #endif
+#ifdef x86_64_HOST_ARCH
+static int ocAllocateSymbolExtras_MachO(ObjectCode* oc)
+{
+    struct mach_header *header = (struct mach_header *) oc->image;
+    struct load_command *lc = (struct load_command *) (header + 1);
+    unsigned i;
 
-static int ocVerifyImage_MachO(ObjectCode* oc STG_UNUSED)
+    for( i = 0; i < header->ncmds; i++ )
+    {   
+        if( lc->cmd == LC_SYMTAB )
+        {
+                // Just allocate one entry for every symbol
+            struct symtab_command *symLC = (struct symtab_command *) lc;
+            
+            return ocAllocateSymbolExtras(oc, symLC->nsyms, 0);
+        }
+        
+        lc = (struct load_command *) ( ((char *)lc) + lc->cmdsize );
+    }
+    return ocAllocateSymbolExtras(oc,0,0);
+}
+#endif
+
+static int ocVerifyImage_MachO(ObjectCode* oc)
 {
-    // FIXME: do some verifying here
+    char *image = (char*) oc->image;
+    struct mach_header *header = (struct mach_header*) image;
+
+#if x86_64_TARGET_ARCH || powerpc64_TARGET_ARCH
+    if(header->magic != MH_MAGIC_64)
+        return 0;
+#else
+    if(header->magic != MH_MAGIC)
+        return 0;
+#endif
+    // FIXME: do some more verifying here
     return 1;
 }
 
@@ -3919,6 +3894,109 @@ static int relocateSection(
 
     for(i=0;i<n;i++)
     {
+#ifdef x86_64_HOST_ARCH
+        struct relocation_info *reloc = &relocs[i];
+        
+        char    *thingPtr = image + sect->offset + reloc->r_address;
+        uint64_t thing;
+        uint64_t value;
+        uint64_t baseValue;
+        int type = reloc->r_type;
+        
+        checkProddableBlock(oc,thingPtr);
+        switch(reloc->r_length)
+        {
+            case 0:
+                thing = *(uint8_t*)thingPtr;
+                baseValue = (uint64_t)thingPtr + 1;
+                break;
+            case 1:
+                thing = *(uint16_t*)thingPtr;
+                baseValue = (uint64_t)thingPtr + 2;
+                break;
+            case 2:
+                thing = *(uint32_t*)thingPtr;
+                baseValue = (uint64_t)thingPtr + 4;
+                break;
+            case 3:
+                thing = *(uint64_t*)thingPtr;
+                baseValue = (uint64_t)thingPtr + 8;
+                break;
+            default:
+                barf("Unknown size.");
+        }
+        
+        if(type == X86_64_RELOC_GOT
+           || type == X86_64_RELOC_GOT_LOAD)
+        {
+            ASSERT(reloc->r_extern);
+            value = (uint64_t) &makeSymbolExtra(oc, reloc->r_symbolnum, value)->addr;
+            
+            type = X86_64_RELOC_SIGNED;
+        }
+        else if(reloc->r_extern)
+        {
+            struct nlist *symbol = &nlist[reloc->r_symbolnum];
+            char *nm = image + symLC->stroff + symbol->n_un.n_strx;
+            if(symbol->n_value == 0)
+                value = (uint64_t) lookupSymbol(nm);
+            else
+                value = relocateAddress(oc, nSections, sections,
+                                        symbol->n_value);
+        }
+        else
+        {
+            value = sections[reloc->r_symbolnum-1].offset
+                  - sections[reloc->r_symbolnum-1].addr
+                 + (uint64_t) image;
+        }
+        
+        if(type == X86_64_RELOC_BRANCH)
+        {
+            if((int32_t)(value - baseValue) != (int64_t)(value - baseValue))
+            {
+                ASSERT(reloc->r_extern);
+                value = (uint64_t) &makeSymbolExtra(oc, reloc->r_symbolnum, value)
+                                        -> jumpIsland;
+            }
+            ASSERT((int32_t)(value - baseValue) == (int64_t)(value - baseValue));
+            type = X86_64_RELOC_SIGNED;
+        }
+        
+        switch(type)
+        {
+            case X86_64_RELOC_UNSIGNED:
+                ASSERT(!reloc->r_pcrel);
+                thing += value;
+                break;
+            case X86_64_RELOC_SIGNED:
+                ASSERT(reloc->r_pcrel);
+                thing += value - baseValue;
+                break;
+            case X86_64_RELOC_SUBTRACTOR:
+                ASSERT(!reloc->r_pcrel);
+                thing -= value;
+                break;
+            default:
+                barf("unkown relocation");
+        }
+                
+        switch(reloc->r_length)
+        {
+            case 0:
+                *(uint8_t*)thingPtr = thing;
+                break;
+            case 1:
+                *(uint16_t*)thingPtr = thing;
+                break;
+            case 2:
+                *(uint32_t*)thingPtr = thing;
+                break;
+            case 3:
+                *(uint64_t*)thingPtr = thing;
+                break;
+        }
+#else
        if(relocs[i].r_address & R_SCATTERED)
        {
            struct scattered_relocation_info *scat =
@@ -4117,7 +4195,11 @@ static int relocateSection(
                             // In the .o file, this should be a relative jump to NULL
                             // and we'll change it to a relative jump to the symbol
                         ASSERT(-word == reloc->r_address);
-                        jumpIsland = makeJumpIsland(oc,reloc->r_symbolnum,(unsigned long) symbolAddress);
+                        jumpIsland = (unsigned long)
+                                        &makeSymbolExtra(oc,
+                                                         reloc->r_symbolnum,
+                                                         (unsigned long) symbolAddress)
+                                         -> jumpIsland;
                         if(jumpIsland != 0)
                         {
                             offsetToJumpIsland = word + jumpIsland
@@ -4180,6 +4262,7 @@ static int relocateSection(
            barf("\nunknown relocation %d",reloc->r_type);
            return 0;
        }
+#endif
     }
     return 1;
 }
@@ -4200,7 +4283,7 @@ static int ocGetNames_MachO(ObjectCode* oc)
 
     for(i=0;i<header->ncmds;i++)
     {
-       if(lc->cmd == LC_SEGMENT)
+       if(lc->cmd == LC_SEGMENT || lc->cmd == LC_SEGMENT_64)
            segLC = (struct segment_command*) lc;
        else if(lc->cmd == LC_SYMTAB)
            symLC = (struct symtab_command*) lc;
@@ -4210,6 +4293,9 @@ static int ocGetNames_MachO(ObjectCode* oc)
     sections = (struct section*) (segLC+1);
     nlist = symLC ? (struct nlist*) (image + symLC->symoff)
                   : NULL;
+    
+    if(!segLC)
+        barf("ocGetNames_MachO: no segment load command");
 
     for(i=0;i<segLC->nsects;i++)
     {
@@ -4280,21 +4366,17 @@ static int ocGetNames_MachO(ObjectCode* oc)
                 if(nlist[i].n_type & N_EXT)
                 {
                     char *nm = image + symLC->stroff + nlist[i].n_un.n_strx;
-                    ghciInsertStrHashTable(oc->fileName, symhash, nm,
-                                            image
-                                            + sections[nlist[i].n_sect-1].offset
-                                            - sections[nlist[i].n_sect-1].addr
-                                            + nlist[i].n_value);
-                    oc->symbols[curSymbol++] = nm;
-                }
-                else
-                {
-                    char *nm = image + symLC->stroff + nlist[i].n_un.n_strx;
-                    ghciInsertStrHashTable(oc->fileName, oc->lochash, nm,
-                                            image
-                                            + sections[nlist[i].n_sect-1].offset
-                                            - sections[nlist[i].n_sect-1].addr
-                                            + nlist[i].n_value);
+                    if((nlist[i].n_desc & N_WEAK_DEF) && lookupSymbol(nm))
+                        ; // weak definition, and we already have a definition
+                    else
+                    {
+                            ghciInsertStrHashTable(oc->fileName, symhash, nm,
+                                                    image
+                                                    + sections[nlist[i].n_sect-1].offset
+                                                    - sections[nlist[i].n_sect-1].addr
+                                                    + nlist[i].n_value);
+                            oc->symbols[curSymbol++] = nm;
+                    }
                 }
             }
         }
@@ -4339,7 +4421,7 @@ static int ocResolve_MachO(ObjectCode* oc)
 
     for(i=0;i<header->ncmds;i++)
     {
-       if(lc->cmd == LC_SEGMENT)
+       if(lc->cmd == LC_SEGMENT || lc->cmd == LC_SEGMENT_64)
            segLC = (struct segment_command*) lc;
        else if(lc->cmd == LC_SYMTAB)
            symLC = (struct symtab_command*) lc;
@@ -4443,9 +4525,14 @@ static int machoGetMisalignment( FILE * f )
     fread(&header, sizeof(header), 1, f);
     rewind(f);
 
+#if x86_64_TARGET_ARCH || powerpc64_TARGET_ARCH
+    if(header.magic != MH_MAGIC_64)
+        return 0;
+#else
     if(header.magic != MH_MAGIC)
         return 0;
-    
+#endif
+
     misalignment = (header.sizeofcmds + sizeof(header))
                     & 0xF;
 
@@ -4453,3 +4540,4 @@ static int machoGetMisalignment( FILE * f )
 }
 
 #endif
+