[project @ 2005-03-02 10:00:36 by simonmar]
[ghc-hetmet.git] / ghc / rts / Linker.c
index 4a2a51b..5ea9d4e 100644 (file)
@@ -10,7 +10,9 @@
 #include "PosixSource.h"
 #endif
 
-//  Linux needs _GNU_SOURCE to get RTLD_DEFAULT from <dlfcn.h>.
+/* Linux needs _GNU_SOURCE to get RTLD_DEFAULT from <dlfcn.h> and 
+   MREMAP_MAYMOVE from <sys/mman.h>.
+ */
 #ifdef __linux__
 #define _GNU_SOURCE
 #endif
@@ -528,6 +530,7 @@ typedef struct _RtsSymbolVal {
       SymX(stg_IND_STATIC_info)                        \
       SymX(stg_INTLIKE_closure)                        \
       SymX(stg_MUT_ARR_PTRS_FROZEN_info)       \
+      SymX(stg_MUT_ARR_PTRS_FROZEN0_info)      \
       SymX(stg_WEAK_info)                       \
       SymX(stg_ap_0_info)                      \
       SymX(stg_ap_v_info)                      \
@@ -1306,21 +1309,51 @@ static void addSection ( ObjectCode* oc, SectionKind kind,
 
 static int ocAllocateJumpIslands( ObjectCode* oc, int count, int first )
 {
+#ifdef USE_MMAP
+  int pagesize, n, m;
+#endif
   int aligned;
 
   if( count > 0 )
   {
-#ifdef USE_MMAP
-    #error ocAllocateJumpIslands doesnt want USE_MMAP to be defined
-#endif
     // round up to the nearest 4
     aligned = (oc->fileSize + 3) & ~3;
 
+#ifdef USE_MMAP
+    #ifndef linux_HOST_OS /* mremap is a linux extension */
+        #error ocAllocateJumpIslands doesnt want USE_MMAP to be defined
+    #endif
+
+    pagesize = getpagesize();
+    n = ROUND_UP( oc->fileSize, pagesize );
+    m = ROUND_UP( aligned + sizeof (ppcJumpIsland) * count, pagesize );
+
+    /* 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.
+     */
+    if( (oc->image = mremap( oc->image, n, m, MREMAP_MAYMOVE )) == 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;
+    }
+
+#else
     oc->image = stgReallocBytes( oc->image,
-                                 aligned + sizeof( ppcJumpIsland ) * count,
+                                 aligned + sizeof (ppcJumpIsland) * count,
                                  "ocAllocateJumpIslands" );
-    oc->jump_islands = (ppcJumpIsland *) (((char *) oc->image) + aligned);
-    memset( oc->jump_islands, 0, sizeof( ppcJumpIsland ) * count );
+#endif /* USE_MMAP */
+
+    oc->jump_islands = (ppcJumpIsland *) (oc->image + aligned);
+    memset( oc->jump_islands, 0, sizeof (ppcJumpIsland) * count );
   }
   else
     oc->jump_islands = NULL;
@@ -2408,6 +2441,65 @@ findElfSection ( void* objImage, Elf_Word sh_type )
    return ptr;
 }
 
+static int
+findElfSectionIndexByName( ObjectCode *oc, const char *sh_name,
+                           Elf_Word expected_type, Elf_Word expected_entsize )
+{
+  Elf_Ehdr *ehdr = (Elf_Ehdr *) oc->image;
+  Elf_Shdr *shdr = (Elf_Shdr *) (oc->image + ehdr->e_shoff);
+  char *sectnames = oc->image + shdr[ehdr->e_shstrndx].sh_offset;
+  int i;
+
+  for( i = 0; i < ehdr->e_shnum; i++ )
+    if( !strcmp( sectnames + shdr[i].sh_name, sh_name ) )
+    {
+      if( shdr[i].sh_type != expected_type )
+      {
+        errorBelch( "The entry type (%d) of the '%s' section isn't %d\n",
+                    shdr[i].sh_type, sh_name, expected_type );
+        return -1;
+      }
+
+      if( shdr[i].sh_entsize != expected_entsize )
+      {
+        errorBelch( "The entry size (%d) of the '%s' section isn't %d\n",
+                    shdr[i].sh_entsize, sh_name, expected_entsize );
+
+        return -1;
+      }
+
+      return i;
+    }
+
+  errorBelch( "This ELF file contains no '%s' section", sh_name );
+  return -1;
+}
+
+static char *
+findElfSectionByName( ObjectCode *oc, const char *sh_name,
+                      Elf_Word expected_type, int expected_entsize,
+                      int *num_entries )
+{
+  Elf_Ehdr *ehdr = (Elf_Ehdr *) oc->image;
+  Elf_Shdr *shdr = (Elf_Shdr *) (oc->image + ehdr->e_shoff);
+  int section;
+
+  section = findElfSectionIndexByName( oc, sh_name, expected_type,
+                                       expected_entsize );
+
+  if( section < 0 )
+    return NULL;
+
+  /* allow for meaningful results in num_entries even when entsize is 0 */
+  if( expected_entsize == 0 )
+    expected_entsize = 1;
+
+  if( num_entries )
+    *num_entries = shdr[section].sh_size / expected_entsize;
+
+  return oc->image + shdr[section].sh_offset;
+}
+
 #if defined(ia64_HOST_ARCH)
 static Elf_Addr
 findElfSegment ( void* objImage, Elf_Addr vaddr )