add readTVarIO :: TVar a -> IO a
[ghc-hetmet.git] / rts / Linker.c
index e86efd3..0b556b7 100644 (file)
@@ -27,6 +27,7 @@
 #include "Schedule.h"
 #include "Sparks.h"
 #include "RtsTypeable.h"
+#include "Timer.h"
 
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #include <sys/wait.h>
 #endif
 
-#if defined(ia64_HOST_ARCH) || defined(openbsd_HOST_OS) || defined(linux_HOST_OS) || defined(freebsd_HOST_OS)
+#if defined(ia64_HOST_ARCH) || defined(linux_HOST_OS) || defined(freebsd_HOST_OS) || defined(netbsd_HOST_OS) || defined(openbsd_HOST_OS)
 #define USE_MMAP
 #include <fcntl.h>
 #include <sys/mman.h>
 
-#if defined(openbsd_HOST_OS) || defined(linux_HOST_OS) || defined(freebsd_HOST_OS)
+#if defined(linux_HOST_OS) || defined(freebsd_HOST_OS) || defined(netbsd_HOST_OS) || defined(openbsd_HOST_OS)
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
@@ -107,7 +108,7 @@ ObjectCode *objects = NULL; /* initially empty */
 static int ocVerifyImage_ELF    ( ObjectCode* oc );
 static int ocGetNames_ELF       ( ObjectCode* oc );
 static int ocResolve_ELF        ( ObjectCode* oc );
-#if defined(powerpc_HOST_ARCH)
+#if defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH)
 static int ocAllocateSymbolExtras_ELF ( ObjectCode* oc );
 #endif
 #elif defined(OBJFORMAT_PEi386)
@@ -128,9 +129,30 @@ static void machoInitSymbolsWithoutUnderscore( void );
 #endif
 #endif
 
-#if defined(x86_64_HOST_ARCH) && defined(OBJFORMAT_ELF)
-static void*x86_64_high_symbol( char *lbl, void *addr );
-#endif
+/* on x86_64 we have a problem with relocating symbol references in
+ * code that was compiled without -fPIC.  By default, the small memory
+ * model is used, which assumes that symbol references can fit in a
+ * 32-bit slot.  The system dynamic linker makes this work for
+ * references to shared libraries by either (a) allocating a jump
+ * table slot for code references, or (b) moving the symbol at load
+ * time (and copying its contents, if necessary) for data references.
+ *
+ * We unfortunately can't tell whether symbol references are to code
+ * or data.  So for now we assume they are code (the vast majority
+ * are), and allocate jump-table slots.  Unfortunately this will
+ * SILENTLY generate crashing code for data references.  This hack is
+ * enabled by X86_64_ELF_NONPIC_HACK.
+ * 
+ * One workaround is to use shared Haskell libraries.  This is
+ * coming.  Another workaround is to keep the static libraries but
+ * compile them with -fPIC, because that will generate PIC references
+ * to data which can be relocated.  The PIC code is still too green to
+ * do this systematically, though.
+ *
+ * See bug #781
+ * See thread http://www.haskell.org/pipermail/cvs-ghc/2007-September/038458.html
+ */
+#define X86_64_ELF_NONPIC_HACK 1
 
 /* -----------------------------------------------------------------------------
  * Built-in symbols from the RTS
@@ -153,6 +175,9 @@ typedef struct _RtsSymbolVal {
 
 #if !defined (mingw32_HOST_OS)
 #define RTS_POSIX_ONLY_SYMBOLS                  \
+      SymX(shutdownHaskellAndSignal)           \
+      Sym(lockFile)                             \
+      Sym(unlockFile)                           \
       SymX(signal_handlers)                    \
       SymX(stg_sig_install)                    \
       Sym(nocldstop)
@@ -418,6 +443,22 @@ typedef struct _RtsSymbolVal {
    SymX(console_handler)
 #endif
 
+#define RTS_LIBFFI_SYMBOLS                      \
+     Sym(ffi_prep_cif)                          \
+     Sym(ffi_call)                              \
+     Sym(ffi_type_void)                         \
+     Sym(ffi_type_float)                        \
+     Sym(ffi_type_double)                       \
+     Sym(ffi_type_sint64)                       \
+     Sym(ffi_type_uint64)                       \
+     Sym(ffi_type_sint32)                       \
+     Sym(ffi_type_uint32)                       \
+     Sym(ffi_type_sint16)                       \
+     Sym(ffi_type_uint16)                       \
+     Sym(ffi_type_sint8)                        \
+     Sym(ffi_type_uint8)                        \
+     Sym(ffi_type_pointer)
+
 #ifdef TABLES_NEXT_TO_CODE
 #define RTS_RET_SYMBOLS /* nothing */
 #else
