[project @ 2005-10-12 02:12:34 by wolfgang]
[ghc-hetmet.git] / ghc / rts / Linker.c
index cb68522..f831c02 100644 (file)
@@ -117,6 +117,10 @@ static void machoInitSymbolsWithoutUnderscore( void );
 #endif
 #endif
 
+#if defined(x86_64_HOST_ARCH)
+static void*x86_64_high_symbol( char *lbl, void *addr );
+#endif
+
 /* -----------------------------------------------------------------------------
  * Built-in symbols from the RTS
  */
@@ -128,14 +132,11 @@ typedef struct _RtsSymbolVal {
 
 
 #if !defined(PAR)
-#define Maybe_ForeignObj        SymX(mkForeignObjzh_fast)
-
 #define Maybe_Stable_Names      SymX(mkWeakzh_fast)                    \
                                SymX(makeStableNamezh_fast)             \
                                SymX(finalizzeWeakzh_fast)
 #else
 /* These are not available in GUM!!! -- HWL */
-#define Maybe_ForeignObj
 #define Maybe_Stable_Names
 #endif
 
@@ -317,6 +318,56 @@ typedef struct _RtsSymbolVal {
       Sym(closedir)
 #endif
 
+#if defined(darwin_TARGET_OS) && HAVE_PRINTF_LDBLSTUB
+#define RTS_DARWIN_ONLY_SYMBOLS                        \
+     Sym(asprintf$LDBLStub)                     \
+     Sym(err$LDBLStub)                          \
+     Sym(errc$LDBLStub)                         \
+     Sym(errx$LDBLStub)                         \
+     Sym(fprintf$LDBLStub)                      \
+     Sym(fscanf$LDBLStub)                       \
+     Sym(fwprintf$LDBLStub)                     \
+     Sym(fwscanf$LDBLStub)                      \
+     Sym(printf$LDBLStub)                       \
+     Sym(scanf$LDBLStub)                        \
+     Sym(snprintf$LDBLStub)                     \
+     Sym(sprintf$LDBLStub)                      \
+     Sym(sscanf$LDBLStub)                       \
+     Sym(strtold$LDBLStub)                      \
+     Sym(swprintf$LDBLStub)                     \
+     Sym(swscanf$LDBLStub)                      \
+     Sym(syslog$LDBLStub)                       \
+     Sym(vasprintf$LDBLStub)                    \
+     Sym(verr$LDBLStub)                         \
+     Sym(verrc$LDBLStub)                        \
+     Sym(verrx$LDBLStub)                        \
+     Sym(vfprintf$LDBLStub)                     \
+     Sym(vfscanf$LDBLStub)                      \
+     Sym(vfwprintf$LDBLStub)                    \
+     Sym(vfwscanf$LDBLStub)                     \
+     Sym(vprintf$LDBLStub)                      \
+     Sym(vscanf$LDBLStub)                       \
+     Sym(vsnprintf$LDBLStub)                    \
+     Sym(vsprintf$LDBLStub)                     \
+     Sym(vsscanf$LDBLStub)                      \
+     Sym(vswprintf$LDBLStub)                    \
+     Sym(vswscanf$LDBLStub)                     \
+     Sym(vsyslog$LDBLStub)                      \
+     Sym(vwarn$LDBLStub)                        \
+     Sym(vwarnc$LDBLStub)                       \
+     Sym(vwarnx$LDBLStub)                       \
+     Sym(vwprintf$LDBLStub)                     \
+     Sym(vwscanf$LDBLStub)                      \
+     Sym(warn$LDBLStub)                         \
+     Sym(warnc$LDBLStub)                        \
+     Sym(warnx$LDBLStub)                        \
+     Sym(wcstold$LDBLStub)                      \
+     Sym(wprintf$LDBLStub)                      \
+     Sym(wscanf$LDBLStub)
+#else
+#define RTS_DARWIN_ONLY_SYMBOLS
+#endif
+
 #ifndef SMP
 # define MAIN_CAP_SYM SymX(MainCapability)
 #else
@@ -355,7 +406,6 @@ typedef struct _RtsSymbolVal {
 #endif
 
 #define RTS_SYMBOLS                            \
-      Maybe_ForeignObj                         \
       Maybe_Stable_Names                       \
       Sym(StgReturn)                           \
       SymX(stg_enter_info)                     \
@@ -658,6 +708,7 @@ RTS_LONG_LONG_SYMS
 RTS_POSIX_ONLY_SYMBOLS
 RTS_MINGW_ONLY_SYMBOLS
 RTS_CYGWIN_ONLY_SYMBOLS
+RTS_DARWIN_ONLY_SYMBOLS
 RTS_LIBGCC_SYMBOLS
 #undef Sym
 #undef SymX
@@ -910,6 +961,16 @@ lookupSymbol( char *lbl )
 #      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)
+       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 /* not openbsd */
        return dlsym(dl_prog_handle, lbl);
 #      endif
@@ -1151,6 +1212,7 @@ loadObj( char *path )
     // 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
@@ -1367,6 +1429,10 @@ static int ocAllocateJumpIslands( ObjectCode* oc, int count, int first )
   int pagesize, n, m;
 #endif
   int aligned;
+  int misalignment = 0;
+#if darwin_HOST_OS
+  misalignment = oc->misalignment;
+#endif
 
   if( count > 0 )
   {
@@ -1401,9 +1467,12 @@ static int ocAllocateJumpIslands( ObjectCode* oc, int count, int first )
     }
 
 #else
+    oc->image -= misalignment;
     oc->image = stgReallocBytes( oc->image,
+                                 misalignment + 
                                  aligned + sizeof (ppcJumpIsland) * count,
                                  "ocAllocateJumpIslands" );
+    oc->image += misalignment;
 #endif /* USE_MMAP */
 
     oc->jump_islands = (ppcJumpIsland *) (oc->image + aligned);
@@ -2484,6 +2553,64 @@ 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|MAP_32BIT|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
  */
@@ -3174,20 +3301,35 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
             break;
 #        endif
 
-#if x86_64_HOST_OS
+#if x86_64_HOST_ARCH
       case R_X86_64_64:
          *(Elf64_Xword *)P = value;
          break;
 
       case R_X86_64_PC32:
-         *(Elf64_Word *)P = (Elf64_Word) (value - P);
+      {
+         StgInt64 off = value - P;
+         if (off >= 0x7fffffffL || off < -0x80000000L) {
+             barf("R_X86_64_PC32 relocation out of range: %s = %p",
+                  symbol, off);
+         }
+         *(Elf64_Word *)P = (Elf64_Word)off;
          break;
+      }
 
       case R_X86_64_32:
+         if (value >= 0x7fffffffL) {
+             barf("R_X86_64_32 relocation out of range: %s = %p\n",
+                  symbol, value);
+         }
          *(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);
+         }
          *(Elf64_Sword *)P = (Elf64_Sword)value;
          break;
 #endif