summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rts/CheckUnload.c14
-rw-r--r--rts/Linker.c893
-rw-r--r--rts/LinkerInternals.h40
-rw-r--r--testsuite/tests/ghci/linking/all.T2
-rw-r--r--testsuite/tests/rts/linker_error.c4
5 files changed, 689 insertions, 264 deletions
diff --git a/rts/CheckUnload.c b/rts/CheckUnload.c
index 7802754445..c75673847e 100644
--- a/rts/CheckUnload.c
+++ b/rts/CheckUnload.c
@@ -40,15 +40,21 @@
static void checkAddress (HashTable *addrs, void *addr)
{
ObjectCode *oc;
+ int i;
if (!lookupHashTable(addrs, (W_)addr)) {
insertHashTable(addrs, (W_)addr, addr);
for (oc = unloaded_objects; oc; oc = oc->next) {
- if ((W_)addr >= (W_)oc->image &&
- (W_)addr < (W_)oc->image + oc->fileSize) {
- oc->referenced = 1;
- break;
+ for (i = 0; i < oc->n_sections; i++) {
+ if (oc->sections[i].kind != SECTIONKIND_OTHER) {
+ if ((W_)addr >= (W_)oc->sections[i].start &&
+ (W_)addr < (W_)oc->sections[i].start
+ + oc->sections[i].size) {
+ oc->referenced = 1;
+ return;
+ }
+ }
}
}
}
diff --git a/rts/Linker.c b/rts/Linker.c
index 355b33a769..be5b3b815f 100644
--- a/rts/Linker.c
+++ b/rts/Linker.c
@@ -174,7 +174,7 @@ typedef void (*init_t) (int argc, char **argv, char **env);
static HsInt isAlreadyLoaded( pathchar *path );
static HsInt loadOc( ObjectCode* oc );
static ObjectCode* mkOc( pathchar *path, char *image, int imageSize,
- char *archiveMemberName
+ rtsBool mapped, char *archiveMemberName
#ifndef USE_MMAP
#ifdef darwin_HOST_OS
, int misalignment
@@ -219,7 +219,7 @@ static int ocVerifyImage_ELF ( ObjectCode* oc );
static int ocGetNames_ELF ( ObjectCode* oc );
static int ocResolve_ELF ( ObjectCode* oc );
static int ocRunInit_ELF ( ObjectCode* oc );
-#if defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH) || defined(arm_HOST_ARCH)
+#if NEED_SYMBOL_EXTRAS
static int ocAllocateSymbolExtras_ELF ( ObjectCode* oc );
#endif
#elif defined(OBJFORMAT_PEi386)
@@ -254,7 +254,7 @@ static int ocRunInit_MachO ( ObjectCode* oc );
#ifndef USE_MMAP
static int machoGetMisalignment( FILE * );
#endif
-#if defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH)
+#if NEED_SYMBOL_EXTRAS
static int ocAllocateSymbolExtras_MachO ( ObjectCode* oc );
#endif
#ifdef powerpc_HOST_ARCH
@@ -264,6 +264,34 @@ static void machoInitSymbolsWithoutUnderscore( void );
static void freeProddableBlocks (ObjectCode *oc);
+#ifdef USE_MMAP
+/**
+ * An allocated page being filled by the allocator
+ */
+struct m32_alloc_t {
+ void * base_addr; // Page address
+ unsigned int current_size; // Number of bytes already reserved
+};
+
+#define M32_MAX_PAGES 32
+
+/**
+ * Allocator
+ *
+ * Currently an allocator is just a set of pages being filled. The maximum
+ * number of pages can be configured with M32_MAX_PAGES.
+ */
+typedef struct m32_allocator_t {
+ struct m32_alloc_t pages[M32_MAX_PAGES];
+} * m32_allocator;
+
+// We use a global memory allocator
+static struct m32_allocator_t allocator;
+
+struct m32_allocator_t;
+static void m32_allocator_init(struct m32_allocator_t *m32);
+#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
@@ -1730,6 +1758,8 @@ initLinker_ (int retain_cafs)
addDLLHandle(WSTR("*.exe"), GetModuleHandle(NULL));
#endif
+ m32_allocator_init(&allocator);
+
IF_DEBUG(linker, debugBelch("initLinker: done\n"));
return;
}
@@ -2194,21 +2224,42 @@ void ghci_enquire ( char* addr )
#ifdef USE_MMAP
#define ROUND_UP(x,size) ((x + size - 1) & ~(size - 1))
+#define ROUND_DOWN(x,size) (x & ~(size - 1))
+
+static StgWord getPageSize(void)
+{
+ static StgWord pagesize = 0;
+ if (pagesize == 0) {
+ return sysconf(_SC_PAGESIZE);
+ } else {
+ return pagesize;
+ }
+}
+
+static StgWord roundUpToPage (StgWord size)
+{
+ return ROUND_UP(size, getPageSize());
+}
+
+#ifdef OBJFORMAT_ELF
+static StgWord roundDownToPage (StgWord size)
+{
+ return ROUND_DOWN(size, getPageSize());
+}
+#endif
//
// Returns NULL on failure.
//
-static void * mmapForLinker (size_t bytes, nat flags, int fd)
+static void * mmapForLinker (size_t bytes, nat flags, int fd, int offset)
{
void *map_addr = NULL;
void *result;
- int pagesize;
StgWord size;
static nat fixed = 0;
IF_DEBUG(linker, debugBelch("mmapForLinker: start\n"));
- pagesize = getpagesize();
- size = ROUND_UP(bytes, pagesize);
+ size = roundUpToPage(bytes);
#if !defined(ALWAYS_PIC) && defined(x86_64_HOST_ARCH)
mmap_again:
@@ -2227,7 +2278,7 @@ mmap_again:
result = mmap(map_addr, size,
PROT_EXEC|PROT_READ|PROT_WRITE,
- MAP_PRIVATE|TRY_MAP_32BIT|fixed|flags, fd, 0);
+ MAP_PRIVATE|TRY_MAP_32BIT|fixed|flags, fd, offset);
if (result == MAP_FAILED) {
sysErrorBelch("mmap %" FMT_Word " bytes at %p",(W_)size,map_addr);
@@ -2289,6 +2340,211 @@ mmap_again:
return result;
}
+
+/*
+
+Note [M32 Allocator]
+~~~~~~~~~~~~~~~~~~~~
+
+A memory allocator that allocates only pages in the 32-bit range (lower 2GB).
+This is useful on 64-bit platforms to ensure that addresses of allocated
+objects can be referenced with a 32-bit relative offset.
+
+Initially, the linker used `mmap` to allocate a page per object. Hence it
+wasted a lot of space for small objects (see #9314). With this allocator, we
+try to fill pages as much as we can for small objects.
+
+How does it work?
+-----------------
+
+For small objects, a Word64 counter is added at the beginning of the page they
+are stored in. It indicates the number of objects that are still alive in the
+page. When the counter drops down to zero, the page is freed. The counter is
+atomically decremented, hence the deallocation is thread-safe.
+
+During the allocation phase, the allocator keeps track of some pages that are
+not totally filled: the number of pages in the "filling" list is configurable
+with M32_MAX_PAGES. Allocation consists in finding some place in one of these
+pages or starting a new one, then increasing the page counter. If none of the
+pages in the "filling" list has enough free space, the most filled one is
+flushed (see below) and a new one is allocated.
+
+The allocator holds a reference on pages in the "filling" list: the counter in
+these pages is 1+n where n is the current number of objects allocated in the
+page. Hence allocated objects can be freed while the allocator is using
+(filling) the page. Flushing a page consists in decreasing its counter and
+removing it from the "filling" list. By extension, flushing the allocator
+consists in flushing all the pages in the "filling" list. Don't forget to
+flush the allocator at the end of the allocation phase in order to avoid space
+leaks!
+
+Large objects are objects that are larger than a page (minus the bytes required
+for the counter and the optional padding). These objects are allocated into
+their own set of pages. We can differentiate large and small objects from
+their address: large objects are aligned on page size while small objects never
+are (because of the space reserved for the page's object counter).
+
+For large objects, the remaining space at the end of the last page is left
+unused by the allocator. It can be used with care as it will be freed with the
+associated large object. GHC linker uses this feature/hack, hence changing the
+implementation of the M32 allocator must be done with care (i.e. do not try to
+improve the allocator to avoid wasting this space without modifying the linker
+code accordingly).
+
+Object allocation is *not* thread-safe (however it could be done easily with a
+lock in the allocator structure). Object deallocation is thread-safe.
+
+*/
+
+/****************************************************************************
+ * M32 ALLOCATOR (see Note [M32 Allocator]
+ ***************************************************************************/
+
+/**
+ * Wrapper for `unmap` that handles error cases.
+ */
+static void munmapForLinker (void * addr, size_t size)
+{
+ int r = munmap(addr,size);
+ if (r == -1) {
+ // Should we abort here?
+ sysErrorBelch("munmap");
+ }
+}
+
+/**
+ * Initialize the allocator structure
+ */
+static void m32_allocator_init(m32_allocator m32) {
+ memset(m32, 0, sizeof(struct m32_allocator_t));
+}
+
+/**
+ * Atomically decrement the object counter on the given page and release the
+ * page if necessary. The given address must be the *base address* of the page.
+ *
+ * You shouldn't have to use this method. Use `m32_free` instead.
+ */
+static void m32_free_internal(void * addr) {
+ uint64_t c = __sync_sub_and_fetch((uint64_t*)addr, 1);
+ if (c == 0) {
+ munmapForLinker(addr, getPageSize());
+ }
+}
+
+/**
+ * Release the allocator's reference to pages on the "filling" list. This
+ * should be called when it is believed that no more allocations will be needed
+ * from the allocator to ensure that empty pages waiting to be filled aren't
+ * unnecessarily held.
+ */
+static void m32_allocator_flush(m32_allocator m32) {
+ int i;
+ for (i=0; i<M32_MAX_PAGES; i++) {
+ void * addr = __sync_fetch_and_and(&m32->pages[i].base_addr, 0x0);
+ if (addr != 0) {
+ m32_free_internal(addr);
+ }
+ }
+}
+
+// Return true if the object has its own dedicated set of pages
+#define m32_is_large_object(size,alignment) \
+ (size >= getPageSize() - ROUND_UP(8,alignment))
+
+// Return true if the object has its own dedicated set of pages
+#define m32_is_large_object_addr(addr) \
+ ((uintptr_t) addr % getPageSize() == 0)
+
+/**
+ * Free the memory associated with an object.
+ *
+ * If the object is "small", the object counter of the page it is allocated in
+ * is decremented and the page is not freed until all of its objects are freed.
+ */
+static void m32_free(void *addr, unsigned int size) {
+ uintptr_t m = (uintptr_t) addr % getPageSize();
+
+ if (m == 0) {
+ // large object
+ munmapForLinker(addr,ROUND_UP(size,getPageSize()));
+ }
+ else {
+ // small object
+ void * page_addr = (void*)((uintptr_t)addr - m);
+ m32_free_internal(page_addr);
+ }
+}
+
+/**
+ * Allocate `size` bytes of memory with the given alignment
+ */
+static void *
+m32_alloc(m32_allocator m32, unsigned int size,
+ unsigned int alignment) {
+
+ unsigned int pgsz = (unsigned int)getPageSize();
+
+ if (m32_is_large_object(size,alignment)) {
+ // large object
+ return mmapForLinker(size,MAP_ANONYMOUS,-1,0);
+ }
+ else {
+ // small object
+ // Try to find a page that can contain it
+ int empty = -1;
+ int most_filled = -1;
+ int i;
+ for (i=0; i<M32_MAX_PAGES; i++) {
+ // empty page
+ if (m32->pages[i].base_addr == 0) {
+ empty = empty == -1 ? i : empty;
+ continue;
+ }
+ // page can contain the buffer?
+ unsigned int alsize = ROUND_UP(m32->pages[i].current_size, alignment);
+ if (size <= pgsz - alsize) {
+ void * addr = (char*)m32->pages[i].base_addr + alsize;
+ m32->pages[i].current_size = alsize + size;
+ // increment the counter atomically
+ __sync_fetch_and_add((uint64_t*)m32->pages[i].base_addr, 1);
+ return addr;
+ }
+ // most filled?
+ if (most_filled == -1
+ || m32->pages[most_filled].current_size < m32->pages[i].current_size)
+ {
+ most_filled = i;
+ }
+ }
+
+ // If we haven't found an empty page, flush the most filled one
+ if (empty == -1) {
+ m32_free_internal(m32->pages[most_filled].base_addr);
+ m32->pages[most_filled].base_addr = 0;
+ m32->pages[most_filled].current_size = 0;
+ empty = most_filled;
+ }
+
+ // Allocate a new page
+ void * addr = mmapForLinker(pgsz,MAP_ANONYMOUS,-1,0);
+ if (addr == NULL) {
+ return NULL;
+ }
+ m32->pages[empty].base_addr = addr;
+ // Add 8 bytes for the counter + padding
+ m32->pages[empty].current_size = size+ROUND_UP(8,alignment);
+ // Initialize the counter:
+ // 1 for the allocator + 1 for the returned allocated memory
+ *((uint64_t*)addr) = 2;
+ return (char*)addr + ROUND_UP(8,alignment);
+ }
+}
+
+/****************************************************************************
+ * END (M32 ALLOCATOR)
+ ***************************************************************************/
+
#endif // USE_MMAP
/*
@@ -2329,6 +2585,39 @@ static void freeOcStablePtrs (ObjectCode *oc)
oc->stable_ptrs = NULL;
}
+static void
+freePreloadObjectFile (ObjectCode *oc)
+{
+#ifdef USE_MMAP
+
+ if (oc->imageMapped) {
+ munmap(oc->image, oc->fileSize);
+ } else {
+ stgFree(oc->image);
+ }
+
+#elif defined(mingw32_HOST_OS)
+
+ VirtualFree(oc->image - PEi386_IMAGE_OFFSET, 0, MEM_RELEASE);
+
+ IndirectAddr *ia, *ia_next;
+ ia = indirects;
+ while (ia != NULL) {
+ ia_next = ia->next;
+ stgFree(ia);
+ ia = ia_next;
+ }
+ indirects = NULL;
+
+#else
+
+ stgFree(oc->image);
+
+#endif
+
+ oc->image = NULL;
+ oc->fileSize = 0;
+}
/*
* freeObjectCode() releases all the pieces of an ObjectCode. It is called by
@@ -2337,69 +2626,54 @@ static void freeOcStablePtrs (ObjectCode *oc)
*/
void freeObjectCode (ObjectCode *oc)
{
+ freePreloadObjectFile(oc);
+
if (oc->symbols != NULL) {
stgFree(oc->symbols);
oc->symbols = NULL;
}
- {
- Section *s, *nexts;
-
- for (s = oc->sections; s != NULL; s = nexts) {
- nexts = s->next;
- stgFree(s);
+ if (oc->sections != NULL) {
+ int i;
+ for (i=0; i < oc->n_sections; i++) {
+ if (oc->sections[i].start != NULL) {
+ switch(oc->sections[i].alloc){
+#ifdef USE_MMAP
+ case SECTION_MMAP:
+ munmap(oc->sections[i].mapped_start,
+ oc->sections[i].mapped_size);
+ break;
+ case SECTION_M32:
+ m32_free(oc->sections[i].start,
+ oc->sections[i].size);
+ break;
+#endif
+ case SECTION_MALLOC:
+ stgFree(oc->sections[i].start);
+ break;
+ default:
+ break;
+ }
+ }
}
+ stgFree(oc->sections);
}
freeProddableBlocks(oc);
+ /* Free symbol_extras. On x86_64 Windows, symbol_extras are allocated
+ * alongside the image, so we don't need to free. */
+#if NEED_SYMBOL_EXTRAS && (!defined(x86_64_HOST_ARCH) || !defined(mingw32_HOST_OS))
#ifdef USE_MMAP
- int pagesize, size, r;
-
- pagesize = getpagesize();
- size = ROUND_UP(oc->fileSize, pagesize);
-
- r = munmap(oc->image, size);
- if (r == -1) {
- sysErrorBelch("munmap");
- }
-
-#if defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH) || defined(arm_HOST_ARCH)
-#if !defined(x86_64_HOST_ARCH) || !defined(mingw32_HOST_OS)
if (!USE_CONTIGUOUS_MMAP && oc->symbol_extras != NULL)
{
- munmap(oc->symbol_extras,
- ROUND_UP(sizeof(SymbolExtra) * oc->n_symbol_extras, pagesize));
+ m32_free(oc->symbol_extras, sizeof(SymbolExtra) * oc->n_symbol_extras);
}
-#endif
-#endif
-
-#else
-
-#ifndef mingw32_HOST_OS
- stgFree(oc->image);
-#else
- VirtualFree(oc->image - PEi386_IMAGE_OFFSET, 0, MEM_RELEASE);
-
- IndirectAddr *ia, *ia_next;
- ia = indirects;
- while (ia != NULL) {
- ia_next = ia->next;
- stgFree(ia);
- ia = ia_next;
- }
- indirects = NULL;
-
-#endif
-
-#if defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH) || defined(arm_HOST_ARCH)
-#if !defined(x86_64_HOST_ARCH) || !defined(mingw32_HOST_OS)
+#else // !USE_MMAP
stgFree(oc->symbol_extras);
#endif
#endif
-#endif
-
stgFree(oc->fileName);
stgFree(oc->archiveMemberName);
stgFree(oc);
@@ -2408,7 +2682,7 @@ void freeObjectCode (ObjectCode *oc)
static ObjectCode*
mkOc( pathchar *path, char *image, int imageSize,
- char *archiveMemberName
+ rtsBool mapped, char *archiveMemberName
#ifndef USE_MMAP
#ifdef darwin_HOST_OS
, int misalignment
@@ -2444,12 +2718,14 @@ mkOc( pathchar *path, char *image, int imageSize,
oc->fileSize = imageSize;
oc->symbols = NULL;
+ oc->n_sections = 0;
oc->sections = NULL;
oc->proddables = NULL;
oc->stable_ptrs = NULL;
-#if powerpc_HOST_ARCH || x86_64_HOST_ARCH || arm_HOST_ARCH
+#if NEED_SYMBOL_EXTRAS
oc->symbol_extras = NULL;
#endif
+ oc->imageMapped = mapped;
#ifndef USE_MMAP
#ifdef darwin_HOST_OS
@@ -2788,16 +3064,7 @@ static HsInt loadArchive_ (pathchar *path)
IF_DEBUG(linker, debugBelch("loadArchive: Member is an object file...loading...\n"));
- /* We can't mmap from the archive directly, as object
- files need to be 8-byte aligned but files in .ar
- archives are 2-byte aligned. When possible we use mmap
- to get some anonymous memory, as on 64-bit platforms if
- we use malloc then we can be given memory above 2^32.
- In the mmap case we're probably wasting lots of space;
- we could do better. */
-#if defined(USE_MMAP)
- image = mmapForLinker(memberSize, MAP_ANONYMOUS, -1);
-#elif defined(mingw32_HOST_OS)
+#if defined(mingw32_HOST_OS)
// TODO: We would like to use allocateExec here, but allocateExec
// cannot currently allocate blocks large enough.
image = allocateImageAndTrampolines(path, fileName,
@@ -2806,11 +3073,16 @@ static HsInt loadArchive_ (pathchar *path)
#endif
memberSize);
#elif defined(darwin_HOST_OS)
+#if defined(USE_MMAP)
+ image = mmapForLinker(memberSize, MAP_ANONYMOUS, -1, 0);
+#else
/* See loadObj() */
misalignment = machoGetMisalignment(f);
image = stgMallocBytes(memberSize + misalignment, "loadArchive(image)");
image += misalignment;
-#else
+#endif // USE_MMAP
+
+#else // not windows or darwin
image = stgMallocBytes(memberSize, "loadArchive(image)");
#endif
@@ -2867,12 +3139,10 @@ static HsInt loadArchive_ (pathchar *path)
sprintf(archiveMemberName, "%" PATH_FMT "(%.*s)",
path, (int)thisFileNameSize, fileName);
- oc = mkOc(path, image, memberSize, archiveMemberName
-#ifndef USE_MMAP
-#ifdef darwin_HOST_OS
+ oc = mkOc(path, image, memberSize, rtsFalse, archiveMemberName
+#if !defined(USE_MMAP) && defined(darwin_HOST_OS)
, misalignment
#endif
-#endif
);
stgFree(archiveMemberName);
@@ -2892,7 +3162,7 @@ static HsInt loadArchive_ (pathchar *path)
}
IF_DEBUG(linker, debugBelch("loadArchive: Found GNU-variant file index\n"));
#ifdef USE_MMAP
- gnuFileIndex = mmapForLinker(memberSize + 1, MAP_ANONYMOUS, -1);
+ gnuFileIndex = mmapForLinker(memberSize + 1, MAP_ANONYMOUS, -1, 0);
#else
gnuFileIndex = stgMallocBytes(memberSize + 1, "loadArchive(image)");
#endif
@@ -2942,6 +3212,10 @@ static HsInt loadArchive_ (pathchar *path)
#endif
}
+#ifdef USE_MMAP
+ m32_allocator_flush(&allocator);
+#endif
+
IF_DEBUG(linker, debugBelch("loadArchive: done\n"));
return 1;
}
@@ -2954,78 +3228,65 @@ HsInt loadArchive (pathchar *path)
return r;
}
-/* -----------------------------------------------------------------------------
- * Load an obj (populate the global symbol table, but don't resolve yet)
- *
- * Returns: 1 if ok, 0 on error.
- */
-static HsInt loadObj_ (pathchar *path)
+//
+// Load the object file into memory. This will not be its final resting place,
+// as on 64-bit platforms we need to map its segments into the low 2Gb of the
+// address space, properly aligned.
+//
+static ObjectCode *
+preloadObjectFile (pathchar *path)
{
- ObjectCode* oc;
- char *image;
int fileSize;
struct_stat st;
int r;
-#ifdef USE_MMAP
- int fd;
-#else
- FILE *f;
-# if defined(darwin_HOST_OS)
+ void *image;
+ ObjectCode *oc;
+#if !defined(USE_MMAP) && defined(darwin_HOST_OS)
int misalignment;
-# endif
#endif
- IF_DEBUG(linker, debugBelch("loadObj %" PATH_FMT "\n", path));
-
- /* debugBelch("loadObj %s\n", path ); */
-
- /* Check that we haven't already loaded this object.
- Ignore requests to load multiple times */
-
- if (isAlreadyLoaded(path)) {
- IF_DEBUG(linker,
- debugBelch("ignoring repeated load of %" PATH_FMT "\n", path));
- return 1; /* success */
- }
r = pathstat(path, &st);
if (r == -1) {
- IF_DEBUG(linker, debugBelch("File doesn't exist\n"));
- return 0;
+ errorBelch("loadObj: %" PATH_FMT ": file doesn't exist", path);
+ return NULL;
}
fileSize = st.st_size;
#ifdef USE_MMAP
- /* On many architectures malloc'd memory isn't executable, so we need to use mmap. */
+ int fd;
+
+ /* On many architectures malloc'd memory isn't executable, so we need to use
+ * mmap. */
#if defined(openbsd_HOST_OS)
- /* coverity[toctou] */
fd = open(path, O_RDONLY, S_IRUSR);
#else
- /* coverity[toctou] */
fd = open(path, O_RDONLY);
#endif
if (fd == -1) {
- errorBelch("loadObj: can't open `%s'", path);
- return 0;
+ errorBelch("loadObj: can't open %s", path);
+ return NULL;
}
- image = mmapForLinker(fileSize, 0, fd);
+ image = mmap(NULL, fileSize, PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_PRIVATE, fd, 0);
+ // not 32-bit yet, we'll remap later
close(fd);
- if (image == NULL) {
- return 0;
- }
#else /* !USE_MMAP */
+ FILE *f;
+
/* load the image into memory */
/* coverity[toctou] */
f = pathopen(path, WSTR("rb"));
if (!f) {
errorBelch("loadObj: can't read `%" PATH_FMT "'", path);
- return 0;
+ return NULL;
}
-# if defined(mingw32_HOST_OS)
+# if defined(mingw32_HOST_OS)
+
// TODO: We would like to use allocateExec here, but allocateExec
// cannot currently allocate blocks large enough.
image = allocateImageAndTrampolines(path, "itself",
@@ -3035,9 +3296,11 @@ static HsInt loadObj_ (pathchar *path)
fileSize);
if (image == NULL) {
fclose(f);
- return 0;
+ return NULL;
}
+
# 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
@@ -3050,30 +3313,57 @@ static HsInt loadObj_ (pathchar *path)
misalignment = machoGetMisalignment(f);
image = stgMallocBytes(fileSize + misalignment, "loadObj(image)");
image += misalignment;
-# else
+
+# else /* !defined(mingw32_HOST_OS) */
+
image = stgMallocBytes(fileSize, "loadObj(image)");
-# endif
- {
- int n;
- n = fread ( image, 1, fileSize, f );
- fclose(f);
- if (n != fileSize) {
- errorBelch("loadObj: error whilst reading `%" PATH_FMT "'", path);
- stgFree(image);
- return 0;
- }
+#endif
+
+ int n;
+ n = fread ( image, 1, fileSize, f );
+ fclose(f);
+ if (n != fileSize) {
+ errorBelch("loadObj: error whilst reading `%" PATH_FMT "'", path);
+ stgFree(image);
+ return NULL;
}
+
#endif /* USE_MMAP */
- oc = mkOc(path, image, fileSize, NULL
-#ifndef USE_MMAP
-#ifdef darwin_HOST_OS
+ oc = mkOc(path, image, fileSize, rtsTrue, NULL
+#if !defined(USE_MMAP) && defined(darwin_HOST_OS)
, misalignment
#endif
-#endif
);
+ return oc;
+}
+
+/* -----------------------------------------------------------------------------
+ * Load an obj (populate the global symbol table, but don't resolve yet)
+ *
+ * Returns: 1 if ok, 0 on error.
+ */
+static HsInt loadObj_ (pathchar *path)
+{
+ ObjectCode* oc;
+ IF_DEBUG(linker, debugBelch("loadObj %" PATH_FMT "\n", path));
+
+ /* debugBelch("loadObj %s\n", path ); */
+
+ /* Check that we haven't already loaded this object.
+ Ignore requests to load multiple times */
+
+ if (isAlreadyLoaded(path)) {
+ IF_DEBUG(linker,
+ debugBelch("ignoring repeated load of %" PATH_FMT "\n", path));
+ return 1; /* success */
+ }
+
+ oc = preloadObjectFile(path);
+ if (oc == NULL) return 0;
+
if (! loadOc(oc)) {
// failed; free everything we've allocated
removeOcSymbols(oc);
@@ -3095,8 +3385,8 @@ HsInt loadObj (pathchar *path)
return r;
}
-static HsInt
-loadOc( ObjectCode* oc ) {
+static HsInt loadOc (ObjectCode* oc)
+{
int r;
IF_DEBUG(linker, debugBelch("loadOc: start\n"));
@@ -3116,20 +3406,22 @@ loadOc( ObjectCode* oc ) {
return r;
}
-# if defined(OBJFORMAT_MACHO) && (defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH))
+#if NEED_SYMBOL_EXTRAS
+# if defined(OBJFORMAT_MACHO)
r = ocAllocateSymbolExtras_MachO ( oc );
if (!r) {
IF_DEBUG(linker, debugBelch("loadOc: ocAllocateSymbolExtras_MachO failed\n"));
return r;
}
-# elif defined(OBJFORMAT_ELF) && (defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH) || defined(arm_HOST_ARCH))
+# elif defined(OBJFORMAT_ELF)
r = ocAllocateSymbolExtras_ELF ( oc );
if (!r) {
IF_DEBUG(linker, debugBelch("loadOc: ocAllocateSymbolExtras_ELF failed\n"));
return r;
}
-# elif defined(OBJFORMAT_PEi386) && defined(x86_64_HOST_ARCH)
+# elif defined(OBJFORMAT_PEi386)
ocAllocateSymbolExtras_PEi386 ( oc );
+# endif
#endif
/* build the symbol list for this image */
@@ -3332,18 +3624,23 @@ static void freeProddableBlocks (ObjectCode *oc)
* Section management.
*/
static void
-addSection ( ObjectCode* oc, SectionKind kind,
- void* start, void* end )
+addSection (Section *s, SectionKind kind, SectionAlloc alloc,
+ void* start, StgWord size, StgWord mapped_offset,
+ void* mapped_start, StgWord mapped_size)
{
- Section* s = stgMallocBytes(sizeof(Section), "addSection");
- s->start = start;
- s->end = end;
- s->kind = kind;
- s->next = oc->sections;
- oc->sections = s;
-
- IF_DEBUG(linker, debugBelch("addSection: %p-%p (size %lld), kind %d\n",
- start, ((char*)end)-1, ((long long)(size_t)end) - ((long long)(size_t)start) + 1, kind ));
+ s->start = start; /* actual start of section in memory */
+ s->size = size; /* actual size of section in memory */
+ s->kind = kind;
+ s->alloc = alloc;
+ s->mapped_offset = mapped_offset; /* offset from the image of mapped_start */
+
+ s->mapped_start = mapped_start; /* start of mmap() block */
+ s->mapped_size = mapped_size; /* size of mmap() block */
+
+ IF_DEBUG(linker,
+ debugBelch("addSection: %p-%p (size %" FMT_Word "), kind %d\n",
+ start, (void*)((StgWord)start + size),
+ size, kind ));
}
@@ -3355,7 +3652,7 @@ addSection ( ObjectCode* oc, SectionKind kind,
* them right next to the object code itself.
*/
-#if defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH) || defined(arm_HOST_ARCH)
+#if NEED_SYMBOL_EXTRAS
#if !defined(x86_64_HOST_ARCH) || !defined(mingw32_HOST_OS)
/*
@@ -3379,63 +3676,55 @@ addSection ( ObjectCode* oc, SectionKind kind,
static int ocAllocateSymbolExtras( ObjectCode* oc, int count, int first )
{
-#ifdef USE_MMAP
- int pagesize, n, m;
-#endif
- int aligned;
+ StgWord n;
#ifndef USE_MMAP
int misalignment = 0;
#ifdef darwin_HOST_OS
- misalignment = oc->misalignment;
+ int aligned;
#endif
#endif
+#ifdef USE_MMAP
+ if (USE_CONTIGUOUS_MMAP)
+ {
+ n = roundUpToPage(oc->fileSize);
+
+ /* Keep image and symbol_extras contiguous */
+ void *new = mmapForLinker(n + (sizeof(SymbolExtra) * count),
+ MAP_ANONYMOUS, -1, 0);
+ if (new)
+ {
+ memcpy(new, oc->image, oc->fileSize);
+ if (oc->imageMapped) {
+ munmap(oc->image, n);
+ }
+ oc->image = new;
+ oc->imageMapped = rtsTrue;
+ oc->fileSize = n + (sizeof(SymbolExtra) * count);
+ oc->symbol_extras = (SymbolExtra *) (oc->image + n);
+ }
+ else {
+ oc->symbol_extras = NULL;
+ return 0;
+ }
+ }
+ else
+#endif
+
if( count > 0 )
{
+#ifdef USE_MMAP
+ n = roundUpToPage(oc->fileSize);
+
+ oc->symbol_extras = m32_alloc(&allocator,
+ sizeof(SymbolExtra) * count, 8);
+ if (oc->symbol_extras == NULL) return 0;
+#else
// round up to the nearest 4
aligned = (oc->fileSize + 3) & ~3;
-#ifdef USE_MMAP
- pagesize = getpagesize();
- n = ROUND_UP( oc->fileSize, pagesize );
- m = ROUND_UP( aligned + sizeof (SymbolExtra) * count, pagesize );
+ misalignment = oc->misalignment;
- /* 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 ) // we need to allocate more pages
- {
- if (USE_CONTIGUOUS_MMAP)
- {
- /* Keep image and symbol_extras contiguous */
- void *new = mmapForLinker(n + (sizeof(SymbolExtra) * count),
- MAP_ANONYMOUS, -1);
- if (new)
- {
- memcpy(new, oc->image, oc->fileSize);
- munmap(oc->image, n);
- oc->image = new;
- oc->fileSize = n + (sizeof(SymbolExtra) * count);
- oc->symbol_extras = (SymbolExtra *) (oc->image + n);
- }
- else {
- oc->symbol_extras = NULL;
- return 0;
- }
- }
- else
- {
- oc->symbol_extras = mmapForLinker(sizeof(SymbolExtra) * count,
- MAP_ANONYMOUS, -1);
- if (oc->symbol_extras == NULL) return 0;
- }
- }
- else
- {
- oc->symbol_extras = (SymbolExtra *) (oc->image + aligned);
- }
-#else
oc->image -= misalignment;
oc->image = stgReallocBytes( oc->image,
misalignment +
@@ -3445,11 +3734,11 @@ static int ocAllocateSymbolExtras( ObjectCode* oc, int count, int first )
oc->symbol_extras = (SymbolExtra *) (oc->image + aligned);
#endif /* USE_MMAP */
+ }
- memset( oc->symbol_extras, 0, sizeof (SymbolExtra) * count );
+ if (oc->symbol_extras != NULL) {
+ memset( oc->symbol_extras, 0, sizeof (SymbolExtra) * count );
}
- else
- oc->symbol_extras = NULL;
oc->first_symbol_extra = first;
oc->n_symbol_extras = count;
@@ -3458,7 +3747,7 @@ static int ocAllocateSymbolExtras( ObjectCode* oc, int count, int first )
}
#endif
-#endif // defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH) || defined(arm_HOST_ARCH)
+#endif // NEED_SYMBOL_EXTRAS
#if defined(arm_HOST_ARCH)
@@ -4360,6 +4649,14 @@ ocGetNames_PEi386 ( ObjectCode* oc )
/* debugBelch("BSS anon section at 0x%x\n", zspace); */
}
+ Section *sections;
+ sections = (Section*)stgCallocBytes(
+ sizeof(Section),
+ hdr->NumberOfSections + 1, /* +1 for the global BSS section see below */
+ "ocGetNames_ELF(sections)");
+ oc->sections = sections;
+ oc->n_sections = hdr->NumberOfSections + 1;
+
/* Copy section information into the ObjectCode. */
for (i = 0; i < hdr->NumberOfSections; i++) {
@@ -4403,8 +4700,8 @@ ocGetNames_PEi386 ( ObjectCode* oc )
end = start + sz - 1;
if (kind != SECTIONKIND_OTHER && end >= start) {
- addSection(oc, kind, start, end);
- addProddableBlock(oc, start, end - start + 1);
+ addSection(&sections[i], kind, SECTION_NOMEM, start, sz, 0, 0, 0);
+ addProddableBlock(oc, start, end - start + 1);
}
stgFree(secname);
@@ -4413,11 +4710,36 @@ ocGetNames_PEi386 ( ObjectCode* oc )
/* Copy exported symbols into the ObjectCode. */
oc->n_symbols = hdr->NumberOfSymbols;
- oc->symbols = stgMallocBytes(oc->n_symbols * sizeof(char*),
+ oc->symbols = stgCallocBytes(sizeof(char*), oc->n_symbols,
"ocGetNames_PEi386(oc->symbols)");
- /* Call me paranoid; I don't care. */
- for (i = 0; i < oc->n_symbols; i++)
- oc->symbols[i] = NULL;
+
+ /* Work out the size of the global BSS section */
+ StgWord globalBssSize = 0;
+ for (i=0; i < (int)hdr->NumberOfSymbols; i++) {
+ COFF_symbol* symtab_i;
+ symtab_i = (COFF_symbol*)
+ myindex ( sizeof_COFF_symbol, symtab, i );
+ if (symtab_i->SectionNumber == MYIMAGE_SYM_UNDEFINED
+ && symtab_i->Value > 0) {
+ globalBssSize += symtab_i->Value;
+ }
+ i += symtab_i->NumberOfAuxSymbols;
+ }
+
+ /* Allocate BSS space */
+ void *bss = NULL;
+ if (globalBssSize > 0) {
+ bss = stgCallocBytes(1, globalBssSize,
+ "ocGetNames_PEi386(non-anonymous bss)");
+ addSection(&sections[oc->n_sections-1],
+ SECTIONKIND_RWDATA, SECTION_MALLOC,
+ bss, globalBssSize, 0, 0, 0);
+ debugBelch("bss @ %p %" FMT_Word "\n", bss, globalBssSize);
+ addProddableBlock(oc, bss, globalBssSize);
+ } else {
+ addSection(&sections[oc->n_sections-1],
+ SECTIONKIND_OTHER, SECTION_NOMEM, NULL, 0, 0, 0, 0);
+ }
for (i = 0; i < oc->n_symbols; i++) {
COFF_symbol* symtab_i;
@@ -4454,13 +4776,10 @@ ocGetNames_PEi386 ( ObjectCode* oc )
if (symtab_i->SectionNumber == MYIMAGE_SYM_UNDEFINED
&& symtab_i->Value > 0) {
/* This symbol isn't in any section at all, ie, global bss.
- Allocate zeroed space for it. */
- addr = stgCallocBytes(1, symtab_i->Value,
- "ocGetNames_PEi386(non-anonymous bss)");
- addSection(oc, SECTIONKIND_RWDATA, addr,
- ((UChar*)addr) + symtab_i->Value - 1);
- addProddableBlock(oc, addr, symtab_i->Value);
- /* debugBelch("BSS section at 0x%x\n", addr); */
+ Allocate zeroed space for it from the BSS section */
+ addr = bss;
+ bss = (void *)((StgWord)bss + (StgWord)symtab_i->Value);
+ debugBelch("bss symbol @ %p %u\n", addr, symtab_i->Value);
}
if (addr != NULL ) {
@@ -5056,7 +5375,6 @@ PLTSize(void)
}
#endif
-
/*
* Generic ELF functions
*/
@@ -5286,6 +5604,9 @@ ocVerifyImage_ELF ( ObjectCode* oc )
return 1;
}
+/* 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"). */
static int getSectionKind_ELF( Elf_Shdr *hdr, int *is_bss )
{
*is_bss = FALSE;
@@ -5324,51 +5645,109 @@ static int getSectionKind_ELF( Elf_Shdr *hdr, int *is_bss )
return SECTIONKIND_OTHER;
}
+static void *
+mapObjectFileSection (int fd, Elf_Word offset, Elf_Word size,
+ void **mapped_start, StgWord *mapped_size,
+ StgWord *mapped_offset)
+{
+ void *p;
+ StgWord pageOffset, pageSize;
+
+ pageOffset = roundDownToPage(offset);
+ pageSize = roundUpToPage(offset-pageOffset+size);
+ p = mmapForLinker(pageSize, 0, fd, pageOffset);
+ if (p == NULL) return NULL;
+ *mapped_size = pageSize;
+ *mapped_offset = pageOffset;
+ *mapped_start = p;
+ return (void*)((StgWord)p + offset - pageOffset);
+}
static int
ocGetNames_ELF ( ObjectCode* oc )
{
- int i, j, nent;
+ int i, j, nent, result, fd = -1;
Elf_Sym* stab;
char* ehdrC = (char*)(oc->image);
Elf_Ehdr* ehdr = (Elf_Ehdr*)ehdrC;
char* strtab;
Elf_Shdr* shdr = (Elf_Shdr*) (ehdrC + ehdr->e_shoff);
+ Section * sections;
ASSERT(symhash != NULL);
+ sections = (Section*)stgCallocBytes(sizeof(Section), ehdr->e_shnum,
+ "ocGetNames_ELF(sections)");
+ oc->sections = sections;
+ oc->n_sections = ehdr->e_shnum;
+
+
+ if (oc->imageMapped) {
+#if defined(openbsd_HOST_OS)
+ fd = open(oc->fileName, O_RDONLY, S_IRUSR);
+#else
+ fd = open(oc->fileName, O_RDONLY);
+#endif
+ if (fd == -1) {
+ errorBelch("loadObj: can't open %" PATH_FMT, oc->fileName);
+ return 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"). */
int is_bss = FALSE;
SectionKind kind = getSectionKind_ELF(&shdr[i], &is_bss);
+ SectionAlloc alloc = SECTION_NOMEM;
+ void *start = NULL, *mapped_start = NULL;
+ StgWord mapped_size = 0, mapped_offset = 0;
+ StgWord size = shdr[i].sh_size;
+ StgWord offset = shdr[i].sh_offset;
- if (is_bss && shdr[i].sh_size > 0) {
+ if (is_bss && 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 = stgCallocBytes(1, shdr[i].sh_size,
- "ocGetNames_ELF(BSS)");
- shdr[i].sh_offset = ((char*)zspace) - ((char*)ehdrC);
+ alloc = SECTION_MALLOC;
+ start = stgCallocBytes(1, size, "ocGetNames_ELF(BSS)");
+ mapped_start = start;
/*
debugBelch("BSS section at 0x%x, size %d\n",
zspace, shdr[i].sh_size);
*/
}
- /* 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);
+ else if (kind != SECTIONKIND_OTHER && size > 0) {
+ if (USE_CONTIGUOUS_MMAP) {
+ // already mapped.
+ start = oc->image + offset;
+ alloc = SECTION_NOMEM;
+ }
+ // use the m32 allocator if either the image is not mapped
+ // (i.e. we cannot map the secions separately), or if the section
+ // size is small.
+ else if (!oc->imageMapped || size < getPageSize() / 3) {
+ start = m32_alloc(&allocator, size, 8);
+ if (start == NULL) goto fail;
+ memcpy(start, oc->image + offset, size);
+ alloc = SECTION_M32;
+ } else {
+ start = mapObjectFileSection(fd, offset, size,
+ &mapped_start, &mapped_size,
+ &mapped_offset);
+ if (start == NULL) goto fail;
+ alloc = SECTION_MMAP;
+ }
+ addProddableBlock(oc, ehdrC + offset, size);
}
+ addSection(&sections[i], kind, alloc, start, size,
+ mapped_offset, mapped_start, mapped_size);
+
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);
+ stab = (Elf_Sym*) (ehdrC + offset);
strtab = ehdrC + shdr[shdr[i].sh_link].sh_offset;
nent = shdr[i].sh_size / sizeof(Elf_Sym);
@@ -5427,7 +5806,8 @@ ocGetNames_ELF ( ObjectCode* oc )
stab[j].st_size, stab[j].st_value, nm);
}
*/
- ad = ehdrC + shdr[ secno ].sh_offset + stab[j].st_value;
+ ad = (void*)((intptr_t)sections[secno].start +
+ (intptr_t)stab[j].st_value);
if (ELF_ST_BIND(stab[j].st_info)==STB_LOCAL) {
isLocal = TRUE;
isWeak = FALSE;
@@ -5456,7 +5836,7 @@ ocGetNames_ELF ( ObjectCode* oc )
} else {
if (! ghciInsertSymbolTable(oc->fileName, symhash,
nm, ad, isWeak, oc)) {
- return 0;
+ goto fail;
}
oc->symbols[j] = nm;
}
@@ -5479,7 +5859,16 @@ ocGetNames_ELF ( ObjectCode* oc )
}
}
- return 1;
+ result = 1;
+ goto end;
+
+fail:
+ result = 0;
+ goto end;
+
+end:
+ if (fd >= 0) close(fd);
+ return result;
}
/* Do ELF relocations which lack an explicit addend. All x86-linux
@@ -5501,18 +5890,14 @@ do_Elf_Rel_relocations ( ObjectCode* oc, char* ehdrC,
stab = (Elf_Sym*) (ehdrC + shdr[ symtab_shndx ].sh_offset);
strtab= (char*) (ehdrC + shdr[ strtab_shndx ].sh_offset);
- targ = (Elf_Word*)(ehdrC + shdr[ target_shndx ].sh_offset);
+ targ = (Elf_Word*)oc->sections[target_shndx].start;
IF_DEBUG(linker,debugBelch( "relocations for section %d using symtab %d and strtab %d\n",
target_shndx, symtab_shndx, strtab_shndx ));
/* Skip sections that we're not interested in. */
- {
- int is_bss;
- SectionKind kind = getSectionKind_ELF(&shdr[target_shndx], &is_bss);
- if (kind == SECTIONKIND_OTHER) {
+ if (oc->sections[target_shndx].kind == SECTIONKIND_OTHER) {
IF_DEBUG(linker,debugBelch( "skipping (target section not loaded)"));
return 1;
- }
}
for (j = 0; j < nent; j++) {
@@ -5545,9 +5930,8 @@ do_Elf_Rel_relocations ( ObjectCode* oc, char* ehdrC,
/* 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);
+ S = (Elf_Addr)oc->sections[sym.st_shndx].start +
+ stab[ELF_R_SYM(info)].st_value;
} else {
symbol = strtab + sym.st_name;
@@ -5816,11 +6200,17 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
strtab= (char*) (ehdrC + shdr[ strtab_shndx ].sh_offset);
#if defined(DEBUG) || defined(sparc_HOST_ARCH) || defined(ia64_HOST_ARCH) || defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH)
/* This #ifdef only serves to avoid set-but-not-used warnings */
- targ = (Elf_Addr) (ehdrC + shdr[ target_shndx ].sh_offset);
+ targ = (Elf_Addr) oc->sections[target_shndx].start;
#endif
IF_DEBUG(linker,debugBelch( "relocations for section %d using symtab %d\n",
target_shndx, symtab_shndx ));
+ /* Skip sections that we're not interested in. */
+ if (oc->sections[target_shndx].kind == SECTIONKIND_OTHER) {
+ IF_DEBUG(linker,debugBelch( "skipping (target section not loaded)"));
+ return 1;
+ }
+
for (j = 0; j < nent; j++) {
#if defined(DEBUG) || defined(sparc_HOST_ARCH) || defined(ia64_HOST_ARCH) || defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH)
/* This #ifdef only serves to avoid unused-var warnings. */
@@ -5854,9 +6244,8 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
/* 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);
+ S = (Elf_Addr)oc->sections[sym.st_shndx].start
+ + 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) {
@@ -6176,12 +6565,12 @@ static int ocRunInit_ELF( ObjectCode *oc )
SectionKind kind = getSectionKind_ELF(&shdr[i], &is_bss);
if (kind == SECTIONKIND_CODE_OR_RODATA
&& 0 == memcmp(".init", sh_strtab + shdr[i].sh_name, 5)) {
- init_t init_f = (init_t)(ehdrC + shdr[i].sh_offset);
- init_f(argc, argv, envv);
+ init_t init_f = (init_t)(oc->sections[i].start);
+ init_f(argc, argv, envv);
}
if (kind == SECTIONKIND_INIT_ARRAY) {
- char *init_startC = ehdrC + shdr[i].sh_offset;
+ char *init_startC = oc->sections[i].start;
init_start = (init_t*)init_startC;
init_end = (init_t*)(init_startC + shdr[i].sh_size);
for (init = init_start; init < init_end; init++) {
@@ -6193,7 +6582,7 @@ static int ocRunInit_ELF( ObjectCode *oc )
// SECTIONKIND_RWDATA; but allowing RODATA seems harmless enough.
if ((kind == SECTIONKIND_RWDATA || kind == SECTIONKIND_CODE_OR_RODATA)
&& 0 == memcmp(".ctors", sh_strtab + shdr[i].sh_name, 6)) {
- char *init_startC = ehdrC + shdr[i].sh_offset;
+ char *init_startC = oc->sections[i].start;
init_start = (init_t*)init_startC;
init_end = (init_t*)(init_startC + shdr[i].sh_size);
// ctors run in reverse
@@ -6211,7 +6600,7 @@ static int ocRunInit_ELF( ObjectCode *oc )
* PowerPC & X86_64 ELF specifics
*/
-#if defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH) || defined(arm_HOST_ARCH)
+#if NEED_SYMBOL_EXTRAS
static int ocAllocateSymbolExtras_ELF( ObjectCode *oc )
{
@@ -6247,7 +6636,7 @@ static int ocAllocateSymbolExtras_ELF( ObjectCode *oc )
return ocAllocateSymbolExtras( oc, shdr[i].sh_size / sizeof( Elf_Sym ), 0 );
}
-#endif /* powerpc */
+#endif /* NEED_SYMBOL_EXTRAS */
#endif /* ELF */
@@ -7088,6 +7477,14 @@ ocGetNames_MachO(ObjectCode* oc)
barf("ocGetNames_MachO: no segment load command");
}
+ Section *secArray;
+ secArray = (Section*)stgCallocBytes(
+ sizeof(Section),
+ segLC->nsects,
+ "ocGetNames_MachO(sections)");
+ oc->sections = secArray;
+ oc->n_sections = segLC->nsects;
+
IF_DEBUG(linker, debugBelch("ocGetNames_MachO: will load %d sections\n", segLC->nsects));
for(i=0;i<segLC->nsects;i++)
{
@@ -7101,7 +7498,7 @@ ocGetNames_MachO(ObjectCode* oc)
if((sections[i].flags & SECTION_TYPE) == S_ZEROFILL)
{
#ifdef USE_MMAP
- char * zeroFillArea = mmapForLinker(sections[i].size, MAP_ANONYMOUS, -1);
+ char * zeroFillArea = mmapForLinker(sections[i].size, MAP_ANONYMOUS, -1, 0);
if (zeroFillArea == NULL) return 0;
memset(zeroFillArea, 0, sections[i].size);
#else
@@ -7124,11 +7521,11 @@ ocGetNames_MachO(ObjectCode* oc)
kind = SECTIONKIND_RWDATA;
}
- if (kind != SECTIONKIND_OTHER) {
- addSection(oc, kind,
- (void*) (image + sections[i].offset),
- (void*) (image + sections[i].offset + sections[i].size));
- }
+ addSection(&secArray[i], kind, SECTION_NOMEM,
+ (void *)(image + sections[i].offset),
+ sections[i].size,
+ 0, 0, 0);
+
addProddableBlock(oc,
(void *) (image + sections[i].offset),
sections[i].size);
diff --git a/rts/LinkerInternals.h b/rts/LinkerInternals.h
index 4eab5deb45..f5f17d2380 100644
--- a/rts/LinkerInternals.h
+++ b/rts/LinkerInternals.h
@@ -27,16 +27,31 @@ typedef
SECTIONKIND_NOINFOAVAIL }
SectionKind;
-typedef
+typedef
+ enum { SECTION_NOMEM,
+ SECTION_M32,
+ SECTION_MMAP,
+ SECTION_MALLOC,
+ }
+ SectionAlloc;
+
+typedef
struct _Section {
- void* start;
- void* end;
+ void* start; /* actual start of section in memory */
+ StgWord size; /* actual size of section in memory */
SectionKind kind;
- struct _Section* next;
- }
+ SectionAlloc alloc;
+
+ /*
+ * The following fields are relevant for SECTION_MMAP sections only
+ */
+ StgWord mapped_offset; /* offset from the image of mapped_start */
+ void* mapped_start; /* start of mmap() block */
+ StgWord mapped_size; /* size of mmap() block */
+ }
Section;
-typedef
+typedef
struct _ProddableBlock {
void* start;
int size;
@@ -55,6 +70,10 @@ typedef struct ForeignExportStablePtr_ {
struct ForeignExportStablePtr_ *next;
} ForeignExportStablePtr;
+#if powerpc_HOST_ARCH || x86_64_HOST_ARCH || arm_HOST_ARCH
+#define NEED_SYMBOL_EXTRAS 1
+#endif
+
/* Jump Islands are sniplets of machine code required for relative
* address relocations on the PowerPC, x86_64 and ARM.
*/
@@ -80,7 +99,7 @@ typedef struct {
typedef struct _ObjectCode {
OStatus status;
pathchar *fileName;
- int fileSize;
+ int fileSize; /* also mapped image size when using mmap() */
char* formatName; /* eg "ELF32", "DLL", "COFF", etc. */
/* If this object is a member of an archive, archiveMemberName is
@@ -95,8 +114,10 @@ typedef struct _ObjectCode {
char** symbols;
int n_symbols;
- /* ptr to malloc'd lump of memory holding the obj file */
+ /* ptr to mem containing the object file image */
char* image;
+ /* non-zero if the object file was mmap'd, otherwise malloc'd */
+ int imageMapped;
/* flag used when deciding whether to unload an object file */
int referenced;
@@ -109,6 +130,7 @@ typedef struct _ObjectCode {
/* The section-kind entries for this object module. Linked
list. */
+ int n_sections;
Section* sections;
/* Allow a chain of these things */
@@ -125,7 +147,7 @@ typedef struct _ObjectCode {
unsigned int pltIndex;
#endif
-#if powerpc_HOST_ARCH || x86_64_HOST_ARCH || arm_HOST_ARCH
+#if NEED_SYMBOL_EXTRAS
SymbolExtra *symbol_extras;
unsigned long first_symbol_extra;
unsigned long n_symbol_extras;
diff --git a/testsuite/tests/ghci/linking/all.T b/testsuite/tests/ghci/linking/all.T
index e823f88613..7404de3923 100644
--- a/testsuite/tests/ghci/linking/all.T
+++ b/testsuite/tests/ghci/linking/all.T
@@ -43,7 +43,7 @@ test('ghcilink006',
test('T3333',
[extra_clean(['T3333.o']),
unless(doing_ghci, skip),
- unless(opsys('linux') or ghci_dynamic(), expect_broken(3333))],
+ unless(opsys('linux') or opsys('darwin') or ghci_dynamic(), expect_broken(3333))],
run_command,
['$MAKE -s --no-print-directory T3333'])
diff --git a/testsuite/tests/rts/linker_error.c b/testsuite/tests/rts/linker_error.c
index 715eabd184..264c95d710 100644
--- a/testsuite/tests/rts/linker_error.c
+++ b/testsuite/tests/rts/linker_error.c
@@ -51,12 +51,12 @@ int main (int argc, char *argv[])
for (i=0; i < ITERATIONS; i++) {
r = loadObj(obj);
if (!r) {
- debugBelch("loadObj(%s) failed", obj);
+ debugBelch("loadObj(%s) failed\n", obj);
continue;
}
r = resolveObjs();
if (!r) {
- debugBelch("resolveObjs failed");
+ debugBelch("resolveObjs failed\n");
unloadObj(obj);
continue;
}