@@ -440,9 +481,26 @@ typedef struct _RtsSymbolVal {
       SymX(stg_ap_pppppp_ret)
 #endif
 
+/* On Windows, we link libgmp.a statically into libHSrts.dll */
+#ifdef mingw32_HOST_OS
+#define GMP_SYMS                               \
+      SymX(__gmpz_cmp)                         \
+      SymX(__gmpz_cmp_si)                      \
+      SymX(__gmpz_cmp_ui)                      \
+      SymX(__gmpz_get_si)                      \
+      SymX(__gmpz_get_ui)
+#else
+#define GMP_SYMS                               \
+      SymExtern(__gmpz_cmp)                    \
+      SymExtern(__gmpz_cmp_si)                 \
+      SymExtern(__gmpz_cmp_ui)                 \
+      SymExtern(__gmpz_get_si)                 \
+      SymExtern(__gmpz_get_ui)
+#endif
+
 #define RTS_SYMBOLS                            \
       Maybe_Stable_Names                       \
-      Sym(StgReturn)                           \
+      SymX(StgReturn)                          \
       SymX(stg_enter_info)                     \
       SymX(stg_gc_void_info)                   \
       SymX(__stg_gc_enter_1)                   \
@@ -479,19 +537,18 @@ typedef struct _RtsSymbolVal {
       SymX(__encodeDouble)                     \
       SymX(__encodeFloat)                      \
       SymX(addDLL)                             \
-      SymExtern(__gmpn_gcd_1)                  \
-      SymExtern(__gmpz_cmp)                    \
-      SymExtern(__gmpz_cmp_si)                 \
-      SymExtern(__gmpz_cmp_ui)                 \
-      SymExtern(__gmpz_get_si)                 \
-      SymExtern(__gmpz_get_ui)                 \
+      GMP_SYMS                                 \
       SymX(__int_encodeDouble)                 \
+      SymX(__word_encodeDouble)                        \
+      SymX(__2Int_encodeDouble)                        \
       SymX(__int_encodeFloat)                  \
+      SymX(__word_encodeFloat)                 \
       SymX(andIntegerzh_fast)                  \
       SymX(atomicallyzh_fast)                  \
       SymX(barf)                               \
       SymX(debugBelch)                         \
       SymX(errorBelch)                         \
+      SymX(asyncExceptionsBlockedzh_fast)      \
       SymX(blockAsyncExceptionszh_fast)                \
       SymX(catchzh_fast)                       \
       SymX(catchRetryzh_fast)                  \
@@ -505,6 +562,8 @@ typedef struct _RtsSymbolVal {
       SymX(createAdjustor)                     \
       SymX(decodeDoublezh_fast)                        \
       SymX(decodeFloatzh_fast)                 \
+      SymX(decodeDoublezu2Intzh_fast)                  \
+      SymX(decodeFloatzuIntzh_fast)                    \
       SymX(defaultsHook)                       \
       SymX(delayzh_fast)                       \
       SymX(deRefWeakzh_fast)                   \
@@ -584,6 +643,7 @@ typedef struct _RtsSymbolVal {
       SymX(raisezh_fast)                       \
       SymX(raiseIOzh_fast)                     \
       SymX(readTVarzh_fast)                    \
+      SymX(readTVarIOzh_fast)                  \
       SymX(remIntegerzh_fast)                  \
       SymX(resetNonBlockingFd)                 \
       SymX(resumeThread)                       \
@@ -645,6 +705,7 @@ typedef struct _RtsSymbolVal {
       SymX(stackOverflow)                      \
       SymX(stg_CAF_BLACKHOLE_info)             \
       SymX(awakenBlockedQueue)                 \
+      SymX(startTimer)                          \
       SymX(stg_CHARLIKE_closure)               \
       SymX(stg_MVAR_CLEAN_info)                        \
       SymX(stg_MVAR_DIRTY_info)                        \
@@ -710,6 +771,7 @@ typedef struct _RtsSymbolVal {
       SymX(stg_upd_frame_info)                 \
       SymX(suspendThread)                      \
       SymX(takeMVarzh_fast)                    \
+      SymX(threadStatuszh_fast)                        \
       SymX(timesIntegerzh_fast)                        \
       SymX(tryPutMVarzh_fast)                  \
       SymX(tryTakeMVarzh_fast)                 \
@@ -722,15 +784,15 @@ typedef struct _RtsSymbolVal {
       SymX(writeTVarzh_fast)                   \
       SymX(xorIntegerzh_fast)                  \
       SymX(yieldzh_fast)                        \
-      SymX(stg_interp_constr_entry)             \
+      Sym(stg_interp_constr_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)              \
+      Sym(rts_breakpoint_io_action)            \
+      Sym(rts_stop_next_breakpoint)            \
+      Sym(rts_stop_on_exception)               \
       SymX(stopTimer)                          \
       SymX(n_capabilities)                     \
       RTS_USER_SIGNALS_SYMBOLS
@@ -793,6 +855,7 @@ RTS_MINGW_ONLY_SYMBOLS
 RTS_CYGWIN_ONLY_SYMBOLS
 RTS_DARWIN_ONLY_SYMBOLS
 RTS_LIBGCC_SYMBOLS
+RTS_LIBFFI_SYMBOLS
 #undef Sym
 #undef SymX
 #undef SymX_redirect
@@ -825,6 +888,7 @@ static RtsSymbolVal rtsSyms[] = {
       RTS_CYGWIN_ONLY_SYMBOLS
       RTS_DARWIN_ONLY_SYMBOLS
       RTS_LIBGCC_SYMBOLS
+      RTS_LIBFFI_SYMBOLS
 #if defined(darwin_HOST_OS) && defined(i386_HOST_ARCH)
       // dyld stub code contains references to this,
       // but it should never be called because we treat
@@ -958,7 +1022,9 @@ addDLL( char *dll_name )
 
    initLinker();
 
-   hdl= dlopen(dll_name, RTLD_NOW | RTLD_GLOBAL);
+   // omitted: RTLD_NOW
+   // see http://www.haskell.org/pipermail/cvs-ghc/2007-September/038570.html
+   hdl= dlopen(dll_name, RTLD_LAZY | RTLD_GLOBAL);
 
    if (hdl == NULL) {
       /* dlopen failed; return a ptr to the error msg. */
@@ -1001,14 +1067,19 @@ addDLL( char *dll_name )
    sprintf(buf, "%s.DLL", dll_name);
    instance = LoadLibrary(buf);
    if (instance == NULL) {
-        sprintf(buf, "%s.DRV", dll_name);      // KAA: allow loading of drivers (like winspool.drv)
-        instance = LoadLibrary(buf);
-        if (instance == NULL) {
-               stgFree(buf);
-
-           /* LoadLibrary failed; return a ptr to the error msg. */
-           return "addDLL: unknown error";
-        }
+       if (GetLastError() != ERROR_MOD_NOT_FOUND) goto error;
+       // KAA: allow loading of drivers (like winspool.drv)
+       sprintf(buf, "%s.DRV", dll_name);
+       instance = LoadLibrary(buf);
+       if (instance == NULL) {
+           if (GetLastError() != ERROR_MOD_NOT_FOUND) goto error;
+           // #1883: allow loading of unix-style libfoo.dll DLLs
+           sprintf(buf, "lib%s.DLL", dll_name);
+           instance = LoadLibrary(buf);
+           if (instance == NULL) {
+               goto error;
+           }
+       }
    }
    stgFree(buf);
 
@@ -1021,6 +1092,14 @@ addDLL( char *dll_name )
    opened_dlls     = o_dll;
 
    return NULL;
+
+error:
+   stgFree(buf);
+   sysErrorBelch(dll_name);
+
+   /* LoadLibrary failed; return a ptr to the error msg. */
+   return "addDLL: could not load DLL";
+
 #  else
    barf("addDLL: not implemented on this platform");
 #  endif
@@ -1059,19 +1138,7 @@ lookupSymbol( char *lbl )
 
     if (val == NULL) {
 #       if defined(OBJFORMAT_ELF)
-#      if defined(x86_64_HOST_ARCH)
-       val = dlsym(dl_prog_handle, lbl);
-       if (val >= (void *)0x80000000) {
-           void *new_val;
-           new_val = x86_64_high_symbol(lbl, val);
-           IF_DEBUG(linker,debugBelch("lookupSymbol: relocating out of range symbol: %s = %p, now %p\n", lbl, val, new_val));
-           return new_val;
-       } else {
-           return val;
-       }
-#      else
        return dlsym(dl_prog_handle, lbl);
-#      endif
 #       elif defined(OBJFORMAT_MACHO)
 #       if HAVE_DLFCN_H
         /* On OS X 10.3 and later, we use dlsym instead of the old legacy
@@ -1125,23 +1192,6 @@ lookupSymbol( char *lbl )
     }
 }
 
-static
-__attribute((unused))
-void *
-lookupLocalSymbol( ObjectCode* oc, char *lbl )
-{
-    void *val;
-    initLinker() ;
-    val = lookupStrHashTable(oc->lochash, lbl);
-
-    if (val == NULL) {
-        return NULL;
-    } else {
-       return val;
-    }
-}
-
-
 /* -----------------------------------------------------------------------------
  * Debugging aid: look in GHCi's object symbol tables for symbols
  * within DELTA bytes of the specified address, and show their names.
@@ -1163,11 +1213,7 @@ void ghci_enquire ( char* addr )
       for (i = 0; i < oc->n_symbols; i++) {
          sym = oc->symbols[i];
          if (sym == NULL) continue;
-         // debugBelch("enquire %p %p\n", sym, oc->lochash);
          a = NULL;
-         if (oc->lochash != NULL) {
-            a = lookupStrHashTable(oc->lochash, sym);
-        }
          if (a == NULL) {
             a = lookupStrHashTable(symhash, sym);
         }
@@ -1252,7 +1298,6 @@ loadObj( char *path )
    oc->fileSize          = st.st_size;
    oc->symbols           = NULL;
    oc->sections          = NULL;
-   oc->lochash           = allocStrHashTable();
    oc->proddables        = NULL;
 
    /* chain it onto the list of objects */
@@ -1350,7 +1395,7 @@ loadObj( char *path )
 #  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)
+#  elif defined(OBJFORMAT_ELF) && (defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH))
    r = ocAllocateSymbolExtras_ELF ( oc );
    if (!r) { return r; }
 #endif
@@ -1461,9 +1506,6 @@ unloadObj( char *path )
            stgFree(oc->fileName);
            stgFree(oc->symbols);
            stgFree(oc->sections);
-           /* The local hash table should have been freed at the end
-               of the ocResolve_ call on it. */
-            ASSERT(oc->lochash == NULL);
            stgFree(oc);
            return 1;
        }
@@ -1532,8 +1574,7 @@ static void addSection ( ObjectCode* oc, SectionKind kind,
  * them right next to the object code itself.
  */
 
-#if defined(powerpc_HOST_ARCH) || (defined(x86_64_HOST_ARCH) \
-                                    && defined(darwin_TARGET_OS))
+#if defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH)
 
 /*
   ocAllocateSymbolExtras
@@ -1560,10 +1601,12 @@ static int ocAllocateSymbolExtras( ObjectCode* oc, int count, int first )
   int pagesize, n, m;
 #endif
   int aligned;
+#ifndef USE_MMAP
   int misalignment = 0;
-#if darwin_HOST_OS
+#ifdef darwin_HOST_OS
   misalignment = oc->misalignment;
 #endif
+#endif
 
   if( count > 0 )
   {
@@ -1571,47 +1614,36 @@ static int ocAllocateSymbolExtras( ObjectCode* oc, int count, int first )
     aligned = (oc->fileSize + 3) & ~3;
 
 #ifdef USE_MMAP
-    #ifndef linux_HOST_OS /* mremap is a linux extension */
-        #error ocAllocateSymbolExtras doesnt want USE_MMAP to be defined
-    #endif
-
     pagesize = getpagesize();
     n = ROUND_UP( oc->fileSize, 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.
-     * If, however, we map in 2 pages, the 2nd page is not accessible
-     * and will give a "Bus Error" on access.  To get around this, we check
-     * if we need any extra pages for the jump islands and map them in
-     * anonymously.  We must check that we actually require extra pages
-     * otherwise the attempt to mmap 0 pages of anonymous memory will
-     * fail -EINVAL.
+    /* we try to use spare space at the end of the last page of the
+     * image for the jump islands, but if there isn't enough space
+     * then we have to map some (anonymously, remembering MAP_32BIT).
      */
-
-    if( m > n )
+    if( m > n ) // we need to allocate more pages
     {
-      /* The effect of this mremap() call is only the ensure that we have
-       * a sufficient number of virtually contiguous pages.  As returned from
-       * mremap, the pages past the end of the file are not backed.  We give
-       * them a backing by using MAP_FIXED to map in anonymous pages.
-       */
-      oc->image = mremap( oc->image, n, m, MREMAP_MAYMOVE );
-
-      if( oc->image == MAP_FAILED )
-      {
-        errorBelch( "Unable to mremap for Jump Islands\n" );
-        return 0;
-      }
-
-      if( mmap( oc->image + n, m - n, PROT_READ | PROT_WRITE | PROT_EXEC,
-                MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 0, 0 ) == MAP_FAILED )
-      {
-        errorBelch( "Unable to mmap( MAP_FIXED ) for Jump Islands\n" );
-        return 0;
-      }
+        oc->symbol_extras = mmap (NULL, sizeof(SymbolExtra) * count,
+                                  PROT_EXEC|PROT_READ|PROT_WRITE,
+                                  MAP_PRIVATE|MAP_ANONYMOUS|EXTRA_MAP_FLAGS,
+                                  0, 0);
+        if (oc->symbol_extras == MAP_FAILED)
+        {
+            errorBelch( "Unable to mmap() for jump islands\n" );
+            return 0;
+        }
+#ifdef x86_64_HOST_ARCH
+        if ((StgWord)oc->symbol_extras > 0x80000000)
+        {
+            barf("mmap() returned memory outside 2Gb");
+        }
+#endif
+    }
+    else
+    {
+        oc->symbol_extras = (SymbolExtra *) (oc->image + aligned);
     }
-
 #else
     oc->image -= misalignment;
     oc->image = stgReallocBytes( oc->image,
@@ -1619,9 +1651,10 @@ static int ocAllocateSymbolExtras( ObjectCode* oc, int count, int first )
                                  aligned + sizeof (SymbolExtra) * count,
                                  "ocAllocateSymbolExtras" );
     oc->image += misalignment;
-#endif /* USE_MMAP */
 
     oc->symbol_extras = (SymbolExtra *) (oc->image + aligned);
+#endif /* USE_MMAP */
+
     memset( oc->symbol_extras, 0, sizeof (SymbolExtra) * count );
   }
   else
@@ -2261,6 +2294,8 @@ ocGetNames_PEi386 ( ObjectCode* oc )
           && 0 != strcmp(".ctors", sectab_i->Name)
           /* ignore section generated from .ident */
           && 0!= strcmp("/4", sectab_i->Name)
+         /* ignore unknown section that appeared in gcc 3.4.5(?) */
+          && 0!= strcmp(".reloc", sectab_i->Name)
          ) {
          errorBelch("Unknown PEi386 section name `%s' (while processing: %s)", sectab_i->Name, oc->fileName);
          return 0;
@@ -2478,13 +2513,9 @@ ocResolve_PEi386 ( ObjectCode* oc )
                    + sym->Value);
          } else {
             copyName ( sym->Name, strtab, symbol, 1000-1 );
-            S = (UInt32) lookupLocalSymbol( oc, symbol );
-            if ((void*)S != NULL) goto foundit;
             S = (UInt32) lookupSymbol( symbol );
             if ((void*)S != NULL) goto foundit;
             zapTrailingAtSign ( symbol );
-            S = (UInt32) lookupLocalSymbol( oc, symbol );
-            if ((void*)S != NULL) goto foundit;
             S = (UInt32) lookupSymbol( symbol );
             if ((void*)S != NULL) goto foundit;
            /* Newline first because the interactive linker has printed "linking..." */
@@ -2744,64 +2775,6 @@ PLTSize(void)
 #endif
 
 
-#if x86_64_HOST_ARCH
-// On x86_64, 32-bit relocations are often used, which requires that
-// we can resolve a symbol to a 32-bit offset.  However, shared
-// libraries are placed outside the 2Gb area, which leaves us with a
-// problem when we need to give a 32-bit offset to a symbol in a
-// shared library.
-// 
-// For a function symbol, we can allocate a bounce sequence inside the
-// 2Gb area and resolve the symbol to this.  The bounce sequence is
-// simply a long jump instruction to the real location of the symbol.
-//
-// For data references, we're screwed.
-//
-typedef struct {
-    unsigned char jmp[8];  /* 6 byte instruction: jmpq *0x00000002(%rip) */
-    void *addr;
-} x86_64_bounce;
-
-#define X86_64_BB_SIZE 1024
-
-static x86_64_bounce *x86_64_bounce_buffer = NULL;
-static nat x86_64_bb_next_off;
-
-static void*
-x86_64_high_symbol( char *lbl, void *addr )
-{
-    x86_64_bounce *bounce;
-
-    if ( x86_64_bounce_buffer == NULL || 
-        x86_64_bb_next_off >= X86_64_BB_SIZE ) {
-       x86_64_bounce_buffer = 
-           mmap(NULL, X86_64_BB_SIZE * sizeof(x86_64_bounce), 
-                PROT_EXEC|PROT_READ|PROT_WRITE, 
-                MAP_PRIVATE|EXTRA_MAP_FLAGS|MAP_ANONYMOUS, -1, 0);
-       if (x86_64_bounce_buffer == MAP_FAILED) {
-           barf("x86_64_high_symbol: mmap failed");
-       }
-       x86_64_bb_next_off = 0;
-    }
-    bounce = &x86_64_bounce_buffer[x86_64_bb_next_off];
-    bounce->jmp[0] = 0xff;
-    bounce->jmp[1] = 0x25;
-    bounce->jmp[2] = 0x02;
-    bounce->jmp[3] = 0x00;
-    bounce->jmp[4] = 0x00;
-    bounce->jmp[5] = 0x00;
-    bounce->addr = addr;
-    x86_64_bb_next_off++;
-
-    IF_DEBUG(linker, debugBelch("x86_64: allocated bounce entry for %s->%p at %p\n",
-                               lbl, addr, bounce));
-
-    insertStrHashTable(symhash, lbl, bounce);
-    return bounce;
-}
-#endif
-
-
 /*
  * Generic ELF functions
  */
@@ -2904,8 +2877,7 @@ ocVerifyImage_ELF ( ObjectCode* oc )
       case EM_PPC:   IF_DEBUG(linker,debugBelch( "powerpc32" )); break;
 #ifdef EM_X86_64
       case EM_X86_64: IF_DEBUG(linker,debugBelch( "x86_64" )); break;
-#endif
-#ifdef EM_AMD64
+#elif defined(EM_AMD64)
       case EM_AMD64: IF_DEBUG(linker,debugBelch( "amd64" )); break;
 #endif
       default:       IF_DEBUG(linker,debugBelch( "unknown" ));
@@ -3171,7 +3143,7 @@ ocGetNames_ELF ( ObjectCode* oc )
                if (ELF_ST_TYPE(stab[j].st_info) == STT_FUNC)
                    ad = (char *)allocateFunctionDesc((Elf_Addr)ad);
 #endif
-               IF_DEBUG(linker,debugBelch( "addOTabName(GLOB): %10p  %s %s",
+               IF_DEBUG(linker,debugBelch( "addOTabName(GLOB): %10p  %s %s\n",
                                       ad, oc->fileName, nm ));
                isLocal = FALSE;
             }
@@ -3518,9 +3490,15 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
       {
          StgInt64 off = value - P;
          if (off >= 0x7fffffffL || off < -0x80000000L) {
-             barf("R_X86_64_PC32 relocation out of range: %s = %p",
-                  symbol, off);
-         }
+#if X86_64_ELF_NONPIC_HACK
+             StgInt64 pltAddress = (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S)
+                                                -> jumpIsland;
+              off = pltAddress + A - P;
+#else
+              barf("R_X86_64_PC32 relocation out of range: %s = %p\nRecompile %s with -fPIC.",
+                   symbol, off, oc->fileName );
+#endif
+          }
          *(Elf64_Word *)P = (Elf64_Word)off;
          break;
       }
@@ -3534,19 +3512,51 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
 
       case R_X86_64_32:
          if (value >= 0x7fffffffL) {
-             barf("R_X86_64_32 relocation out of range: %s = %p\n",
-                  symbol, value);
-         }
+#if X86_64_ELF_NONPIC_HACK           
+              StgInt64 pltAddress = (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S)
+                                                -> jumpIsland;
+              value = pltAddress + A;
+#else
+              barf("R_X86_64_32 relocation out of range: %s = %p\nRecompile %s with -fPIC.",
+                  symbol, value, oc->fileName );
+#endif
+          }
          *(Elf64_Word *)P = (Elf64_Word)value;
          break;
 
       case R_X86_64_32S:
          if ((StgInt64)value > 0x7fffffffL || (StgInt64)value < -0x80000000L) {
-             barf("R_X86_64_32S relocation out of range: %s = %p\n",
-                  symbol, value);
+#if X86_64_ELF_NONPIC_HACK           
+              StgInt64 pltAddress = (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S)
+                                                -> jumpIsland;
+              value = pltAddress + A;
+#else
+              barf("R_X86_64_32S relocation out of range: %s = %p\nRecompile %s with -fPIC.",
+                  symbol, value, oc->fileName );
+#endif
          }
          *(Elf64_Sword *)P = (Elf64_Sword)value;
          break;
+         
+      case R_X86_64_GOTPCREL:
+      {
+          StgInt64 gotAddress = (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S)->addr;
+         StgInt64 off = gotAddress + A - P;
+         *(Elf64_Word *)P = (Elf64_Word)off;
+         break;
+      }
+      
+      case R_X86_64_PLT32:
+      {
+         StgInt64 off = value - P;
+         if (off >= 0x7fffffffL || off < -0x80000000L) {
+              StgInt64 pltAddress = (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S)
+                                                    -> jumpIsland;
+              off = pltAddress + A - P;
+         }
+         *(Elf64_Word *)P = (Elf64_Word)off;
+         break;
+      }
 #endif
 
          default:
@@ -3595,10 +3605,6 @@ ocResolve_ELF ( ObjectCode* oc )
       }
    }
 
-   /* Free the local symbol table; we won't need it again. */
-   freeHashTable(oc->lochash, NULL);
-   oc->lochash = NULL;
-
 #if defined(powerpc_HOST_ARCH)
    ocFlushInstructionCache( oc );
 #endif
@@ -3699,10 +3705,10 @@ ia64_reloc_pcrel21(Elf_Addr target, Elf_Addr value, ObjectCode *oc)
 #endif /* ia64 */
 
 /*
- * PowerPC ELF specifics
+ * PowerPC & X86_64 ELF specifics
  */
 
-#ifdef powerpc_HOST_ARCH
+#if defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH)
 
 static int ocAllocateSymbolExtras_ELF( ObjectCode *oc )
 {
@@ -3726,7 +3732,7 @@ static int ocAllocateSymbolExtras_ELF( ObjectCode *oc )
   if( shdr[i].sh_entsize != sizeof( Elf_Sym ) )
   {
     errorBelch( "The entry size (%d) of the symtab isn't %d\n",
-      shdr[i].sh_entsize, sizeof( Elf_Sym ) );
+      (int) shdr[i].sh_entsize, (int) sizeof( Elf_Sym ) );
     
     return 0;
   }
@@ -3877,8 +3883,6 @@ static int resolveImports(
        if((symbol->n_type & N_TYPE) == N_UNDF
            && (symbol->n_type & N_EXT) && (symbol->n_value != 0))
            addr = (void*) (symbol->n_value);
-       else if((addr = lookupLocalSymbol(oc,nm)) != NULL)
-           ;
        else
            addr = lookupSymbol(nm);
        if(!addr)
@@ -4525,10 +4529,6 @@ static int ocResolve_MachO(ObjectCode* oc)
            return 0;
     }
 
-    /* Free the local symbol table; we won't need it again. */
-    freeHashTable(oc->lochash, NULL);
-    oc->lochash = NULL;
-
 #if defined (powerpc_HOST_ARCH)
     ocFlushInstructionCache( oc );
 #endif