rts: enable parallel GC scan of large (32M+) allocation area
[ghc.git] / rts / Linker.c
index 2ba84f8..b41bc1a 100644 (file)
 #include "PosixSource.h"
 #endif
 
-/* Linux needs _GNU_SOURCE to get RTLD_DEFAULT from <dlfcn.h> and
-   MREMAP_MAYMOVE from <sys/mman.h>.
- */
-#if defined(__linux__)  || defined(__GLIBC__)
-#define _GNU_SOURCE 1
-#endif
-
 #include "Rts.h"
 #include "HsFFI.h"
 
 #include "Proftimer.h"
 #include "GetEnv.h"
 #include "Stable.h"
+#include "RtsSymbols.h"
+#include "RtsSymbolInfo.h"
+#include "Profiling.h"
+#include "sm/OSMem.h"
+#include "linker/M32Alloc.h"
 
 #if !defined(mingw32_HOST_OS)
 #include "posix/Signals.h"
 #include <dlfcn.h>
 #endif
 
-#if defined(cygwin32_HOST_OS)
-#ifdef HAVE_DIRENT_H
-#include <dirent.h>
-#endif
-
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#include <regex.h>
-#include <sys/fcntl.h>
-#include <sys/termios.h>
-#include <sys/utime.h>
-#include <sys/utsname.h>
-#include <sys/wait.h>
-#endif
-
-#if (defined(powerpc_HOST_ARCH) && defined(linux_HOST_OS)) \
- || (!defined(powerpc_HOST_ARCH) && \
-    (   defined(linux_HOST_OS)     || defined(freebsd_HOST_OS) || \
-        defined(dragonfly_HOST_OS) || defined(netbsd_HOST_OS ) || \
-        defined(openbsd_HOST_OS  ) || defined(darwin_HOST_OS ) || \
-        defined(kfreebsdgnu_HOST_OS) || defined(gnu_HOST_OS)))
-/* Don't use mmap on powerpc_HOST_ARCH as mmap doesn't support
- * reallocating but we need to allocate jump islands just after each
- * object images. Otherwise relative branches to jump islands can fail
- * due to 24-bits displacement overflow.
+/* PowerPC and ARM have relative branch instructions with only 24 bit
+ * displacements and therefore need jump islands contiguous with each object
+ * code module.
  */
-#define USE_MMAP
-#include <fcntl.h>
-#include <sys/mman.h>
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
+#if defined(powerpc_HOST_ARCH)
+#define SHORT_REL_BRANCH 1
 #endif
-
+#if defined(arm_HOST_ARCH)
+#define SHORT_REL_BRANCH 1
 #endif
 
-
-/* PowerPC has relative branch instructions with only 24 bit displacements
- * and therefore needs jump islands contiguous with each object code module.
- */
-#if (defined(USE_MMAP) && defined(powerpc_HOST_ARCH) && defined(linux_HOST_OS))
+#if (RTS_LINKER_USE_MMAP && defined(SHORT_REL_BRANCH) && defined(linux_HOST_OS))
 #define USE_CONTIGUOUS_MMAP 1
 #else
 #define USE_CONTIGUOUS_MMAP 0
 #  define OBJFORMAT_ELF
 #  include <regex.h>    // regex is already used by dlopen() so this is OK
                         // to use here without requiring an additional lib
-#elif defined(cygwin32_HOST_OS) || defined (mingw32_HOST_OS)
+#elif defined (mingw32_HOST_OS)
 #  define OBJFORMAT_PEi386
 #  include <windows.h>
+#  include <shfolder.h> /* SHGetFolderPathW */
 #  include <math.h>
+#  include <wchar.h>
 #elif defined(darwin_HOST_OS)
 #  define OBJFORMAT_MACHO
 #  include <regex.h>
 #  include <mach-o/loader.h>
 #  include <mach-o/nlist.h>
 #  include <mach-o/reloc.h>
-#if !defined(HAVE_DLFCN_H)
-#  include <mach-o/dyld.h>
-#endif
 #if defined(powerpc_HOST_ARCH)
 #  include <mach-o/ppc/reloc.h>
 #endif
 #include <sys/tls.h>
 #endif
 
+/* SymbolInfo tracks a symbol's address, the object code from which
+   it originated, and whether or not it's weak.
+
+   RtsSymbolInfo is used to track the state of the symbols currently
+   loaded or to be loaded by the Linker.
+
+   Where the information in the `ObjectCode` is used to track the
+   original status of the symbol inside the `ObjectCode`.
+
+   A weak symbol that has been used will still be marked as weak
+   in the `ObjectCode` but in the `RtsSymbolInfo` it won't be.
+*/
 typedef struct _RtsSymbolInfo {
-    void *value;
-    const ObjectCode *owner;
+    SymbolAddr* value;
+    ObjectCode *owner;
     HsBool weak;
 } RtsSymbolInfo;
 
-/* Hash table mapping symbol names to RtsSymbolInfo */
+/* `symhash` is a Hash table mapping symbol names to RtsSymbolInfo.
+   This hashtable will contain information on all symbols
+   that we know of, however the .o they are in may not be loaded.
+
+   Until the ObjectCode the symbol belongs to is actually
+   loaded this symbol may be replaced. So do not rely on
+   addresses of unloaded symbols.
+
+   Note [runtime-linker-phases]
+   --------------------------------------
+   Broadly the behavior of the runtime linker can be
+   split into the following four phases:
+
+   - Indexing (e.g. ocVerifyImage and ocGetNames)
+   - Initialization (e.g. ocResolve and ocRunInit)
+   - Resolve (e.g. resolveObjs())
+   - Lookup (e.g. lookupSymbol)
+
+   This is to enable lazy loading of symbols. Eager loading is problematic
+   as it means that all symbols must be available, even those which we will
+   never use. This is especially painful of Windows, where the number of
+   libraries required to link things like mingwex grows to be quite high.
+
+   We proceed through these stages as follows,
+
+   * During Indexing we verify and open the ObjectCode and
+     perform a quick scan/indexing of the ObjectCode. All the work
+     required to actually load the ObjectCode is done.
+
+     All symbols from the ObjectCode is also inserted into
+     `symhash`, where possible duplicates are handled via the semantics
+     described in `ghciInsertSymbolTable`.
+
+     This phase will produce ObjectCode with status `OBJECT_LOADED` or `OBJECT_NEEDED`
+     depending on whether they are an archive members or not.
+
+   * During initialization we load ObjectCode, perform relocations, execute
+     static constructors etc. This phase may trigger other ObjectCodes to
+     be loaded because of the calls to lookupSymbol.
+
+     This phase will produce ObjectCode with status `OBJECT_NEEDED` if the
+     previous status was `OBJECT_LOADED`.
+
+   * During resolve we attempt to resolve all the symbols needed for the
+     initial link. This essentially means, that for any ObjectCode given
+     directly to the command-line we perform lookupSymbols on the required
+     symbols. lookupSymbols may trigger the loading of additional ObjectCode
+     if required.
+
+     This phase will produce ObjectCode with status `OBJECT_RESOLVED` if
+     the previous status was `OBJECT_NEEDED`.
+
+   * Lookup symbols is used to lookup any symbols required, both during initial
+     link and during statement and expression compilations in the REPL.
+     Declaration of e.g. an foreign import, will eventually call lookupSymbol
+     which will either fail (symbol unknown) or succeed (and possibly triggered a
+     load).
+
+     This phase may transition an ObjectCode from `OBJECT_LOADED` to `OBJECT_RESOLVED`
+
+   When a new scope is introduced (e.g. a new module imported) GHCi does a full re-link
+   by calling unloadObj and starting over.
+   When a new declaration or statement is performed ultimately lookupSymbol is called
+   without doing a re-link.
+
+   The goal of these different phases is to allow the linker to be able to perform
+   "lazy loading" of ObjectCode. The reason for this is that we want to only link
+   in symbols that are actually required for the link. This reduces:
+
+   1) Dependency chains, if A.o required a .o in libB but A.o isn't required to link
+      then we don't need to load libB. This means the dependency chain for libraries
+      such as mingw32 and mingwex can be broken down.
+
+   2) The number of duplicate symbols, since now only symbols that are
+      true duplicates will display the error.
+ */
 static /*Str*/HashTable *symhash;
 
 /* List of currently loaded objects */
@@ -162,7 +216,7 @@ Mutex linker_mutex;
  * This protects unloaded_objects.  We have a separate mutex for this, because
  * the GC needs to access unloaded_objects in checkUnload, while the linker only
  * needs to access unloaded_objects in unloadObj(), so this allows most linker
- * operations proceed concurrently with the GC. 
+ * operations proceed concurrently with the GC.
  */
 Mutex linker_unloaded_mutex;
 #endif
@@ -173,12 +227,8 @@ 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
-#ifndef USE_MMAP
-#ifdef darwin_HOST_OS
-                       , int misalignment
-#endif
-#endif
+                         rtsBool mapped, char *archiveMemberName,
+                         int misalignment
                        );
 
 // Use wchar_t for pathnames on Windows (#5697)
@@ -190,6 +240,8 @@ static ObjectCode* mkOc( pathchar *path, char *image, int imageSize,
 #define struct_stat struct _stat
 #define open wopen
 #define WSTR(s) L##s
+#define pathprintf swprintf
+#define pathsize sizeof(wchar_t)
 #else
 #define pathcmp strcmp
 #define pathlen strlen
@@ -197,6 +249,8 @@ static ObjectCode* mkOc( pathchar *path, char *image, int imageSize,
 #define pathstat stat
 #define struct_stat struct stat
 #define WSTR(s) s
+#define pathprintf snprintf
+#define pathsize sizeof(char)
 #endif
 
 static pathchar* pathdup(pathchar *path)
@@ -206,19 +260,61 @@ static pathchar* pathdup(pathchar *path)
     ret = wcsdup(path);
 #else
     /* sigh, strdup() isn't a POSIX function, so do it the long way */
-    ret = stgMallocBytes( strlen(path)+1, "loadObj" );
+    ret = stgMallocBytes( strlen(path)+1, "pathdup" );
     strcpy(ret, path);
 #endif
     return ret;
 }
 
+static pathchar* pathdir(pathchar *path)
+{
+    pathchar *ret;
+#if defined(mingw32_HOST_OS)
+    pathchar *drive, *dirName;
+    size_t memberLen = pathlen(path) + 1;
+    dirName = stgMallocBytes(pathsize * memberLen, "pathdir(path)");
+    ret     = stgMallocBytes(pathsize * memberLen, "pathdir(path)");
+    drive   = stgMallocBytes(pathsize * _MAX_DRIVE, "pathdir(path)");
+    _wsplitpath_s(path, drive, _MAX_DRIVE, dirName, pathsize * pathlen(path), NULL, 0, NULL, 0);
+    pathprintf(ret, memberLen, WSTR("%" PATH_FMT "%" PATH_FMT), drive, dirName);
+    stgFree(drive);
+    stgFree(dirName);
+#else
+    pathchar* dirName = dirname(path);
+    size_t memberLen  = pathlen(dirName);
+    ret = stgMallocBytes(pathsize * (memberLen + 2), "pathdir(path)");
+    strcpy(ret, dirName);
+    ret[memberLen  ] = '/';
+    ret[memberLen+1] = '\0';
+#endif
+    return ret;
+}
+
+static pathchar* mkPath(char* path)
+{
+#if defined(mingw32_HOST_OS)
+    size_t required = mbstowcs(NULL, path, 0);
+    pathchar *ret = stgMallocBytes(sizeof(pathchar) * (required + 1), "mkPath");
+    if (mbstowcs(ret, path, required) == (size_t)-1)
+    {
+        barf("mkPath failed converting char* to wchar_t*");
+    }
+    ret[required] = '\0';
+    return ret;
+#else
+    return pathdup(path);
+#endif
+}
+
+/* Generic wrapper function to try and Resolve and RunInit oc files */
+int ocTryLoad( ObjectCode* oc );
 
 #if defined(OBJFORMAT_ELF)
 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)
@@ -227,13 +323,22 @@ static int ocGetNames_PEi386    ( ObjectCode* oc );
 static int ocResolve_PEi386     ( ObjectCode* oc );
 static int ocRunInit_PEi386     ( ObjectCode* oc );
 static void *lookupSymbolInDLLs ( unsigned char *lbl );
-static void zapTrailingAtSign   ( unsigned char *sym );
+/* See Note [mingw-w64 name decoration scheme] */
+#ifndef x86_64_HOST_ARCH
+ static void zapTrailingAtSign   ( unsigned char *sym );
+#endif
+
+#if defined(x86_64_HOST_ARCH)
+#define USED_IF_x86_64_HOST_ARCH    /* Nothing */
+#else
+#define USED_IF_x86_64_HOST_ARCH    STG_UNUSED
+#endif
+
 static char *allocateImageAndTrampolines (
    pathchar* arch_name, char* member_name,
-#if defined(x86_64_HOST_ARCH)
    FILE* f,
-#endif
-   int size );
+   int size,
+   int isThin);
 #if defined(x86_64_HOST_ARCH)
 static int ocAllocateSymbolExtras_PEi386 ( ObjectCode* oc );
 static size_t makeSymbolExtra_PEi386( ObjectCode* oc, size_t, char* symbol );
@@ -246,11 +351,8 @@ static int ocVerifyImage_MachO    ( ObjectCode* oc );
 static int ocGetNames_MachO       ( ObjectCode* oc );
 static int ocResolve_MachO        ( ObjectCode* oc );
 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
@@ -258,6 +360,50 @@ static void machoInitSymbolsWithoutUnderscore( void );
 #endif
 #endif
 
+#if defined(OBJFORMAT_PEi386)
+/* string utility function */
+static HsBool endsWithPath(pathchar* base, pathchar* str) {
+    int blen = pathlen(base);
+    int slen = pathlen(str);
+    return (blen >= slen) && (0 == pathcmp(base + blen - slen, str));
+}
+
+static int checkAndLoadImportLibrary(
+    pathchar* arch_name,
+    char* member_name,
+    FILE* f);
+
+static int findAndLoadImportLibrary(
+    ObjectCode* oc
+    );
+
+static UChar *myindex(
+    int scale,
+    void* base,
+    int index);
+static UChar *cstring_from_COFF_symbol_name(
+    UChar* name,
+    UChar* strtab);
+static char *cstring_from_section_name(
+    UChar* name,
+    UChar* strtab);
+
+
+/* Add ld symbol for PE image base. */
+#if defined(__GNUC__)
+#define __ImageBase __MINGW_LSYMBOL(_image_base__)
+#endif
+
+/* Get the base of the module.       */
+/* This symbol is defined by ld.     */
+extern IMAGE_DOS_HEADER __ImageBase;
+#define __image_base (void*)((HINSTANCE)&__ImageBase)
+
+// MingW-w64 is missing these from the implementation. So we have to look them up
+typedef DLL_DIRECTORY_COOKIE(WINAPI *LPAddDLLDirectory)(PCWSTR NewDirectory);
+typedef WINBOOL(WINAPI *LPRemoveDLLDirectory)(DLL_DIRECTORY_COOKIE Cookie);
+#endif /* OBJFORMAT_PEi386 */
+
 static void freeProddableBlocks (ObjectCode *oc);
 
 /* on x86_64 we have a problem with relocating symbol references in
@@ -310,6 +456,30 @@ static void freeProddableBlocks (ObjectCode *oc);
 #endif
 
 /*
+  Note [The ARM/Thumb Story]
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+  Support for the ARM architecture is complicated by the fact that ARM has not
+  one but several instruction encodings. The two relevant ones here are the original
+  ARM encoding and Thumb, a more dense variant of ARM supporting only a subset
+  of the instruction set.
+
+  How the CPU decodes a particular instruction is determined by a mode bit. This
+  mode bit is set on jump instructions, the value being determined by the low
+  bit of the target address: An odd address means the target is a procedure
+  encoded in the Thumb encoding whereas an even address means it's a traditional
+  ARM procedure (the actual address jumped to is even regardless of the encoding bit).
+
+  Interoperation between Thumb- and ARM-encoded object code (known as "interworking")
+  is tricky. If the linker needs to link a call by an ARM object into Thumb code
+  (or vice-versa) it will produce a jump island. This, however, is incompatible with
+  GHC's tables-next-to-code. For this reason, it is critical that GHC emit
+  exclusively ARM or Thumb objects for all Haskell code.
+
+  We still do, however, need to worry about foreign code.
+*/
+
+/*
  * Due to the small memory model (see above), on x86_64 we have to map
  * all our non-PIC object files into the low 2Gb of the address space
  * (why 2Gb and not 4Gb?  Because all addresses must be reachable
@@ -336,1209 +506,41 @@ static void freeProddableBlocks (ObjectCode *oc);
 static void *mmap_32bit_base = (void *)MMAP_32BIT_BASE_DEFAULT;
 #endif
 
-/* MAP_ANONYMOUS is MAP_ANON on some systems, e.g. OpenBSD */
-#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
-#define MAP_ANONYMOUS MAP_ANON
-#endif
-
-/* -----------------------------------------------------------------------------
- * Built-in symbols from the RTS
- */
-
-typedef struct _RtsSymbolVal {
-    char   *lbl;
-    void   *addr;
-} RtsSymbolVal;
-
-#define Maybe_Stable_Names      SymI_HasProto(stg_mkWeakzh)                     \
-                                SymI_HasProto(stg_mkWeakNoFinalizzerzh)         \
-                                SymI_HasProto(stg_addCFinalizzerToWeakzh)       \
-                                SymI_HasProto(stg_makeStableNamezh)             \
-                                SymI_HasProto(stg_finalizzeWeakzh)
-
-#if !defined (mingw32_HOST_OS)
-#define RTS_POSIX_ONLY_SYMBOLS                  \
-      SymI_HasProto(__hscore_get_saved_termios) \
-      SymI_HasProto(__hscore_set_saved_termios) \
-      SymI_HasProto(shutdownHaskellAndSignal)   \
-      SymI_HasProto(signal_handlers)            \
-      SymI_HasProto(stg_sig_install)            \
-      SymI_HasProto(rtsTimerSignal)             \
-      SymI_HasProto(atexit)                     \
-      SymI_NeedsProto(nocldstop)
-#endif
-
-#if defined (cygwin32_HOST_OS)
-#define RTS_MINGW_ONLY_SYMBOLS /**/
-/* Don't have the ability to read import libs / archives, so
- * we have to stupidly list a lot of what libcygwin.a
- * exports; sigh.
- */
-#define RTS_CYGWIN_ONLY_SYMBOLS                          \
-      SymI_HasProto(regfree)                             \
-      SymI_HasProto(regexec)                             \
-      SymI_HasProto(regerror)                            \
-      SymI_HasProto(regcomp)                             \
-      SymI_HasProto(__errno)                             \
-      SymI_HasProto(access)                              \
-      SymI_HasProto(chmod)                               \
-      SymI_HasProto(chdir)                               \
-      SymI_HasProto(close)                               \
-      SymI_HasProto(creat)                               \
-      SymI_HasProto(dup)                                 \
-      SymI_HasProto(dup2)                                \
-      SymI_HasProto(fstat)                               \
-      SymI_HasProto(fcntl)                               \
-      SymI_HasProto(getcwd)                              \
-      SymI_HasProto(getenv)                              \
-      SymI_HasProto(lseek)                               \
-      SymI_HasProto(open)                                \
-      SymI_HasProto(fpathconf)                           \
-      SymI_HasProto(pathconf)                            \
-      SymI_HasProto(stat)                                \
-      SymI_HasProto(pow)                                 \
-      SymI_HasProto(tanh)                                \
-      SymI_HasProto(cosh)                                \
-      SymI_HasProto(sinh)                                \
-      SymI_HasProto(atan)                                \
-      SymI_HasProto(acos)                                \
-      SymI_HasProto(asin)                                \
-      SymI_HasProto(tan)                                 \
-      SymI_HasProto(cos)                                 \
-      SymI_HasProto(sin)                                 \
-      SymI_HasProto(exp)                                 \
-      SymI_HasProto(log)                                 \
-      SymI_HasProto(sqrt)                                \
-      SymI_HasProto(localtime_r)                         \
-      SymI_HasProto(gmtime_r)                            \
-      SymI_HasProto(mktime)                              \
-      SymI_NeedsProto(_imp___tzname)                     \
-      SymI_HasProto(gettimeofday)                        \
-      SymI_HasProto(timezone)                            \
-      SymI_HasProto(tcgetattr)                           \
-      SymI_HasProto(tcsetattr)                           \
-      SymI_HasProto(memcpy)                              \
-      SymI_HasProto(memmove)                             \
-      SymI_HasProto(realloc)                             \
-      SymI_HasProto(malloc)                              \
-      SymI_HasProto(free)                                \
-      SymI_HasProto(fork)                                \
-      SymI_HasProto(lstat)                               \
-      SymI_HasProto(isatty)                              \
-      SymI_HasProto(mkdir)                               \
-      SymI_HasProto(opendir)                             \
-      SymI_HasProto(readdir)                             \
-      SymI_HasProto(rewinddir)                           \
-      SymI_HasProto(closedir)                            \
-      SymI_HasProto(link)                                \
-      SymI_HasProto(mkfifo)                              \
-      SymI_HasProto(pipe)                                \
-      SymI_HasProto(read)                                \
-      SymI_HasProto(rename)                              \
-      SymI_HasProto(rmdir)                               \
-      SymI_HasProto(select)                              \
-      SymI_HasProto(system)                              \
-      SymI_HasProto(write)                               \
-      SymI_HasProto(strcmp)                              \
-      SymI_HasProto(strcpy)                              \
-      SymI_HasProto(strncpy)                             \
-      SymI_HasProto(strerror)                            \
-      SymI_HasProto(sigaddset)                           \
-      SymI_HasProto(sigemptyset)                         \
-      SymI_HasProto(sigprocmask)                         \
-      SymI_HasProto(umask)                               \
-      SymI_HasProto(uname)                               \
-      SymI_HasProto(unlink)                              \
-      SymI_HasProto(utime)                               \
-      SymI_HasProto(waitpid)
-
-#elif defined(mingw32_HOST_OS)
-#define RTS_POSIX_ONLY_SYMBOLS  /**/
-#define RTS_CYGWIN_ONLY_SYMBOLS /**/
-
-#if HAVE_GETTIMEOFDAY
-#define RTS_MINGW_GETTIMEOFDAY_SYM SymI_NeedsProto(gettimeofday)
-#else
-#define RTS_MINGW_GETTIMEOFDAY_SYM /**/
-#endif
-
-#if HAVE___MINGW_VFPRINTF
-#define RTS___MINGW_VFPRINTF_SYM SymI_HasProto(__mingw_vfprintf)
-#else
-#define RTS___MINGW_VFPRINTF_SYM /**/
-#endif
-
-#if defined(i386_HOST_ARCH)
-#define RTS_WIN32_ONLY(X) X
-#else
-#define RTS_WIN32_ONLY(X) /**/
-#endif
-
-#if defined(x86_64_HOST_ARCH)
-#define RTS_WIN64_ONLY(X) X
-#else
-#define RTS_WIN64_ONLY(X) /**/
-#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                           \
-      SymI_HasProto(stg_asyncReadzh)                     \
-      SymI_HasProto(stg_asyncWritezh)                    \
-      SymI_HasProto(stg_asyncDoProczh)                   \
-      SymI_HasProto(getWin32ProgArgv)                    \
-      SymI_HasProto(setWin32ProgArgv)                    \
-      SymI_HasProto(memset)                              \
-      SymI_HasProto(inet_ntoa)                           \
-      SymI_HasProto(inet_addr)                           \
-      SymI_HasProto(htonl)                               \
-      SymI_HasProto(recvfrom)                            \
-      SymI_HasProto(listen)                              \
-      SymI_HasProto(bind)                                \
-      SymI_HasProto(shutdown)                            \
-      SymI_HasProto(connect)                             \
-      SymI_HasProto(htons)                               \
-      SymI_HasProto(ntohs)                               \
-      SymI_HasProto(getservbyname)                       \
-      SymI_HasProto(getservbyport)                       \
-      SymI_HasProto(getprotobynumber)                    \
-      SymI_HasProto(getprotobyname)                      \
-      SymI_HasProto(gethostbyname)                       \
-      SymI_HasProto(gethostbyaddr)                       \
-      SymI_HasProto(gethostname)                         \
-      SymI_HasProto(strcpy)                              \
-      SymI_HasProto(strncpy)                             \
-      SymI_HasProto(abort)                               \
-      RTS_WIN32_ONLY(SymI_NeedsProto(_alloca))           \
-      SymI_HasProto(isxdigit)                            \
-      SymI_HasProto(isupper)                             \
-      SymI_HasProto(ispunct)                             \
-      SymI_HasProto(islower)                             \
-      SymI_HasProto(isspace)                             \
-      SymI_HasProto(isprint)                             \
-      SymI_HasProto(isdigit)                             \
-      SymI_HasProto(iscntrl)                             \
-      SymI_HasProto(isalpha)                             \
-      SymI_HasProto(isalnum)                             \
-      SymI_HasProto(isascii)                             \
-      RTS___MINGW_VFPRINTF_SYM                           \
-      SymI_HasProto(strcmp)                              \
-      SymI_HasProto(memmove)                             \
-      SymI_HasProto(realloc)                             \
-      SymI_HasProto(malloc)                              \
-      SymI_HasProto(pow)                                 \
-      SymI_HasProto(tanh)                                \
-      SymI_HasProto(cosh)                                \
-      SymI_HasProto(sinh)                                \
-      SymI_HasProto(atan)                                \
-      SymI_HasProto(acos)                                \
-      SymI_HasProto(asin)                                \
-      SymI_HasProto(tan)                                 \
-      SymI_HasProto(cos)                                 \
-      SymI_HasProto(sin)                                 \
-      SymI_HasProto(exp)                                 \
-      SymI_HasProto(log)                                 \
-      SymI_HasProto(sqrt)                                \
-      SymI_HasProto(powf)                                \
-      SymI_HasProto(tanhf)                               \
-      SymI_HasProto(coshf)                               \
-      SymI_HasProto(sinhf)                               \
-      SymI_HasProto(atanf)                               \
-      SymI_HasProto(acosf)                               \
-      SymI_HasProto(asinf)                               \
-      SymI_HasProto(tanf)                                \
-      SymI_HasProto(cosf)                                \
-      SymI_HasProto(sinf)                                \
-      SymI_HasProto(expf)                                \
-      SymI_HasProto(logf)                                \
-      SymI_HasProto(sqrtf)                               \
-      SymI_HasProto(erf)                                 \
-      SymI_HasProto(erfc)                                \
-      SymI_HasProto(erff)                                \
-      SymI_HasProto(erfcf)                               \
-      SymI_HasProto(memcpy)                              \
-      SymI_HasProto(rts_InstallConsoleEvent)             \
-      SymI_HasProto(rts_ConsoleHandlerDone)              \
-      SymI_NeedsProto(mktime)                            \
-      RTS_WIN32_ONLY(SymI_NeedsProto(_imp___timezone))   \
-      RTS_WIN32_ONLY(SymI_NeedsProto(_imp___tzname))     \
-      RTS_WIN32_ONLY(SymI_NeedsProto(_imp__tzname))      \
-      RTS_WIN32_ONLY(SymI_NeedsProto(_imp___iob))        \
-      RTS_WIN32_ONLY(SymI_NeedsProto(_imp___osver))      \
-      SymI_NeedsProto(localtime)                         \
-      SymI_NeedsProto(gmtime)                            \
-      SymI_NeedsProto(opendir)                           \
-      SymI_NeedsProto(readdir)                           \
-      SymI_NeedsProto(rewinddir)                         \
-      RTS_WIN32_ONLY(SymI_NeedsProto(_imp____mb_cur_max)) \
-      RTS_WIN32_ONLY(SymI_NeedsProto(_imp___pctype))     \
-      RTS_WIN32_ONLY(SymI_NeedsProto(__chkstk))          \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp___iob_func))  \
-      RTS_WIN64_ONLY(SymI_NeedsProto(___chkstk_ms))      \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_localeconv))  \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_islower))     \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_isspace))     \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_isxdigit))    \
-      RTS_WIN64_ONLY(SymI_HasProto(close))               \
-      RTS_WIN64_ONLY(SymI_HasProto(read))                \
-      RTS_WIN64_ONLY(SymI_HasProto(dup))                 \
-      RTS_WIN64_ONLY(SymI_HasProto(dup2))                \
-      RTS_WIN64_ONLY(SymI_HasProto(write))               \
-      SymI_NeedsProto(getpid)                            \
-      RTS_WIN64_ONLY(SymI_HasProto(access))              \
-      SymI_HasProto(chmod)                               \
-      RTS_WIN64_ONLY(SymI_HasProto(creat))               \
-      RTS_WIN64_ONLY(SymI_HasProto(umask))               \
-      SymI_HasProto(unlink)                              \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp__errno))      \
-      RTS_WIN64_ONLY(SymI_NeedsProto(ftruncate64))       \
-      RTS_WIN64_ONLY(SymI_HasProto(setmode))             \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp__wstat64))    \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp__fstat64))    \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp__wsopen))     \
-      RTS_WIN64_ONLY(SymI_HasProto(__imp__environ))      \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_GetFileAttributesA))          \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_GetFileInformationByHandle))  \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_GetFileType))                 \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_GetLastError))                \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_QueryPerformanceFrequency))   \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_QueryPerformanceCounter))     \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_GetTickCount))                \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_WaitForSingleObject))         \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_PeekConsoleInputA))           \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_ReadConsoleInputA))           \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_PeekNamedPipe))               \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp__isatty))                     \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_select))                      \
-      RTS_WIN64_ONLY(SymI_HasProto(isatty))                              \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp__get_osfhandle))              \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_GetConsoleMode))              \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_SetConsoleMode))              \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_FlushConsoleInputBuffer))     \
-      RTS_WIN64_ONLY(SymI_HasProto(free))                                \
-      RTS_WIN64_ONLY(SymI_NeedsProto(raise))                             \
-      RTS_WIN64_ONLY(SymI_NeedsProto(_getpid))                           \
-      RTS_WIN64_ONLY(SymI_HasProto(getc))                                \
-      RTS_WIN64_ONLY(SymI_HasProto(ungetc))                              \
-      RTS_WIN64_ONLY(SymI_HasProto(puts))                                \
-      RTS_WIN64_ONLY(SymI_HasProto(putc))                                \
-      RTS_WIN64_ONLY(SymI_HasProto(putchar))                             \
-      RTS_WIN64_ONLY(SymI_HasProto(fputc))                               \
-      RTS_WIN64_ONLY(SymI_HasProto(fread))                               \
-      RTS_WIN64_ONLY(SymI_HasProto(fwrite))                              \
-      RTS_WIN64_ONLY(SymI_HasProto(ferror))                              \
-      RTS_WIN64_ONLY(SymI_HasProto(printf))                              \
-      RTS_WIN64_ONLY(SymI_HasProto(fprintf))                             \
-      RTS_WIN64_ONLY(SymI_HasProto(sprintf))                             \
-      RTS_WIN64_ONLY(SymI_HasProto(vsprintf))                            \
-      RTS_WIN64_ONLY(SymI_HasProto(sscanf))                              \
-      RTS_WIN64_ONLY(SymI_HasProto(ldexp))                               \
-      RTS_WIN64_ONLY(SymI_HasProto(strlen))                              \
-      RTS_WIN64_ONLY(SymI_HasProto(strnlen))                             \
-      RTS_WIN64_ONLY(SymI_HasProto(strchr))                              \
-      RTS_WIN64_ONLY(SymI_HasProto(strtol))                              \
-      RTS_WIN64_ONLY(SymI_HasProto(strerror))                            \
-      RTS_WIN64_ONLY(SymI_HasProto(memchr))                              \
-      RTS_WIN64_ONLY(SymI_HasProto(memcmp))                              \
-      RTS_WIN64_ONLY(SymI_HasProto(wcscpy))                              \
-      RTS_WIN64_ONLY(SymI_HasProto(wcslen))                              \
-      RTS_WIN64_ONLY(SymI_HasProto(_lseeki64))                           \
-      RTS_WIN64_ONLY(SymI_HasProto(_wchmod))                             \
-      RTS_WIN64_ONLY(SymI_HasProto(closesocket))                         \
-      RTS_WIN64_ONLY(SymI_HasProto(send))                                \
-      RTS_WIN64_ONLY(SymI_HasProto(recv))                                \
-      RTS_WIN64_ONLY(SymI_HasProto(bsearch))                             \
-      RTS_WIN64_ONLY(SymI_HasProto(CommandLineToArgvW))                  \
-      RTS_WIN64_ONLY(SymI_HasProto(CreateBitmap))                        \
-      RTS_WIN64_ONLY(SymI_HasProto(CreateBitmapIndirect))                \
-      RTS_WIN64_ONLY(SymI_HasProto(CreateCompatibleBitmap))              \
-      RTS_WIN64_ONLY(SymI_HasProto(CreateDIBPatternBrushPt))             \
-      RTS_WIN64_ONLY(SymI_HasProto(CreateDIBitmap))                      \
-      RTS_WIN64_ONLY(SymI_HasProto(SetBitmapDimensionEx))                \
-      RTS_WIN64_ONLY(SymI_HasProto(GetBitmapDimensionEx))                \
-      RTS_WIN64_ONLY(SymI_HasProto(GetStockObject))                      \
-      RTS_WIN64_ONLY(SymI_HasProto(GetObjectW))                          \
-      RTS_WIN64_ONLY(SymI_HasProto(DeleteObject))                        \
-      RTS_WIN64_ONLY(SymI_HasProto(SetDIBits))                           \
-      RTS_WIN64_ONLY(SymI_HasProto(GetDIBits))                           \
-      RTS_WIN64_ONLY(SymI_HasProto(CreateSolidBrush))                    \
-      RTS_WIN64_ONLY(SymI_HasProto(CreateHatchBrush))                    \
-      RTS_WIN64_ONLY(SymI_HasProto(CreatePatternBrush))                  \
-      RTS_WIN64_ONLY(SymI_HasProto(CreateFontW))                         \
-      RTS_WIN64_ONLY(SymI_HasProto(AngleArc)) \
-      RTS_WIN64_ONLY(SymI_HasProto(Arc)) \
-      RTS_WIN64_ONLY(SymI_HasProto(ArcTo)) \
-      RTS_WIN64_ONLY(SymI_HasProto(BeginPath)) \
-      RTS_WIN64_ONLY(SymI_HasProto(BitBlt)) \
-      RTS_WIN64_ONLY(SymI_HasProto(CancelDC)) \
-      RTS_WIN64_ONLY(SymI_HasProto(Chord)) \
-      RTS_WIN64_ONLY(SymI_HasProto(CloseFigure)) \
-      RTS_WIN64_ONLY(SymI_HasProto(CombineRgn)) \
-      RTS_WIN64_ONLY(SymI_HasProto(CreateCompatibleDC)) \
-      RTS_WIN64_ONLY(SymI_HasProto(CreateEllipticRgn)) \
-      RTS_WIN64_ONLY(SymI_HasProto(CreateEllipticRgnIndirect)) \
-      RTS_WIN64_ONLY(SymI_HasProto(CreatePen)) \
-      RTS_WIN64_ONLY(SymI_HasProto(CreatePolygonRgn)) \
-      RTS_WIN64_ONLY(SymI_HasProto(CreateRectRgn)) \
-      RTS_WIN64_ONLY(SymI_HasProto(CreateRectRgnIndirect)) \
-      RTS_WIN64_ONLY(SymI_HasProto(CreateRoundRectRgn)) \
-      RTS_WIN64_ONLY(SymI_HasProto(DeleteDC)) \
-      RTS_WIN64_ONLY(SymI_HasProto(Ellipse)) \
-      RTS_WIN64_ONLY(SymI_HasProto(EndPath)) \
-      RTS_WIN64_ONLY(SymI_HasProto(EqualRgn)) \
-      RTS_WIN64_ONLY(SymI_HasProto(ExtSelectClipRgn)) \
-      RTS_WIN64_ONLY(SymI_HasProto(FillPath)) \
-      RTS_WIN64_ONLY(SymI_HasProto(FillRgn)) \
-      RTS_WIN64_ONLY(SymI_HasProto(FlattenPath)) \
-      RTS_WIN64_ONLY(SymI_HasProto(FrameRgn)) \
-      RTS_WIN64_ONLY(SymI_HasProto(GetArcDirection)) \
-      RTS_WIN64_ONLY(SymI_HasProto(GetBkColor)) \
-      RTS_WIN64_ONLY(SymI_HasProto(GetBkMode)) \
-      RTS_WIN64_ONLY(SymI_HasProto(GetBrushOrgEx)) \
-      RTS_WIN64_ONLY(SymI_HasProto(GetCurrentObject)) \
-      RTS_WIN64_ONLY(SymI_HasProto(GetDCOrgEx)) \
-      RTS_WIN64_ONLY(SymI_HasProto(GetGraphicsMode)) \
-      RTS_WIN64_ONLY(SymI_HasProto(GetMiterLimit)) \
-      RTS_WIN64_ONLY(SymI_HasProto(GetPolyFillMode)) \
-      RTS_WIN64_ONLY(SymI_HasProto(GetRgnBox)) \
-      RTS_WIN64_ONLY(SymI_HasProto(GetStretchBltMode)) \
-      RTS_WIN64_ONLY(SymI_HasProto(GetTextAlign)) \
-      RTS_WIN64_ONLY(SymI_HasProto(GetTextCharacterExtra)) \
-      RTS_WIN64_ONLY(SymI_HasProto(GetTextColor)) \
-      RTS_WIN64_ONLY(SymI_HasProto(GetTextExtentPoint32W)) \
-      RTS_WIN64_ONLY(SymI_HasProto(InvertRgn)) \
-      RTS_WIN64_ONLY(SymI_HasProto(LineTo)) \
-      RTS_WIN64_ONLY(SymI_HasProto(MaskBlt)) \
-      RTS_WIN64_ONLY(SymI_HasProto(MoveToEx)) \
-      RTS_WIN64_ONLY(SymI_HasProto(OffsetRgn)) \
-      RTS_WIN64_ONLY(SymI_HasProto(PaintRgn)) \
-      RTS_WIN64_ONLY(SymI_HasProto(PathToRegion)) \
-      RTS_WIN64_ONLY(SymI_HasProto(Pie)) \
-      RTS_WIN64_ONLY(SymI_HasProto(PlgBlt)) \
-      RTS_WIN64_ONLY(SymI_HasProto(PolyBezier)) \
-      RTS_WIN64_ONLY(SymI_HasProto(PolyBezierTo)) \
-      RTS_WIN64_ONLY(SymI_HasProto(Polygon)) \
-      RTS_WIN64_ONLY(SymI_HasProto(Polyline)) \
-      RTS_WIN64_ONLY(SymI_HasProto(PolylineTo)) \
-      RTS_WIN64_ONLY(SymI_HasProto(PtInRegion)) \
-      RTS_WIN64_ONLY(SymI_HasProto(Rectangle)) \
-      RTS_WIN64_ONLY(SymI_HasProto(RectInRegion)) \
-      RTS_WIN64_ONLY(SymI_HasProto(RestoreDC)) \
-      RTS_WIN64_ONLY(SymI_HasProto(RoundRect)) \
-      RTS_WIN64_ONLY(SymI_HasProto(SaveDC)) \
-      RTS_WIN64_ONLY(SymI_HasProto(SelectClipPath)) \
-      RTS_WIN64_ONLY(SymI_HasProto(SelectClipRgn)) \
-      RTS_WIN64_ONLY(SymI_HasProto(SelectObject)) \
-      RTS_WIN64_ONLY(SymI_HasProto(SelectPalette)) \
-      RTS_WIN64_ONLY(SymI_HasProto(SetArcDirection)) \
-      RTS_WIN64_ONLY(SymI_HasProto(SetBkColor)) \
-      RTS_WIN64_ONLY(SymI_HasProto(SetBkMode)) \
-      RTS_WIN64_ONLY(SymI_HasProto(SetBrushOrgEx)) \
-      RTS_WIN64_ONLY(SymI_HasProto(SetGraphicsMode)) \
-      RTS_WIN64_ONLY(SymI_HasProto(SetMiterLimit)) \
-      RTS_WIN64_ONLY(SymI_HasProto(SetPolyFillMode)) \
-      RTS_WIN64_ONLY(SymI_HasProto(SetStretchBltMode)) \
-      RTS_WIN64_ONLY(SymI_HasProto(SetTextAlign)) \
-      RTS_WIN64_ONLY(SymI_HasProto(SetTextCharacterExtra)) \
-      RTS_WIN64_ONLY(SymI_HasProto(SetTextColor)) \
-      RTS_WIN64_ONLY(SymI_HasProto(StretchBlt)) \
-      RTS_WIN64_ONLY(SymI_HasProto(StrokeAndFillPath)) \
-      RTS_WIN64_ONLY(SymI_HasProto(StrokePath)) \
-      RTS_WIN64_ONLY(SymI_HasProto(TextOutW)) \
-      RTS_WIN64_ONLY(SymI_HasProto(timeGetTime)) \
-      RTS_WIN64_ONLY(SymI_HasProto(WidenPath)) \
-      RTS_WIN64_ONLY(SymI_HasProto(GetFileSecurityW)) \
-      RTS_WIN64_ONLY(SymI_HasProto(RegCloseKey)) \
-      RTS_WIN64_ONLY(SymI_HasProto(RegConnectRegistryW)) \
-      RTS_WIN64_ONLY(SymI_HasProto(RegCreateKeyExW)) \
-      RTS_WIN64_ONLY(SymI_HasProto(RegCreateKeyW)) \
-      RTS_WIN64_ONLY(SymI_HasProto(RegDeleteKeyW)) \
-      RTS_WIN64_ONLY(SymI_HasProto(RegDeleteValueW)) \
-      RTS_WIN64_ONLY(SymI_HasProto(RegEnumKeyW)) \
-      RTS_WIN64_ONLY(SymI_HasProto(RegEnumValueW)) \
-      RTS_WIN64_ONLY(SymI_HasProto(RegFlushKey)) \
-      RTS_WIN64_ONLY(SymI_HasProto(RegLoadKeyW)) \
-      RTS_WIN64_ONLY(SymI_HasProto(RegNotifyChangeKeyValue)) \
-      RTS_WIN64_ONLY(SymI_HasProto(RegOpenKeyExW)) \
-      RTS_WIN64_ONLY(SymI_HasProto(RegOpenKeyW)) \
-      RTS_WIN64_ONLY(SymI_HasProto(RegQueryInfoKeyW)) \
-      RTS_WIN64_ONLY(SymI_HasProto(RegQueryValueExW)) \
-      RTS_WIN64_ONLY(SymI_HasProto(RegQueryValueW)) \
-      RTS_WIN64_ONLY(SymI_HasProto(RegReplaceKeyW)) \
-      RTS_WIN64_ONLY(SymI_HasProto(RegRestoreKeyW)) \
-      RTS_WIN64_ONLY(SymI_HasProto(RegSaveKeyW)) \
-      RTS_WIN64_ONLY(SymI_HasProto(RegSetValueExW)) \
-      RTS_WIN64_ONLY(SymI_HasProto(RegSetValueW)) \
-      RTS_WIN64_ONLY(SymI_HasProto(RegUnLoadKeyW)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(SHGetFolderPathW)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_SetWindowLongPtrW)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_GetWindowLongPtrW)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_MenuItemFromPoint)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_ChildWindowFromPoint)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_ChildWindowFromPointEx)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_DeleteObject)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_UnmapViewOfFile)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_CloseHandle)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_FreeLibrary)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_GetMessageW)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_TranslateMessage)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_DispatchMessageW)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_DefWindowProcW)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_GetDIBits)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_GlobalAlloc)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_GlobalFree)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_CreateFileW)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_WriteFile)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_CreateCompatibleBitmap)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_SelectObject)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_Polygon)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_FormatMessageW)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp__localtime64)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp__tzname)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp__timezone)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_CreatePipe)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_SetHandleInformation)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_GetStdHandle)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_GetCurrentProcess)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_DuplicateHandle)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_CreateProcessW)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_TerminateProcess)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp__open_osfhandle)) \
-      RTS_WIN64_ONLY(SymI_NeedsProto(__imp_GetExitCodeProcess)) \
-      RTS_MINGW_GETTIMEOFDAY_SYM                         \
-      SymI_NeedsProto(closedir)
-
-#else
-#define RTS_MINGW_ONLY_SYMBOLS /**/
-#define RTS_CYGWIN_ONLY_SYMBOLS /**/
-#endif
-
-
-#if defined(darwin_HOST_OS) && HAVE_PRINTF_LDBLSTUB
-#define RTS_DARWIN_ONLY_SYMBOLS                             \
-     SymI_NeedsProto(asprintf$LDBLStub)                     \
-     SymI_NeedsProto(err$LDBLStub)                          \
-     SymI_NeedsProto(errc$LDBLStub)                         \
-     SymI_NeedsProto(errx$LDBLStub)                         \
-     SymI_NeedsProto(fprintf$LDBLStub)                      \
-     SymI_NeedsProto(fscanf$LDBLStub)                       \
-     SymI_NeedsProto(fwprintf$LDBLStub)                     \
-     SymI_NeedsProto(fwscanf$LDBLStub)                      \
-     SymI_NeedsProto(printf$LDBLStub)                       \
-     SymI_NeedsProto(scanf$LDBLStub)                        \
-     SymI_NeedsProto(snprintf$LDBLStub)                     \
-     SymI_NeedsProto(sprintf$LDBLStub)                      \
-     SymI_NeedsProto(sscanf$LDBLStub)                       \
-     SymI_NeedsProto(strtold$LDBLStub)                      \
-     SymI_NeedsProto(swprintf$LDBLStub)                     \
-     SymI_NeedsProto(swscanf$LDBLStub)                      \
-     SymI_NeedsProto(syslog$LDBLStub)                       \
-     SymI_NeedsProto(vasprintf$LDBLStub)                    \
-     SymI_NeedsProto(verr$LDBLStub)                         \
-     SymI_NeedsProto(verrc$LDBLStub)                        \
-     SymI_NeedsProto(verrx$LDBLStub)                        \
-     SymI_NeedsProto(vfprintf$LDBLStub)                     \
-     SymI_NeedsProto(vfscanf$LDBLStub)                      \
-     SymI_NeedsProto(vfwprintf$LDBLStub)                    \
-     SymI_NeedsProto(vfwscanf$LDBLStub)                     \
-     SymI_NeedsProto(vprintf$LDBLStub)                      \
-     SymI_NeedsProto(vscanf$LDBLStub)                       \
-     SymI_NeedsProto(vsnprintf$LDBLStub)                    \
-     SymI_NeedsProto(vsprintf$LDBLStub)                     \
-     SymI_NeedsProto(vsscanf$LDBLStub)                      \
-     SymI_NeedsProto(vswprintf$LDBLStub)                    \
-     SymI_NeedsProto(vswscanf$LDBLStub)                     \
-     SymI_NeedsProto(vsyslog$LDBLStub)                      \
-     SymI_NeedsProto(vwarn$LDBLStub)                        \
-     SymI_NeedsProto(vwarnc$LDBLStub)                       \
-     SymI_NeedsProto(vwarnx$LDBLStub)                       \
-     SymI_NeedsProto(vwprintf$LDBLStub)                     \
-     SymI_NeedsProto(vwscanf$LDBLStub)                      \
-     SymI_NeedsProto(warn$LDBLStub)                         \
-     SymI_NeedsProto(warnc$LDBLStub)                        \
-     SymI_NeedsProto(warnx$LDBLStub)                        \
-     SymI_NeedsProto(wcstold$LDBLStub)                      \
-     SymI_NeedsProto(wprintf$LDBLStub)                      \
-     SymI_NeedsProto(wscanf$LDBLStub)
-#else
-#define RTS_DARWIN_ONLY_SYMBOLS
-#endif
-
-#ifndef SMP
-# define MAIN_CAP_SYM SymI_HasProto(MainCapability)
-#else
-# define MAIN_CAP_SYM
-#endif
-
-#if !defined(mingw32_HOST_OS)
-#define RTS_USER_SIGNALS_SYMBOLS        \
-   SymI_HasProto(setIOManagerControlFd) \
-   SymI_HasProto(setTimerManagerControlFd) \
-   SymI_HasProto(setIOManagerWakeupFd)  \
-   SymI_HasProto(ioManagerWakeup)       \
-   SymI_HasProto(blockUserSignals)      \
-   SymI_HasProto(unblockUserSignals)
-#else
-#define RTS_USER_SIGNALS_SYMBOLS        \
-   SymI_HasProto(ioManagerWakeup)       \
-   SymI_HasProto(sendIOManagerEvent)    \
-   SymI_HasProto(readIOManagerEvent)    \
-   SymI_HasProto(getIOManagerEvent)     \
-   SymI_HasProto(console_handler)
-#endif
-
-#define RTS_LIBFFI_SYMBOLS                                  \
-     SymE_NeedsProto(ffi_prep_cif)                          \
-     SymE_NeedsProto(ffi_call)                              \
-     SymE_NeedsProto(ffi_type_void)                         \
-     SymE_NeedsProto(ffi_type_float)                        \
-     SymE_NeedsProto(ffi_type_double)                       \
-     SymE_NeedsProto(ffi_type_sint64)                       \
-     SymE_NeedsProto(ffi_type_uint64)                       \
-     SymE_NeedsProto(ffi_type_sint32)                       \
-     SymE_NeedsProto(ffi_type_uint32)                       \
-     SymE_NeedsProto(ffi_type_sint16)                       \
-     SymE_NeedsProto(ffi_type_uint16)                       \
-     SymE_NeedsProto(ffi_type_sint8)                        \
-     SymE_NeedsProto(ffi_type_uint8)                        \
-     SymE_NeedsProto(ffi_type_pointer)
-
-#ifdef TABLES_NEXT_TO_CODE
-#define RTS_RET_SYMBOLS /* nothing */
-#else
-#define RTS_RET_SYMBOLS                                 \
-      SymI_HasProto(stg_enter_ret)                      \
-      SymI_HasProto(stg_gc_fun_ret)                     \
-      SymI_HasProto(stg_ap_v_ret)                       \
-      SymI_HasProto(stg_ap_f_ret)                       \
-      SymI_HasProto(stg_ap_d_ret)                       \
-      SymI_HasProto(stg_ap_l_ret)                       \
-      SymI_HasProto(stg_ap_v16_ret)                     \
-      SymI_HasProto(stg_ap_v32_ret)                     \
-      SymI_HasProto(stg_ap_v64_ret)                     \
-      SymI_HasProto(stg_ap_n_ret)                       \
-      SymI_HasProto(stg_ap_p_ret)                       \
-      SymI_HasProto(stg_ap_pv_ret)                      \
-      SymI_HasProto(stg_ap_pp_ret)                      \
-      SymI_HasProto(stg_ap_ppv_ret)                     \
-      SymI_HasProto(stg_ap_ppp_ret)                     \
-      SymI_HasProto(stg_ap_pppv_ret)                    \
-      SymI_HasProto(stg_ap_pppp_ret)                    \
-      SymI_HasProto(stg_ap_ppppp_ret)                   \
-      SymI_HasProto(stg_ap_pppppp_ret)
-#endif
-
-/* Modules compiled with -ticky may mention ticky counters */
-/* This list should marry up with the one in $(TOP)/includes/stg/Ticky.h */
-#define RTS_TICKY_SYMBOLS                               \
-      SymI_NeedsProto(ticky_entry_ctrs)                 \
-      SymI_NeedsProto(top_ct)                           \
-                                                        \
-      SymI_HasProto(ENT_VIA_NODE_ctr)                   \
-      SymI_HasProto(ENT_STATIC_THK_SINGLE_ctr)          \
-      SymI_HasProto(ENT_STATIC_THK_MANY_ctr)            \
-      SymI_HasProto(ENT_DYN_THK_SINGLE_ctr)             \
-      SymI_HasProto(ENT_DYN_THK_MANY_ctr)               \
-      SymI_HasProto(ENT_STATIC_FUN_DIRECT_ctr)          \
-      SymI_HasProto(ENT_DYN_FUN_DIRECT_ctr)             \
-      SymI_HasProto(ENT_STATIC_CON_ctr)                 \
-      SymI_HasProto(ENT_DYN_CON_ctr)                    \
-      SymI_HasProto(ENT_STATIC_IND_ctr)                 \
-      SymI_HasProto(ENT_DYN_IND_ctr)                    \
-      SymI_HasProto(ENT_PERM_IND_ctr)                   \
-      SymI_HasProto(ENT_PAP_ctr)                        \
-      SymI_HasProto(ENT_AP_ctr)                         \
-      SymI_HasProto(ENT_AP_STACK_ctr)                   \
-      SymI_HasProto(ENT_BH_ctr)                         \
-      SymI_HasProto(ENT_LNE_ctr)                        \
-      SymI_HasProto(UNKNOWN_CALL_ctr)                   \
-      SymI_HasProto(SLOW_CALL_fast_v16_ctr)                  \
-      SymI_HasProto(SLOW_CALL_fast_v_ctr)                    \
-      SymI_HasProto(SLOW_CALL_fast_f_ctr)                    \
-      SymI_HasProto(SLOW_CALL_fast_d_ctr)                    \
-      SymI_HasProto(SLOW_CALL_fast_l_ctr)                    \
-      SymI_HasProto(SLOW_CALL_fast_n_ctr)                    \
-      SymI_HasProto(SLOW_CALL_fast_p_ctr)                    \
-      SymI_HasProto(SLOW_CALL_fast_pv_ctr)                   \
-      SymI_HasProto(SLOW_CALL_fast_pp_ctr)                   \
-      SymI_HasProto(SLOW_CALL_fast_ppv_ctr)                  \
-      SymI_HasProto(SLOW_CALL_fast_ppp_ctr)                  \
-      SymI_HasProto(SLOW_CALL_fast_pppv_ctr)                 \
-      SymI_HasProto(SLOW_CALL_fast_pppp_ctr)                 \
-      SymI_HasProto(SLOW_CALL_fast_ppppp_ctr)                \
-      SymI_HasProto(SLOW_CALL_fast_pppppp_ctr)               \
-      SymI_HasProto(VERY_SLOW_CALL_ctr)                \
-      SymI_HasProto(ticky_slow_call_unevald)            \
-      SymI_HasProto(SLOW_CALL_ctr)                      \
-      SymI_HasProto(MULTI_CHUNK_SLOW_CALL_ctr)          \
-      SymI_HasProto(MULTI_CHUNK_SLOW_CALL_CHUNKS_ctr)   \
-      SymI_HasProto(KNOWN_CALL_ctr)                     \
-      SymI_HasProto(KNOWN_CALL_TOO_FEW_ARGS_ctr)        \
-      SymI_HasProto(KNOWN_CALL_EXTRA_ARGS_ctr)          \
-      SymI_HasProto(SLOW_CALL_FUN_TOO_FEW_ctr)          \
-      SymI_HasProto(SLOW_CALL_FUN_CORRECT_ctr)          \
-      SymI_HasProto(SLOW_CALL_FUN_TOO_MANY_ctr)         \
-      SymI_HasProto(SLOW_CALL_PAP_TOO_FEW_ctr)          \
-      SymI_HasProto(SLOW_CALL_PAP_CORRECT_ctr)          \
-      SymI_HasProto(SLOW_CALL_PAP_TOO_MANY_ctr)         \
-      SymI_HasProto(SLOW_CALL_UNEVALD_ctr)              \
-      SymI_HasProto(UPDF_OMITTED_ctr)                   \
-      SymI_HasProto(UPDF_PUSHED_ctr)                    \
-      SymI_HasProto(CATCHF_PUSHED_ctr)                  \
-      SymI_HasProto(UPDF_RCC_PUSHED_ctr)                \
-      SymI_HasProto(UPDF_RCC_OMITTED_ctr)               \
-      SymI_HasProto(UPD_SQUEEZED_ctr)                   \
-      SymI_HasProto(UPD_CON_IN_NEW_ctr)                 \
-      SymI_HasProto(UPD_CON_IN_PLACE_ctr)               \
-      SymI_HasProto(UPD_PAP_IN_NEW_ctr)                 \
-      SymI_HasProto(UPD_PAP_IN_PLACE_ctr)               \
-      SymI_HasProto(ALLOC_HEAP_ctr)                     \
-      SymI_HasProto(ALLOC_HEAP_tot)                     \
-      SymI_HasProto(HEAP_CHK_ctr)                       \
-      SymI_HasProto(STK_CHK_ctr)                        \
-      SymI_HasProto(ALLOC_RTS_ctr)                      \
-      SymI_HasProto(ALLOC_RTS_tot)                      \
-      SymI_HasProto(ALLOC_FUN_ctr)                      \
-      SymI_HasProto(ALLOC_FUN_adm)                      \
-      SymI_HasProto(ALLOC_FUN_gds)                      \
-      SymI_HasProto(ALLOC_FUN_slp)                      \
-      SymI_HasProto(UPD_NEW_IND_ctr)                    \
-      SymI_HasProto(UPD_NEW_PERM_IND_ctr)               \
-      SymI_HasProto(UPD_OLD_IND_ctr)                    \
-      SymI_HasProto(UPD_OLD_PERM_IND_ctr)               \
-      SymI_HasProto(UPD_CAF_BH_UPDATABLE_ctr)           \
-      SymI_HasProto(UPD_CAF_BH_SINGLE_ENTRY_ctr)        \
-      SymI_HasProto(GC_SEL_ABANDONED_ctr)               \
-      SymI_HasProto(GC_SEL_MINOR_ctr)                   \
-      SymI_HasProto(GC_SEL_MAJOR_ctr)                   \
-      SymI_HasProto(GC_FAILED_PROMOTION_ctr)            \
-      SymI_HasProto(ALLOC_UP_THK_ctr)                   \
-      SymI_HasProto(ALLOC_SE_THK_ctr)                   \
-      SymI_HasProto(ALLOC_THK_adm)                      \
-      SymI_HasProto(ALLOC_THK_gds)                      \
-      SymI_HasProto(ALLOC_THK_slp)                      \
-      SymI_HasProto(ALLOC_CON_ctr)                      \
-      SymI_HasProto(ALLOC_CON_adm)                      \
-      SymI_HasProto(ALLOC_CON_gds)                      \
-      SymI_HasProto(ALLOC_CON_slp)                      \
-      SymI_HasProto(ALLOC_TUP_ctr)                      \
-      SymI_HasProto(ALLOC_TUP_adm)                      \
-      SymI_HasProto(ALLOC_TUP_gds)                      \
-      SymI_HasProto(ALLOC_TUP_slp)                      \
-      SymI_HasProto(ALLOC_BH_ctr)                       \
-      SymI_HasProto(ALLOC_BH_adm)                       \
-      SymI_HasProto(ALLOC_BH_gds)                       \
-      SymI_HasProto(ALLOC_BH_slp)                       \
-      SymI_HasProto(ALLOC_PRIM_ctr)                     \
-      SymI_HasProto(ALLOC_PRIM_adm)                     \
-      SymI_HasProto(ALLOC_PRIM_gds)                     \
-      SymI_HasProto(ALLOC_PRIM_slp)                     \
-      SymI_HasProto(ALLOC_PAP_ctr)                      \
-      SymI_HasProto(ALLOC_PAP_adm)                      \
-      SymI_HasProto(ALLOC_PAP_gds)                      \
-      SymI_HasProto(ALLOC_PAP_slp)                      \
-      SymI_HasProto(ALLOC_TSO_ctr)                      \
-      SymI_HasProto(ALLOC_TSO_adm)                      \
-      SymI_HasProto(ALLOC_TSO_gds)                      \
-      SymI_HasProto(ALLOC_TSO_slp)                      \
-      SymI_HasProto(RET_NEW_ctr)                        \
-      SymI_HasProto(RET_OLD_ctr)                        \
-      SymI_HasProto(RET_UNBOXED_TUP_ctr)                \
-      SymI_HasProto(RET_SEMI_loads_avoided)
-
-
-// On most platforms, the garbage collector rewrites references
-//      to small integer and char objects to a set of common, shared ones.
-//
-// We don't do this when compiling to Windows DLLs at the moment because
-//      it doesn't support cross package data references well.
-//
-#if defined(COMPILING_WINDOWS_DLL)
-#define RTS_INTCHAR_SYMBOLS
-#else
-#define RTS_INTCHAR_SYMBOLS                             \
-      SymI_HasProto(stg_CHARLIKE_closure)               \
-      SymI_HasProto(stg_INTLIKE_closure)
-#endif
-
-
-#define RTS_SYMBOLS                                                     \
-      Maybe_Stable_Names                                                \
-      RTS_TICKY_SYMBOLS                                                 \
-      SymI_HasProto(StgReturn)                                          \
-      SymI_HasProto(stg_gc_noregs)                                      \
-      SymI_HasProto(stg_ret_v_info)                                     \
-      SymI_HasProto(stg_ret_p_info)                                     \
-      SymI_HasProto(stg_ret_n_info)                                     \
-      SymI_HasProto(stg_ret_f_info)                                     \
-      SymI_HasProto(stg_ret_d_info)                                     \
-      SymI_HasProto(stg_ret_l_info)                                     \
-      SymI_HasProto(stg_gc_prim_p)                                      \
-      SymI_HasProto(stg_gc_prim_pp)                                     \
-      SymI_HasProto(stg_gc_prim_n)                                      \
-      SymI_HasProto(stg_enter_info)                                     \
-      SymI_HasProto(__stg_gc_enter_1)                                   \
-      SymI_HasProto(stg_gc_unpt_r1)                                     \
-      SymI_HasProto(stg_gc_unbx_r1)                                     \
-      SymI_HasProto(stg_gc_f1)                                          \
-      SymI_HasProto(stg_gc_d1)                                          \
-      SymI_HasProto(stg_gc_l1)                                          \
-      SymI_HasProto(stg_gc_pp)                                          \
-      SymI_HasProto(stg_gc_ppp)                                         \
-      SymI_HasProto(stg_gc_pppp)                                        \
-      SymI_HasProto(__stg_gc_fun)                                       \
-      SymI_HasProto(stg_gc_fun_info)                                    \
-      SymI_HasProto(stg_yield_noregs)                                   \
-      SymI_HasProto(stg_yield_to_interpreter)                           \
-      SymI_HasProto(stg_block_noregs)                                   \
-      SymI_HasProto(stg_block_takemvar)                                 \
-      SymI_HasProto(stg_block_readmvar)                           \
-      SymI_HasProto(stg_block_putmvar)                                  \
-      MAIN_CAP_SYM                                                      \
-      SymI_HasProto(MallocFailHook)                                     \
-      SymI_HasProto(OnExitHook)                                         \
-      SymI_HasProto(OutOfHeapHook)                                      \
-      SymI_HasProto(StackOverflowHook)                                  \
-      SymI_HasProto(addDLL)                                             \
-      SymI_HasProto(__int_encodeDouble)                                 \
-      SymI_HasProto(__word_encodeDouble)                                \
-      SymI_HasProto(__int_encodeFloat)                                  \
-      SymI_HasProto(__word_encodeFloat)                                 \
-      SymI_HasProto(stg_atomicallyzh)                                   \
-      SymI_HasProto(barf)                                               \
-      SymI_HasProto(deRefStablePtr)                                     \
-      SymI_HasProto(debugBelch)                                         \
-      SymI_HasProto(errorBelch)                                         \
-      SymI_HasProto(sysErrorBelch)                                      \
-      SymI_HasProto(stg_getMaskingStatezh)                              \
-      SymI_HasProto(stg_maskAsyncExceptionszh)                          \
-      SymI_HasProto(stg_maskUninterruptiblezh)                          \
-      SymI_HasProto(stg_catchzh)                                        \
-      SymI_HasProto(stg_catchRetryzh)                                   \
-      SymI_HasProto(stg_catchSTMzh)                                     \
-      SymI_HasProto(stg_checkzh)                                        \
-      SymI_HasProto(closure_flags)                                      \
-      SymI_HasProto(cmp_thread)                                         \
-      SymI_HasProto(createAdjustor)                                     \
-      SymI_HasProto(stg_decodeDoublezu2Intzh)                           \
-      SymI_HasProto(stg_decodeDoublezuInt64zh)                          \
-      SymI_HasProto(stg_decodeFloatzuIntzh)                             \
-      SymI_HasProto(defaultsHook)                                       \
-      SymI_HasProto(stg_delayzh)                                        \
-      SymI_HasProto(stg_deRefWeakzh)                                    \
-      SymI_HasProto(stg_deRefStablePtrzh)                               \
-      SymI_HasProto(dirty_MUT_VAR)                                      \
-      SymI_HasProto(dirty_TVAR)                                         \
-      SymI_HasProto(stg_forkzh)                                         \
-      SymI_HasProto(stg_forkOnzh)                                       \
-      SymI_HasProto(forkProcess)                                        \
-      SymI_HasProto(forkOS_createThread)                                \
-      SymI_HasProto(freeHaskellFunctionPtr)                             \
-      SymI_HasProto(getOrSetGHCConcSignalSignalHandlerStore)            \
-      SymI_HasProto(getOrSetGHCConcWindowsPendingDelaysStore)           \
-      SymI_HasProto(getOrSetGHCConcWindowsIOManagerThreadStore)         \
-      SymI_HasProto(getOrSetGHCConcWindowsProddingStore)                \
-      SymI_HasProto(getOrSetSystemEventThreadEventManagerStore)         \
-      SymI_HasProto(getOrSetSystemEventThreadIOManagerThreadStore)      \
-      SymI_HasProto(getOrSetSystemTimerThreadEventManagerStore)         \
-      SymI_HasProto(getOrSetSystemTimerThreadIOManagerThreadStore)      \
-      SymI_HasProto(getOrSetLibHSghcFastStringTable)                    \
-      SymI_HasProto(getGCStats)                                         \
-      SymI_HasProto(getGCStatsEnabled)                                  \
-      SymI_HasProto(genericRaise)                                       \
-      SymI_HasProto(getProgArgv)                                        \
-      SymI_HasProto(getFullProgArgv)                                    \
-      SymI_HasProto(getStablePtr)                                       \
-      SymI_HasProto(foreignExportStablePtr)                             \
-      SymI_HasProto(hs_init)                                            \
-      SymI_HasProto(hs_exit)                                            \
-      SymI_HasProto(hs_set_argv)                                        \
-      SymI_HasProto(hs_add_root)                                        \
-      SymI_HasProto(hs_perform_gc)                                      \
-      SymI_HasProto(hs_lock_stable_tables)                              \
-      SymI_HasProto(hs_unlock_stable_tables)                            \
-      SymI_HasProto(hs_free_stable_ptr)                                 \
-      SymI_HasProto(hs_free_stable_ptr_unsafe)                          \
-      SymI_HasProto(hs_free_fun_ptr)                                    \
-      SymI_HasProto(hs_hpc_rootModule)                                  \
-      SymI_HasProto(hs_hpc_module)                                      \
-      SymI_HasProto(initLinker)                                         \
-      SymI_HasProto(initLinker_)                                        \
-      SymI_HasProto(stg_unpackClosurezh)                                \
-      SymI_HasProto(stg_getApStackValzh)                                \
-      SymI_HasProto(stg_getSparkzh)                                     \
-      SymI_HasProto(stg_numSparkszh)                                    \
-      SymI_HasProto(stg_isCurrentThreadBoundzh)                         \
-      SymI_HasProto(stg_isEmptyMVarzh)                                  \
-      SymI_HasProto(stg_killThreadzh)                                   \
-      SymI_HasProto(loadArchive)                                        \
-      SymI_HasProto(loadObj)                                            \
-      SymI_HasProto(insertSymbol)                                       \
-      SymI_HasProto(lookupSymbol)                                       \
-      SymI_HasProto(stg_makeStablePtrzh)                                \
-      SymI_HasProto(stg_mkApUpd0zh)                                     \
-      SymI_HasProto(stg_myThreadIdzh)                                   \
-      SymI_HasProto(stg_labelThreadzh)                                  \
-      SymI_HasProto(stg_newArrayzh)                                     \
-      SymI_HasProto(stg_copyArrayzh)                                    \
-      SymI_HasProto(stg_copyMutableArrayzh)                             \
-      SymI_HasProto(stg_copyArrayArrayzh)                               \
-      SymI_HasProto(stg_copyMutableArrayArrayzh)                        \
-      SymI_HasProto(stg_cloneArrayzh)                                   \
-      SymI_HasProto(stg_cloneMutableArrayzh)                            \
-      SymI_HasProto(stg_freezzeArrayzh)                                 \
-      SymI_HasProto(stg_thawArrayzh)                                    \
-      SymI_HasProto(stg_newArrayArrayzh)                                \
-      SymI_HasProto(stg_casArrayzh)                                     \
-      SymI_HasProto(stg_newSmallArrayzh)                                \
-      SymI_HasProto(stg_unsafeThawSmallArrayzh)                         \
-      SymI_HasProto(stg_cloneSmallArrayzh)                              \
-      SymI_HasProto(stg_cloneSmallMutableArrayzh)                       \
-      SymI_HasProto(stg_freezzeSmallArrayzh)                            \
-      SymI_HasProto(stg_thawSmallArrayzh)                               \
-      SymI_HasProto(stg_copySmallArrayzh)                               \
-      SymI_HasProto(stg_copySmallMutableArrayzh)                        \
-      SymI_HasProto(stg_casSmallArrayzh)                                \
-      SymI_HasProto(stg_newBCOzh)                                       \
-      SymI_HasProto(stg_newByteArrayzh)                                 \
-      SymI_HasProto(stg_casIntArrayzh)                                  \
-      SymI_HasProto(stg_newMVarzh)                                      \
-      SymI_HasProto(stg_newMutVarzh)                                    \
-      SymI_HasProto(stg_newTVarzh)                                      \
-      SymI_HasProto(stg_noDuplicatezh)                                  \
-      SymI_HasProto(stg_atomicModifyMutVarzh)                           \
-      SymI_HasProto(stg_casMutVarzh)                                    \
-      SymI_HasProto(stg_newPinnedByteArrayzh)                           \
-      SymI_HasProto(stg_newAlignedPinnedByteArrayzh)                    \
-      SymI_HasProto(stg_shrinkMutableByteArrayzh)                       \
-      SymI_HasProto(stg_resizzeMutableByteArrayzh)                      \
-      SymI_HasProto(newSpark)                                           \
-      SymI_HasProto(performGC)                                          \
-      SymI_HasProto(performMajorGC)                                     \
-      SymI_HasProto(prog_argc)                                          \
-      SymI_HasProto(prog_argv)                                          \
-      SymI_HasProto(stg_putMVarzh)                                      \
-      SymI_HasProto(stg_raisezh)                                        \
-      SymI_HasProto(stg_raiseIOzh)                                      \
-      SymI_HasProto(stg_readTVarzh)                                     \
-      SymI_HasProto(stg_readTVarIOzh)                                   \
-      SymI_HasProto(resumeThread)                                       \
-      SymI_HasProto(setNumCapabilities)                                 \
-      SymI_HasProto(getNumberOfProcessors)                              \
-      SymI_HasProto(resolveObjs)                                        \
-      SymI_HasProto(stg_retryzh)                                        \
-      SymI_HasProto(rts_apply)                                          \
-      SymI_HasProto(rts_checkSchedStatus)                               \
-      SymI_HasProto(rts_eval)                                           \
-      SymI_HasProto(rts_evalIO)                                         \
-      SymI_HasProto(rts_evalLazyIO)                                     \
-      SymI_HasProto(rts_evalStableIO)                                   \
-      SymI_HasProto(rts_eval_)                                          \
-      SymI_HasProto(rts_getBool)                                        \
-      SymI_HasProto(rts_getChar)                                        \
-      SymI_HasProto(rts_getDouble)                                      \
-      SymI_HasProto(rts_getFloat)                                       \
-      SymI_HasProto(rts_getInt)                                         \
-      SymI_HasProto(rts_getInt8)                                        \
-      SymI_HasProto(rts_getInt16)                                       \
-      SymI_HasProto(rts_getInt32)                                       \
-      SymI_HasProto(rts_getInt64)                                       \
-      SymI_HasProto(rts_getPtr)                                         \
-      SymI_HasProto(rts_getFunPtr)                                      \
-      SymI_HasProto(rts_getStablePtr)                                   \
-      SymI_HasProto(rts_getThreadId)                                    \
-      SymI_HasProto(rts_getWord)                                        \
-      SymI_HasProto(rts_getWord8)                                       \
-      SymI_HasProto(rts_getWord16)                                      \
-      SymI_HasProto(rts_getWord32)                                      \
-      SymI_HasProto(rts_getWord64)                                      \
-      SymI_HasProto(rts_lock)                                           \
-      SymI_HasProto(rts_mkBool)                                         \
-      SymI_HasProto(rts_mkChar)                                         \
-      SymI_HasProto(rts_mkDouble)                                       \
-      SymI_HasProto(rts_mkFloat)                                        \
-      SymI_HasProto(rts_mkInt)                                          \
-      SymI_HasProto(rts_mkInt8)                                         \
-      SymI_HasProto(rts_mkInt16)                                        \
-      SymI_HasProto(rts_mkInt32)                                        \
-      SymI_HasProto(rts_mkInt64)                                        \
-      SymI_HasProto(rts_mkPtr)                                          \
-      SymI_HasProto(rts_mkFunPtr)                                       \
-      SymI_HasProto(rts_mkStablePtr)                                    \
-      SymI_HasProto(rts_mkString)                                       \
-      SymI_HasProto(rts_mkWord)                                         \
-      SymI_HasProto(rts_mkWord8)                                        \
-      SymI_HasProto(rts_mkWord16)                                       \
-      SymI_HasProto(rts_mkWord32)                                       \
-      SymI_HasProto(rts_mkWord64)                                       \
-      SymI_HasProto(rts_unlock)                                         \
-      SymI_HasProto(rts_unsafeGetMyCapability)                          \
-      SymI_HasProto(rtsSupportsBoundThreads)                            \
-      SymI_HasProto(rts_isProfiled)                                     \
-      SymI_HasProto(rts_isDynamic)                                      \
-      SymI_HasProto(rts_getThreadAllocationCounter)                     \
-      SymI_HasProto(rts_setThreadAllocationCounter)                     \
-      SymI_HasProto(rts_enableThreadAllocationLimit)                    \
-      SymI_HasProto(rts_disableThreadAllocationLimit)                   \
-      SymI_HasProto(setProgArgv)                                        \
-      SymI_HasProto(startupHaskell)                                     \
-      SymI_HasProto(shutdownHaskell)                                    \
-      SymI_HasProto(shutdownHaskellAndExit)                             \
-      SymI_HasProto(stable_name_table)                                  \
-      SymI_HasProto(stable_ptr_table)                                   \
-      SymI_HasProto(stackOverflow)                                      \
-      SymI_HasProto(stg_CAF_BLACKHOLE_info)                             \
-      SymI_HasProto(stg_BLACKHOLE_info)                                 \
-      SymI_HasProto(__stg_EAGER_BLACKHOLE_info)                         \
-      SymI_HasProto(stg_BLOCKING_QUEUE_CLEAN_info)                      \
-      SymI_HasProto(stg_BLOCKING_QUEUE_DIRTY_info)                      \
-      SymI_HasProto(startTimer)                                         \
-      SymI_HasProto(stg_MVAR_CLEAN_info)                                \
-      SymI_HasProto(stg_MVAR_DIRTY_info)                                \
-      SymI_HasProto(stg_TVAR_CLEAN_info)                                \
-      SymI_HasProto(stg_TVAR_DIRTY_info)                                \
-      SymI_HasProto(stg_IND_STATIC_info)                                \
-      SymI_HasProto(stg_ARR_WORDS_info)                                 \
-      SymI_HasProto(stg_MUT_ARR_PTRS_DIRTY_info)                        \
-      SymI_HasProto(stg_MUT_ARR_PTRS_FROZEN_info)                       \
-      SymI_HasProto(stg_MUT_ARR_PTRS_FROZEN0_info)                      \
-      SymI_HasProto(stg_SMALL_MUT_ARR_PTRS_DIRTY_info)                  \
-      SymI_HasProto(stg_SMALL_MUT_ARR_PTRS_FROZEN_info)                 \
-      SymI_HasProto(stg_SMALL_MUT_ARR_PTRS_FROZEN0_info)                \
-      SymI_HasProto(stg_MUT_VAR_CLEAN_info)                             \
-      SymI_HasProto(stg_MUT_VAR_DIRTY_info)                             \
-      SymI_HasProto(stg_WEAK_info)                                      \
-      SymI_HasProto(stg_ap_v_info)                                      \
-      SymI_HasProto(stg_ap_f_info)                                      \
-      SymI_HasProto(stg_ap_d_info)                                      \
-      SymI_HasProto(stg_ap_l_info)                                      \
-      SymI_HasProto(stg_ap_v16_info)                                    \
-      SymI_HasProto(stg_ap_v32_info)                                    \
-      SymI_HasProto(stg_ap_v64_info)                                    \
-      SymI_HasProto(stg_ap_n_info)                                      \
-      SymI_HasProto(stg_ap_p_info)                                      \
-      SymI_HasProto(stg_ap_pv_info)                                     \
-      SymI_HasProto(stg_ap_pp_info)                                     \
-      SymI_HasProto(stg_ap_ppv_info)                                    \
-      SymI_HasProto(stg_ap_ppp_info)                                    \
-      SymI_HasProto(stg_ap_pppv_info)                                   \
-      SymI_HasProto(stg_ap_pppp_info)                                   \
-      SymI_HasProto(stg_ap_ppppp_info)                                  \
-      SymI_HasProto(stg_ap_pppppp_info)                                 \
-      SymI_HasProto(stg_ap_0_fast)                                      \
-      SymI_HasProto(stg_ap_v_fast)                                      \
-      SymI_HasProto(stg_ap_f_fast)                                      \
-      SymI_HasProto(stg_ap_d_fast)                                      \
-      SymI_HasProto(stg_ap_l_fast)                                      \
-      SymI_HasProto(stg_ap_v16_fast)                                    \
-      SymI_HasProto(stg_ap_v32_fast)                                    \
-      SymI_HasProto(stg_ap_v64_fast)                                    \
-      SymI_HasProto(stg_ap_n_fast)                                      \
-      SymI_HasProto(stg_ap_p_fast)                                      \
-      SymI_HasProto(stg_ap_pv_fast)                                     \
-      SymI_HasProto(stg_ap_pp_fast)                                     \
-      SymI_HasProto(stg_ap_ppv_fast)                                    \
-      SymI_HasProto(stg_ap_ppp_fast)                                    \
-      SymI_HasProto(stg_ap_pppv_fast)                                   \
-      SymI_HasProto(stg_ap_pppp_fast)                                   \
-      SymI_HasProto(stg_ap_ppppp_fast)                                  \
-      SymI_HasProto(stg_ap_pppppp_fast)                                 \
-      SymI_HasProto(stg_ap_1_upd_info)                                  \
-      SymI_HasProto(stg_ap_2_upd_info)                                  \
-      SymI_HasProto(stg_ap_3_upd_info)                                  \
-      SymI_HasProto(stg_ap_4_upd_info)                                  \
-      SymI_HasProto(stg_ap_5_upd_info)                                  \
-      SymI_HasProto(stg_ap_6_upd_info)                                  \
-      SymI_HasProto(stg_ap_7_upd_info)                                  \
-      SymI_HasProto(stg_exit)                                           \
-      SymI_HasProto(stg_sel_0_upd_info)                                 \
-      SymI_HasProto(stg_sel_1_upd_info)                                 \
-      SymI_HasProto(stg_sel_2_upd_info)                                 \
-      SymI_HasProto(stg_sel_3_upd_info)                                 \
-      SymI_HasProto(stg_sel_4_upd_info)                                 \
-      SymI_HasProto(stg_sel_5_upd_info)                                 \
-      SymI_HasProto(stg_sel_6_upd_info)                                 \
-      SymI_HasProto(stg_sel_7_upd_info)                                 \
-      SymI_HasProto(stg_sel_8_upd_info)                                 \
-      SymI_HasProto(stg_sel_9_upd_info)                                 \
-      SymI_HasProto(stg_sel_10_upd_info)                                \
-      SymI_HasProto(stg_sel_11_upd_info)                                \
-      SymI_HasProto(stg_sel_12_upd_info)                                \
-      SymI_HasProto(stg_sel_13_upd_info)                                \
-      SymI_HasProto(stg_sel_14_upd_info)                                \
-      SymI_HasProto(stg_sel_15_upd_info)                                \
-      SymI_HasProto(stg_sel_0_noupd_info)                                 \
-      SymI_HasProto(stg_sel_1_noupd_info)                                 \
-      SymI_HasProto(stg_sel_2_noupd_info)                                 \
-      SymI_HasProto(stg_sel_3_noupd_info)                                 \
-      SymI_HasProto(stg_sel_4_noupd_info)                                 \
-      SymI_HasProto(stg_sel_5_noupd_info)                                 \
-      SymI_HasProto(stg_sel_6_noupd_info)                                 \
-      SymI_HasProto(stg_sel_7_noupd_info)                                 \
-      SymI_HasProto(stg_sel_8_noupd_info)                                 \
-      SymI_HasProto(stg_sel_9_noupd_info)                                 \
-      SymI_HasProto(stg_sel_10_noupd_info)                                \
-      SymI_HasProto(stg_sel_11_noupd_info)                                \
-      SymI_HasProto(stg_sel_12_noupd_info)                                \
-      SymI_HasProto(stg_sel_13_noupd_info)                                \
-      SymI_HasProto(stg_sel_14_noupd_info)                                \
-      SymI_HasProto(stg_sel_15_noupd_info)                                \
-      SymI_HasProto(stg_upd_frame_info)                                 \
-      SymI_HasProto(stg_bh_upd_frame_info)                              \
-      SymI_HasProto(suspendThread)                                      \
-      SymI_HasProto(stg_takeMVarzh)                                     \
-      SymI_HasProto(stg_readMVarzh)                               \
-      SymI_HasProto(stg_threadStatuszh)                                 \
-      SymI_HasProto(stg_tryPutMVarzh)                                   \
-      SymI_HasProto(stg_tryTakeMVarzh)                                  \
-      SymI_HasProto(stg_tryReadMVarzh)                            \
-      SymI_HasProto(stg_unmaskAsyncExceptionszh)                        \
-      SymI_HasProto(unloadObj)                                          \
-      SymI_HasProto(stg_unsafeThawArrayzh)                              \
-      SymI_HasProto(stg_waitReadzh)                                     \
-      SymI_HasProto(stg_waitWritezh)                                    \
-      SymI_HasProto(stg_writeTVarzh)                                    \
-      SymI_HasProto(stg_yieldzh)                                        \
-      SymI_NeedsProto(stg_interp_constr_entry)                          \
-      SymI_HasProto(stg_arg_bitmaps)                                    \
-      SymI_HasProto(large_alloc_lim)                                    \
-      SymI_HasProto(g0)                                                 \
-      SymI_HasProto(allocate)                                           \
-      SymI_HasProto(allocateExec)                                       \
-      SymI_HasProto(flushExec)                                          \
-      SymI_HasProto(freeExec)                                           \
-      SymI_HasProto(getAllocations)                                     \
-      SymI_HasProto(revertCAFs)                                         \
-      SymI_HasProto(RtsFlags)                                           \
-      SymI_NeedsProto(rts_breakpoint_io_action)                         \
-      SymI_NeedsProto(rts_stop_next_breakpoint)                         \
-      SymI_NeedsProto(rts_stop_on_exception)                            \
-      SymI_HasProto(stopTimer)                                          \
-      SymI_HasProto(n_capabilities)                                     \
-      SymI_HasProto(enabled_capabilities)                               \
-      SymI_HasProto(stg_traceCcszh)                                     \
-      SymI_HasProto(stg_traceEventzh)                                   \
-      SymI_HasProto(stg_traceMarkerzh)                                  \
-      SymI_HasProto(getMonotonicNSec)                                   \
-      SymI_HasProto(lockFile)                                           \
-      SymI_HasProto(unlockFile)                                         \
-      SymI_HasProto(startProfTimer)                                     \
-      SymI_HasProto(stopProfTimer)                                      \
-      SymI_HasProto(atomic_inc)                                         \
-      SymI_HasProto(atomic_dec)                                         \
-      SymI_HasProto(hs_spt_lookup)                                      \
-      SymI_HasProto(hs_spt_insert)                                      \
-      SymI_HasProto(hs_spt_remove)                                      \
-      SymI_HasProto(hs_spt_keys)                                        \
-      SymI_HasProto(hs_spt_key_count)                                   \
-      RTS_USER_SIGNALS_SYMBOLS                                          \
-      RTS_INTCHAR_SYMBOLS
-
-
-// 64-bit support functions in libgcc.a
-#if defined(__GNUC__) && SIZEOF_VOID_P <= 4 && !defined(_ABIN32)
-#define RTS_LIBGCC_SYMBOLS                             \
-      SymI_NeedsProto(__divdi3)                        \
-      SymI_NeedsProto(__udivdi3)                       \
-      SymI_NeedsProto(__moddi3)                        \
-      SymI_NeedsProto(__umoddi3)                       \
-      SymI_NeedsProto(__muldi3)                        \
-      SymI_NeedsProto(__ashldi3)                       \
-      SymI_NeedsProto(__ashrdi3)                       \
-      SymI_NeedsProto(__lshrdi3)                       \
-      SymI_NeedsProto(__fixunsdfdi)
-#else
-#define RTS_LIBGCC_SYMBOLS
-#endif
-
-#if defined(darwin_HOST_OS) && defined(powerpc_HOST_ARCH)
-      // Symbols that don't have a leading underscore
-      // on Mac OS X. They have to receive special treatment,
-      // see machoInitSymbolsWithoutUnderscore()
-#define RTS_MACHO_NOUNDERLINE_SYMBOLS                   \
-      SymI_NeedsProto(saveFP)                           \
-      SymI_NeedsProto(restFP)
-#endif
-
-/* entirely bogus claims about types of these symbols */
-#define SymI_NeedsProto(vvv)  extern void vvv(void);
-#if defined(COMPILING_WINDOWS_DLL)
-#define SymE_HasProto(vvv)    SymE_HasProto(vvv);
-#  if defined(x86_64_HOST_ARCH)
-#    define SymE_NeedsProto(vvv)    extern void __imp_ ## vvv (void);
-#  else
-#    define SymE_NeedsProto(vvv)    extern void _imp__ ## vvv (void);
-#  endif
-#else
-#define SymE_NeedsProto(vvv)  SymI_NeedsProto(vvv);
-#define SymE_HasProto(vvv)    SymI_HasProto(vvv)
-#endif
-#define SymI_HasProto(vvv) /**/
-#define SymI_HasProto_redirect(vvv,xxx) /**/
-RTS_SYMBOLS
-RTS_RET_SYMBOLS
-RTS_POSIX_ONLY_SYMBOLS
-RTS_MINGW_ONLY_SYMBOLS
-RTS_CYGWIN_ONLY_SYMBOLS
-RTS_DARWIN_ONLY_SYMBOLS
-RTS_LIBGCC_SYMBOLS
-RTS_LIBFFI_SYMBOLS
-#undef SymI_NeedsProto
-#undef SymI_HasProto
-#undef SymI_HasProto_redirect
-#undef SymE_HasProto
-#undef SymE_NeedsProto
-
-#ifdef LEADING_UNDERSCORE
-#define MAYBE_LEADING_UNDERSCORE_STR(s) ("_" s)
-#else
-#define MAYBE_LEADING_UNDERSCORE_STR(s) (s)
-#endif
-
-#define SymI_HasProto(vvv) { MAYBE_LEADING_UNDERSCORE_STR(#vvv), \
-                    (void*)(&(vvv)) },
-#define SymE_HasProto(vvv) { MAYBE_LEADING_UNDERSCORE_STR(#vvv), \
-            (void*)DLL_IMPORT_DATA_REF(vvv) },
-
-#define SymI_NeedsProto(vvv) SymI_HasProto(vvv)
-#define SymE_NeedsProto(vvv) SymE_HasProto(vvv)
-
-// SymI_HasProto_redirect allows us to redirect references to one symbol to
-// another symbol.  See newCAF/newDynCAF for an example.
-#define SymI_HasProto_redirect(vvv,xxx)   \
-    { MAYBE_LEADING_UNDERSCORE_STR(#vvv), \
-      (void*)(&(xxx)) },
-
-static RtsSymbolVal rtsSyms[] = {
-      RTS_SYMBOLS
-      RTS_RET_SYMBOLS
-      RTS_POSIX_ONLY_SYMBOLS
-      RTS_MINGW_ONLY_SYMBOLS
-      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
-      // lazy pointers as nonlazy.
-      { "dyld_stub_binding_helper", (void*)0xDEADBEEF },
-#endif
-      { 0, 0 } /* sentinel */
-};
-
+static void ghciRemoveSymbolTable(HashTable *table, const SymbolName* key,
+    ObjectCode *owner)
+{
+    RtsSymbolInfo *pinfo = lookupStrHashTable(table, key);
+    if (!pinfo || owner != pinfo->owner) return;
+    removeStrHashTable(table, key, NULL);
+    stgFree(pinfo);
+}
 
 /* -----------------------------------------------------------------------------
  * Insert symbols into hash tables, checking for duplicates.
  *
  * Returns: 0 on failure, nonzero on success
  */
-
+/*
+ Note [weak-symbols-support]
+ -------------------------------------
+ While ghciInsertSymbolTable does implement extensive
+ logic for weak symbol support, weak symbols are not currently
+ fully supported by the RTS. This code is mostly here for COMDAT
+ support which uses the weak symbols support.
+
+ Linking weak symbols defined purely in C code with other C code
+ should also work, probably. Observing weak symbols in Haskell
+ won't.
+
+ Some test have been written for weak symbols but have been disabled
+ mostly because it's unsure how the weak symbols support should look.
+ See Trac #11223
+ */
 static int ghciInsertSymbolTable(
    pathchar* obj_name,
    HashTable *table,
-   char* key,
-   void *data,
+   const SymbolName* key,
+   SymbolAddr* data,
    HsBool weak,
    ObjectCode *owner)
 {
@@ -1552,11 +554,24 @@ static int ghciInsertSymbolTable(
       insertStrHashTable(table, key, pinfo);
       return 1;
    }
-   else if ((!pinfo->weak || pinfo->value) && weak)
+   else if (weak && data && pinfo->weak && !pinfo->value)
    {
-     return 1; /* duplicate weak symbol, throw it away */
+       /* The existing symbol is weak with a zero value; replace it with the new symbol. */
+       pinfo->value = data;
+       pinfo->owner = owner;
+       return 1;
    }
-   else if (pinfo->weak) /* weak symbol is in the table */
+   else if (weak)
+   {
+       return 1; /* weak symbol, because the symbol is weak, data = 0 and we
+                 already know of another copy throw this one away.
+
+                 or both weak symbols have a nonzero value. Keep the existing one.
+
+                 This also preserves the semantics of linking against
+                 the first symbol we find. */
+   }
+   else if (pinfo->weak && !weak) /* weak symbol is in the table */
    {
       /* override the weak definition with the non-weak one */
       pinfo->value = data;
@@ -1564,24 +579,78 @@ static int ghciInsertSymbolTable(
       pinfo->weak = HS_BOOL_FALSE;
       return 1;
    }
+   else if (  pinfo->owner
+           && pinfo->owner->status != OBJECT_RESOLVED
+           && pinfo->owner->status != OBJECT_NEEDED)
+   {
+        /* If the other symbol hasn't been loaded or will be loaded and we want to
+           explicitly load the new one, we can just swap it out and load the one
+           that has been requested. If not, just keep the first one encountered.
+
+           Because the `symHash' table consists symbols we've also not loaded but
+           found during the initial scan this is safe to do. If however the existing
+           symbol has been loaded then it means we have a duplicate.
+
+           This is essentially emulating the behavior of a linker wherein it will always
+           link in object files that are .o file arguments, but only take object files
+           from archives as needed. */
+       if (owner && (owner->status == OBJECT_NEEDED || owner->status == OBJECT_RESOLVED)) {
+           pinfo->value = data;
+           pinfo->owner = owner;
+           pinfo->weak  = weak;
+       }
+
+       return 1;
+    }
+    else if (pinfo->owner == owner)
+    {
+       /* If it's the same symbol, ignore. This makes ghciInsertSymbolTable idempotent */
+       return 1;
+    }
+    else if (owner && owner->status == OBJECT_LOADED)
+    {
+        /* If the duplicate symbol is just in state OBJECT_LOADED it means we're in discovery of an
+           member. It's not a real duplicate yet. If the Oc Becomes OBJECT_NEEDED then ocTryLoad will
+           call this function again to trigger the duplicate error. */
+        return 1;
+    }
+
+   pathchar* archiveName = NULL;
    debugBelch(
       "GHC runtime linker: fatal error: I found a duplicate definition for symbol\n"
       "   %s\n"
       "whilst processing object file\n"
       "   %" PATH_FMT "\n"
+      "The symbol was previously defined in\n"
+      "   %" PATH_FMT "\n"
       "This could be caused by:\n"
       "   * Loading two different object files which export the same symbol\n"
       "   * Specifying the same object file twice on the GHCi command line\n"
       "   * An incorrect `package.conf' entry, causing some object to be\n"
       "     loaded twice.\n",
       (char*)key,
-      obj_name
+      obj_name,
+      pinfo->owner == NULL ? WSTR("(GHCi built-in symbols)") :
+      pinfo->owner->archiveMemberName ? archiveName = mkPath(pinfo->owner->archiveMemberName)
+      : pinfo->owner->fileName
    );
+
+   if (archiveName)
+   {
+       stgFree(archiveName);
+       archiveName = NULL;
+   }
    return 0;
 }
 
-static HsBool ghciLookupSymbolTable(HashTable *table,
-    const char *key, void **result)
+/* -----------------------------------------------------------------------------
+* Looks up symbols into hash tables.
+*
+* Returns: 0 on failure and result is not set,
+*          nonzero on success and result set to nonzero pointer
+*/
+static HsBool ghciLookupSymbolInfo(HashTable *table,
+    const SymbolName* key, RtsSymbolInfo **result)
 {
     RtsSymbolInfo *pinfo = lookupStrHashTable(table, key);
     if (!pinfo) {
@@ -1589,22 +658,14 @@ static HsBool ghciLookupSymbolTable(HashTable *table,
         return HS_BOOL_FALSE;
     }
     if (pinfo->weak)
-        IF_DEBUG(linker, debugBelch("lookup: promoting %s\n", key));
+        IF_DEBUG(linker, debugBelch("lookupSymbolInfo: promoting %s\n", key));
     /* Once it's looked up, it can no longer be overridden */
     pinfo->weak = HS_BOOL_FALSE;
 
-    *result = pinfo->value;
+    *result = pinfo;
     return HS_BOOL_TRUE;
 }
 
-static void ghciRemoveSymbolTable(HashTable *table, const char *key,
-    ObjectCode *owner)
-{
-    RtsSymbolInfo *pinfo = lookupStrHashTable(table, key);
-    if (!pinfo || owner != pinfo->owner) return;
-    removeStrHashTable(table, key, NULL);
-    stgFree(pinfo);
-}
 /* -----------------------------------------------------------------------------
  * initialize the object linker
  */
@@ -1684,10 +745,18 @@ initLinker_ (int retain_cafs)
         barf("ghciInsertSymbolTable failed");
     }
 
-    // Redurect newCAF to newDynCAF if retain_cafs is true.
+#if defined(OBJFORMAT_PEi386)
+    if (!ghciInsertSymbolTable(WSTR("(GHCi/Ld special symbols)"),
+                               symhash, "__image_base__", __image_base, HS_BOOL_TRUE, NULL)) {
+        barf("ghciInsertSymbolTable failed");
+    }
+#endif /* OBJFORMAT_PEi386 */
+
+
+    // Redirect newCAF to newRetainedCAF if retain_cafs is true.
     if (! ghciInsertSymbolTable(WSTR("(GHCi built-in symbols)"), symhash,
                                 MAYBE_LEADING_UNDERSCORE_STR("newCAF"),
-                                retain_cafs ? newDynCAF : newCAF,
+                                retain_cafs ? newRetainedCAF : newGCdCAF,
                                 HS_BOOL_FALSE, NULL)) {
         barf("ghciInsertSymbolTable failed");
     }
@@ -1731,6 +800,9 @@ initLinker_ (int retain_cafs)
     addDLLHandle(WSTR("*.exe"), GetModuleHandle(NULL));
 #endif
 
+    if (RTS_LINKER_USE_MMAP)
+        m32_allocator_init();
+
     IF_DEBUG(linker, debugBelch("initLinker: done\n"));
     return;
 }
@@ -1791,7 +863,7 @@ static OpenedDLL* opened_dlls = NULL;
 /* A record for storing indirectly linked functions from DLLs. */
 typedef
    struct _IndirectAddr {
-      void*                 addr;
+      SymbolAddr*           addr;
       struct _IndirectAddr* next;
    }
    IndirectAddr;
@@ -1999,7 +1071,7 @@ addDLL( pathchar *dll_name )
    OpenedDLL* o_dll;
    HINSTANCE  instance;
 
-   /* debugBelch("\naddDLL; dll_name = `%s'\n", dll_name); */
+   IF_DEBUG(linker, debugBelch("\naddDLL; dll_name = `%" PATH_FMT "'\n", dll_name));
 
    /* See if we've already got it, and ignore if so. */
    for (o_dll = opened_dlls; o_dll != NULL; o_dll = o_dll->next) {
@@ -2019,23 +1091,46 @@ addDLL( pathchar *dll_name )
 
    size_t bufsize = pathlen(dll_name) + 10;
    buf = stgMallocBytes(bufsize * sizeof(wchar_t), "addDLL");
-   snwprintf(buf, bufsize, L"%s.DLL", dll_name);
-   instance = LoadLibraryW(buf);
-   if (instance == NULL) {
-       if (GetLastError() != ERROR_MOD_NOT_FOUND) goto error;
-       // KAA: allow loading of drivers (like winspool.drv)
-       snwprintf(buf, bufsize, L"%s.DRV", dll_name);
-       instance = LoadLibraryW(buf);
-       if (instance == NULL) {
-           if (GetLastError() != ERROR_MOD_NOT_FOUND) goto error;
-           // #1883: allow loading of unix-style libfoo.dll DLLs
-           snwprintf(buf, bufsize, L"lib%s.DLL", dll_name);
-           instance = LoadLibraryW(buf);
-           if (instance == NULL) {
-               goto error;
+
+   /* These are ordered by probability of success and order we'd like them */
+   const wchar_t *formats[] = { L"%ls.DLL", L"%ls.DRV", L"lib%ls.DLL", L"%ls" };
+   const DWORD flags[]      = { LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS, 0 };
+
+   int cFormat;
+   int cFlag;
+   int flags_start = 1; // Assume we don't support the new API
+
+   /* Detect if newer API are available, if not, skip the first flags entry */
+   if (GetProcAddress((HMODULE)LoadLibraryW(L"Kernel32.DLL"), "AddDllDirectory")) {
+       flags_start = 0;
+   }
+
+   /* Iterate through the possible flags and formats */
+   for (cFlag = flags_start; cFlag < 2; cFlag++)
+   {
+       for (cFormat = 0; cFormat < 4; cFormat++)
+       {
+           snwprintf(buf, bufsize, formats[cFormat], dll_name);
+           instance = LoadLibraryExW(buf, NULL, flags[cFlag]);
+           if (instance == NULL)
+           {
+               if (GetLastError() != ERROR_MOD_NOT_FOUND)
+               {
+                   goto error;
+               }
+           }
+           else
+           {
+               break; // We're done. DLL has been loaded.
            }
        }
    }
+
+   // Check if we managed to load the DLL
+   if (instance == NULL) {
+       goto error;
+   }
+
    stgFree(buf);
 
    addDLLHandle(dll_name, instance);
@@ -2044,7 +1139,7 @@ addDLL( pathchar *dll_name )
 
 error:
    stgFree(buf);
-   sysErrorBelch("%" PATH_FMT, dll_name);
+   sysErrorBelch("addDLL: %" PATH_FMT " (Win32 error %lu)", dll_name, GetLastError());
 
    /* LoadLibrary failed; return a ptr to the error msg. */
    return "addDLL: could not load DLL";
@@ -2055,11 +1150,180 @@ error:
 }
 
 /* -----------------------------------------------------------------------------
+* Searches the system directories to determine if there is a system DLL that
+* satisfies the given name. This prevent GHCi from linking against a static
+* library if a DLL is available.
+*
+* Returns: NULL on failure or no DLL found, else the full path to the DLL
+*          that can be loaded.
+*/
+pathchar* findSystemLibrary(pathchar* dll_name)
+{
+    IF_DEBUG(linker, debugBelch("\nfindSystemLibrary: dll_name = `%" PATH_FMT "'\n", dll_name));
+
+#if defined(OBJFORMAT_PEi386)
+    const unsigned int init_buf_size = 1024;
+    unsigned int bufsize     = init_buf_size;
+    wchar_t* result = malloc(sizeof(wchar_t) * bufsize);
+    DWORD wResult   = SearchPathW(NULL, dll_name, NULL, bufsize, result, NULL);
+
+    if (wResult > bufsize) {
+        result  = realloc(result, sizeof(wchar_t) * wResult);
+        wResult = SearchPathW(NULL, dll_name, NULL, wResult, result, NULL);
+    }
+
+
+    if (!wResult) {
+        free(result);
+        return NULL;
+    }
+
+    return result;
+#else
+    (void)(dll_name); // Function not implemented for other platforms.
+    return NULL;
+#endif
+}
+
+/* -----------------------------------------------------------------------------
+* Emits a warning determining that the system is missing a required security
+* update that we need to get access to the proper APIs
+*/
+void warnMissingKBLibraryPaths( void )
+{
+    static HsBool missing_update_warn = HS_BOOL_FALSE;
+    if (!missing_update_warn) {
+        debugBelch("Warning: If linking fails, consider installing KB2533623.\n");
+        missing_update_warn = HS_BOOL_TRUE;
+    }
+}
+
+/* -----------------------------------------------------------------------------
+* appends a directory to the process DLL Load path so LoadLibrary can find it
+*
+* Returns: NULL on failure, or pointer to be passed to removeLibrarySearchPath to
+*          restore the search path to what it was before this call.
+*/
+HsPtr addLibrarySearchPath(pathchar* dll_path)
+{
+    IF_DEBUG(linker, debugBelch("\naddLibrarySearchPath: dll_path = `%" PATH_FMT "'\n", dll_path));
+
+#if defined(OBJFORMAT_PEi386)
+    HINSTANCE hDLL = LoadLibraryW(L"Kernel32.DLL");
+    LPAddDLLDirectory AddDllDirectory = (LPAddDLLDirectory)GetProcAddress((HMODULE)hDLL, "AddDllDirectory");
+
+    HsPtr result = NULL;
+
+    const unsigned int init_buf_size = 4096;
+    int bufsize = init_buf_size;
+
+    // Make sure the path is an absolute path
+    WCHAR* abs_path = malloc(sizeof(WCHAR) * init_buf_size);
+    DWORD wResult = GetFullPathNameW(dll_path, bufsize, abs_path, NULL);
+    if (!wResult){
+        sysErrorBelch("addLibrarySearchPath[GetFullPathNameW]: %" PATH_FMT " (Win32 error %lu)", dll_path, GetLastError());
+    }
+    else if (wResult > init_buf_size) {
+        abs_path = realloc(abs_path, sizeof(WCHAR) * wResult);
+        if (!GetFullPathNameW(dll_path, bufsize, abs_path, NULL)) {
+            sysErrorBelch("addLibrarySearchPath[GetFullPathNameW]: %" PATH_FMT " (Win32 error %lu)", dll_path, GetLastError());
+        }
+    }
+
+    if (AddDllDirectory) {
+        result = AddDllDirectory(abs_path);
+    }
+    else
+    {
+        warnMissingKBLibraryPaths();
+        WCHAR* str = malloc(sizeof(WCHAR) * init_buf_size);
+        wResult = GetEnvironmentVariableW(L"PATH", str, bufsize);
+
+        if (wResult > init_buf_size) {
+            str = realloc(str, sizeof(WCHAR) * wResult);
+            bufsize = wResult;
+            wResult = GetEnvironmentVariableW(L"PATH", str, bufsize);
+            if (!wResult) {
+                sysErrorBelch("addLibrarySearchPath[GetEnvironmentVariableW]: %" PATH_FMT " (Win32 error %lu)", dll_path, GetLastError());
+            }
+        }
+
+        bufsize = wResult + 2 + pathlen(abs_path);
+        wchar_t* newPath = malloc(sizeof(wchar_t) * bufsize);
+
+        wcscpy(newPath, abs_path);
+        wcscat(newPath, L";");
+        wcscat(newPath, str);
+        if (!SetEnvironmentVariableW(L"PATH", (LPCWSTR)newPath)) {
+            sysErrorBelch("addLibrarySearchPath[SetEnvironmentVariableW]: %" PATH_FMT " (Win32 error %lu)", abs_path, GetLastError());
+        }
+
+        free(newPath);
+        free(abs_path);
+
+        return str;
+    }
+
+    if (!result) {
+        sysErrorBelch("addLibrarySearchPath: %" PATH_FMT " (Win32 error %lu)", abs_path, GetLastError());
+        free(abs_path);
+        return NULL;
+    }
+
+    free(abs_path);
+    return result;
+#else
+    (void)(dll_path); // Function not implemented for other platforms.
+    return NULL;
+#endif
+}
+
+/* -----------------------------------------------------------------------------
+* removes a directory from the process DLL Load path
+*
+* Returns: HS_BOOL_TRUE on success, otherwise HS_BOOL_FALSE
+*/
+HsBool removeLibrarySearchPath(HsPtr dll_path_index)
+{
+    IF_DEBUG(linker, debugBelch("\nremoveLibrarySearchPath: ptr = `%p'\n", dll_path_index));
+
+#if defined(OBJFORMAT_PEi386)
+    HsBool result = 0;
+
+    if (dll_path_index != NULL) {
+        HINSTANCE hDLL = LoadLibraryW(L"Kernel32.DLL");
+        LPRemoveDLLDirectory RemoveDllDirectory = (LPRemoveDLLDirectory)GetProcAddress((HMODULE)hDLL, "RemoveDllDirectory");
+
+        if (RemoveDllDirectory) {
+            result = RemoveDllDirectory(dll_path_index);
+            // dll_path_index is now invalid, do not use it after this point.
+        }
+        else
+        {
+            warnMissingKBLibraryPaths();
+            result = SetEnvironmentVariableW(L"PATH", (LPCWSTR)dll_path_index);
+            free(dll_path_index);
+        }
+
+        if (!result) {
+            sysErrorBelch("removeLibrarySearchPath: (Win32 error %lu)", GetLastError());
+            return HS_BOOL_FALSE;
+        }
+    }
+
+    return result == 0 ? HS_BOOL_TRUE : HS_BOOL_FALSE;
+#else
+    (void)(dll_path_index); // Function not implemented for other platforms.
+    return HS_BOOL_FALSE;
+#endif
+}
+
+/* -----------------------------------------------------------------------------
  * insert a symbol in the hash table
  *
  * Returns: 0 on failure, nozero on success
  */
-HsInt insertSymbol(pathchar* obj_name, char* key, void* data)
+HsInt insertSymbol(pathchar* obj_name, SymbolName* key, SymbolAddr* data)
 {
     return ghciInsertSymbolTable(obj_name, symhash, key, data, HS_BOOL_FALSE, NULL);
 }
@@ -2067,23 +1331,21 @@ HsInt insertSymbol(pathchar* obj_name, char* key, void* data)
 /* -----------------------------------------------------------------------------
  * lookup a symbol in the hash table
  */
-static void* lookupSymbol_ (char *lbl)
+static SymbolAddr* lookupSymbol_ (SymbolName* lbl)
 {
-    void *val;
     IF_DEBUG(linker, debugBelch("lookupSymbol: looking up %s\n", lbl));
 
     ASSERT(symhash != NULL);
+    RtsSymbolInfo *pinfo;
 
-    if (!ghciLookupSymbolTable(symhash, lbl, &val)) {
+    if (!ghciLookupSymbolInfo(symhash, lbl, &pinfo)) {
         IF_DEBUG(linker, debugBelch("lookupSymbol: symbol not found\n"));
+
 #       if defined(OBJFORMAT_ELF)
         return internal_dlsym(lbl);
 #       elif defined(OBJFORMAT_MACHO)
-#       if HAVE_DLFCN_H
-        /* On OS X 10.3 and later, we use dlsym instead of the old legacy
-           interface.
 
-           HACK: On OS X, all symbols are prefixed with an underscore.
+        /* HACK: On OS X, all symbols are prefixed with an underscore.
                  However, dlsym wants us to omit the leading underscore from the
                  symbol name -- the dlsym routine puts it back on before searching
                  for the symbol. For now, we simply strip it off here (and ONLY
@@ -2092,25 +1354,13 @@ static void* lookupSymbol_ (char *lbl)
         IF_DEBUG(linker, debugBelch("lookupSymbol: looking up %s with dlsym\n", lbl));
         ASSERT(lbl[0] == '_');
         return internal_dlsym(lbl + 1);
-#       else
-        if (NSIsSymbolNameDefined(lbl)) {
-            NSSymbol symbol = NSLookupAndBindSymbol(lbl);
-            return NSAddressOfSymbol(symbol);
-        } else {
-            return NULL;
-        }
-#       endif /* HAVE_DLFCN_H */
 #       elif defined(OBJFORMAT_PEi386)
-        void* sym;
-
-        sym = lookupSymbolInDLLs((unsigned char*)lbl);
-        if (sym != NULL) {
-            return sym;
-        };
+        SymbolAddr* sym;
 
-        // Also try looking up the symbol without the @N suffix.  Some
-        // DLLs have the suffixes on their symbols, some don't.
-        zapTrailingAtSign ( (unsigned char*)lbl );
+/* See Note [mingw-w64 name decoration scheme] */
+#ifndef x86_64_HOST_ARCH
+         zapTrailingAtSign ( (unsigned char*)lbl );
+#endif
         sym = lookupSymbolInDLLs((unsigned char*)lbl);
         return sym; // might be NULL if not found
 
@@ -2119,15 +1369,33 @@ static void* lookupSymbol_ (char *lbl)
         return NULL;
 #       endif
     } else {
+        SymbolAddr* val = pinfo->value;
         IF_DEBUG(linker, debugBelch("lookupSymbol: value of %s is %p\n", lbl, val));
+
+        int r;
+        ObjectCode* oc = pinfo->owner;
+
+        /* Symbol can be found during linking, but hasn't been relocated. Do so now.
+           See Note [runtime-linker-phases] */
+        if (oc && oc->status == OBJECT_LOADED) {
+            oc->status = OBJECT_NEEDED;
+            IF_DEBUG(linker, debugBelch("lookupSymbol: on-demand loading symbol '%s'\n", lbl));
+            r = ocTryLoad(oc);
+
+            if (!r) {
+                errorBelch("Could not on-demand load symbol '%s'\n", lbl);
+                return NULL;
+            }
+        }
+
         return val;
     }
 }
 
-void* lookupSymbol( char *lbl )
+SymbolAddr* lookupSymbol( SymbolName* lbl )
 {
     ACQUIRE_LOCK(&linker_mutex);
-    char *r = lookupSymbol_(lbl);
+    SymbolAddr* r = lookupSymbol_(lbl);
     RELEASE_LOCK(&linker_mutex);
     return r;
 }
@@ -2168,13 +1436,13 @@ StgStablePtr foreignExportStablePtr (StgPtr p)
  * within DELTA bytes of the specified address, and show their names.
  */
 #ifdef DEBUG
-void ghci_enquire ( char* addr );
+void ghci_enquire ( SymbolAddr* addr );
 
-void ghci_enquire ( char* addr )
+void ghci_enquire(SymbolAddr* addr)
 {
    int   i;
-   char* sym;
-   char* a;
+   SymbolName* sym;
+   RtsSymbolInfo* a;
    const int DELTA = 64;
    ObjectCode* oc;
 
@@ -2184,36 +1452,35 @@ void ghci_enquire ( char* addr )
          if (sym == NULL) continue;
          a = NULL;
          if (a == NULL) {
-            ghciLookupSymbolTable(symhash, sym, (void **)&a);
+             ghciLookupSymbolInfo(symhash, sym, &a);
          }
          if (a == NULL) {
              // debugBelch("ghci_enquire: can't find %s\n", sym);
          }
-         else if (addr-DELTA <= a && a <= addr+DELTA) {
-            debugBelch("%p + %3d  ==  `%s'\n", addr, (int)(a - addr), sym);
+         else if (   a->value
+                  && (char*)addr-DELTA <= (char*)a->value
+                  && (char*)a->value <= (char*)addr+DELTA) {
+             debugBelch("%p + %3d  ==  `%s'\n", addr, (int)((char*)a->value - (char*)addr), sym);
          }
       }
    }
 }
 #endif
 
-#ifdef USE_MMAP
-#define ROUND_UP(x,size) ((x + size - 1) & ~(size - 1))
-
+#if RTS_LINKER_USE_MMAP
 //
 // Returns NULL on failure.
 //
-static void * mmapForLinker (size_t bytes, nat flags, int fd)
+void *
+mmapForLinker (size_t bytes, uint32_t flags, int fd, int offset)
 {
    void *map_addr = NULL;
    void *result;
-   int pagesize;
-   StgWord size;
-   static nat fixed = 0;
+   size_t size;
+   static uint32_t 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:
@@ -2232,7 +1499,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);
@@ -2294,7 +1561,7 @@ mmap_again:
 
    return result;
 }
-#endif // USE_MMAP
+#endif
 
 /*
  * Remove symbols from the symbol table, and free oc->symbols.
@@ -2334,6 +1601,36 @@ static void freeOcStablePtrs (ObjectCode *oc)
     oc->stable_ptrs = NULL;
 }
 
+static void
+freePreloadObjectFile (ObjectCode *oc)
+{
+#if 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
+
+    if (RTS_LINKER_USE_MMAP && oc->imageMapped) {
+        munmap(oc->image, oc->fileSize);
+    }
+    else {
+        stgFree(oc->image);
+    }
+
+#endif
+
+    oc->image = NULL;
+    oc->fileSize = 0;
+}
 
 /*
  * freeObjectCode() releases all the pieces of an ObjectCode.  It is called by
@@ -2342,83 +1639,80 @@ static void freeOcStablePtrs (ObjectCode *oc)
  */
 void freeObjectCode (ObjectCode *oc)
 {
+    freePreloadObjectFile(oc);
+
     if (oc->symbols != NULL) {
         stgFree(oc->symbols);
         oc->symbols = NULL;
     }
 
-    {
-        Section *s, *nexts;
+    if (oc->extraInfos != NULL) {
+        freeHashTable(oc->extraInfos, NULL);
+        oc->extraInfos = NULL;
+    }
 
-        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){
+#if RTS_LINKER_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);
 
-#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));
+    /* 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))
+    if (RTS_LINKER_USE_MMAP) {
+        if (!USE_CONTIGUOUS_MMAP && oc->symbol_extras != NULL) {
+            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;
+    else {
+        stgFree(oc->symbol_extras);
     }
-
-#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)
-    stgFree(oc->symbol_extras);
-#endif
-#endif
-
 #endif
 
     stgFree(oc->fileName);
     stgFree(oc->archiveMemberName);
+
     stgFree(oc);
 }
 
+/* -----------------------------------------------------------------------------
+* Sets the initial status of a fresh ObjectCode
+*/
+static void setOcInitialStatus(ObjectCode* oc) {
+    if (oc->archiveMemberName == NULL) {
+        oc->status = OBJECT_NEEDED;
+    } else {
+        oc->status = OBJECT_LOADED;
+    }
+}
 
 static ObjectCode*
 mkOc( pathchar *path, char *image, int imageSize,
-      char *archiveMemberName
-#ifndef USE_MMAP
-#ifdef darwin_HOST_OS
-    , int misalignment
-#endif
-#endif
-    ) {
+      rtsBool mapped, char *archiveMemberName, int misalignment ) {
    ObjectCode* oc;
 
    IF_DEBUG(linker, debugBelch("mkOc: start\n"));
@@ -2441,25 +1735,25 @@ mkOc( pathchar *path, char *image, int imageSize,
    if (archiveMemberName) {
        oc->archiveMemberName = stgMallocBytes( strlen(archiveMemberName)+1, "loadObj" );
        strcpy(oc->archiveMemberName, archiveMemberName);
-   }
-   else {
+   } else {
        oc->archiveMemberName = NULL;
    }
 
+   setOcInitialStatus( oc );
+
    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
-   oc->misalignment = misalignment;
-#endif
-#endif
+   oc->misalignment      = misalignment;
+   oc->extraInfos        = NULL;
 
    /* chain it onto the list of objects */
    oc->next              = NULL;
@@ -2495,7 +1789,7 @@ static HsInt loadArchive_ (pathchar *path)
     size_t thisFileNameSize;
     char *fileName;
     size_t fileNameSize;
-    int isObject, isGnuIndex, isThin;
+    int isObject, isGnuIndex, isThin, isImportLib;
     char tmp[20];
     char *gnuFileIndex;
     int gnuFileIndexSize;
@@ -2517,10 +1811,8 @@ static HsInt loadArchive_ (pathchar *path)
 #else
 #error Unknown Darwin architecture
 #endif
-#if !defined(USE_MMAP)
-    int misalignment;
-#endif
 #endif
+    int misalignment = 0;
 
     /* TODO: don't call barf() on error, instead return an error code, freeing
      * all resources correctly.  This function is pretty complex, so it needs
@@ -2544,10 +1836,11 @@ static HsInt loadArchive_ (pathchar *path)
     fileName = stgMallocBytes(fileNameSize, "loadArchive(fileName)");
 
     isThin = 0;
+    isImportLib = 0;
 
     f = pathopen(path, WSTR("rb"));
     if (!f)
-        barf("loadObj: can't read `%s'", path);
+        barf("loadObj: can't read `%" PATH_FMT "'", path);
 
     /* Check if this is an archive by looking for the magic "!<arch>\n"
      * string.  Usually, if this fails, we barf and quit.  On Darwin however,
@@ -2570,14 +1863,26 @@ static HsInt loadArchive_ (pathchar *path)
 
     n = fread ( tmp, 1, 8, f );
     if (n != 8)
-        barf("loadArchive: Failed reading header from `%s'", path);
+        barf("loadArchive: Failed reading header from `%" PATH_FMT "'", path);
     if (strncmp(tmp, "!<arch>\n", 8) == 0) {}
-#if !defined(mingw32_HOST_OS)
-    /* See Note [thin archives on Windows] */
+    /* Check if this is a thin archive by looking for the magic string "!<thin>\n"
+     *
+     * ar thin libraries have the exact same format as normal archives except they
+     * have a different magic string and they don't copy the object files into the
+     * archive.
+     *
+     * Instead each header entry points to the location of the object file on disk.
+     * This is useful when a library is only created to satisfy a compile time dependency
+     * instead of to be distributed. This saves the time required for copying.
+     *
+     * Thin archives are always flattened. They always only contain simple headers
+     * pointing to the object file and so we need not allocate more memory than needed
+     * to find the object file.
+     *
+     */
     else if (strncmp(tmp, "!<thin>\n", 8) == 0) {
         isThin = 1;
     }
-#endif
 #if defined(darwin_HOST_OS)
     /* Not a standard archive, look for a fat archive magic number: */
     else if (ntohl(*(uint32_t *)tmp) == FAT_MAGIC) {
@@ -2620,13 +1925,14 @@ static HsInt loadArchive_ (pathchar *path)
     }
 #else
     else {
-        barf("loadArchive: Not an archive: `%s'", path);
+        barf("loadArchive: Not an archive: `%" PATH_FMT "'", path);
     }
 #endif
 
     IF_DEBUG(linker, debugBelch("loadArchive: loading archive contents\n"));
 
-    while(1) {
+    while (1) {
+        IF_DEBUG(linker, debugBelch("loadArchive: reading at %ld\n", ftell(f)));
         n = fread ( fileName, 1, 16, f );
         if (n != 16) {
             if (feof(f)) {
@@ -2634,7 +1940,7 @@ static HsInt loadArchive_ (pathchar *path)
                 break;
             }
             else {
-                barf("loadArchive: Failed reading file name from `%s'", path);
+                barf("loadArchive: Failed reading file name from `%" PATH_FMT "'", path);
             }
         }
 
@@ -2647,19 +1953,19 @@ static HsInt loadArchive_ (pathchar *path)
 
         n = fread ( tmp, 1, 12, f );
         if (n != 12)
-            barf("loadArchive: Failed reading mod time from `%s'", path);
+            barf("loadArchive: Failed reading mod time from `%" PATH_FMT "'", path);
         n = fread ( tmp, 1, 6, f );
         if (n != 6)
-            barf("loadArchive: Failed reading owner from `%s'", path);
+            barf("loadArchive: Failed reading owner from `%" PATH_FMT "'", path);
         n = fread ( tmp, 1, 6, f );
         if (n != 6)
-            barf("loadArchive: Failed reading group from `%s'", path);
+            barf("loadArchive: Failed reading group from `%" PATH_FMT "'", path);
         n = fread ( tmp, 1, 8, f );
         if (n != 8)
-            barf("loadArchive: Failed reading mode from `%s'", path);
+            barf("loadArchive: Failed reading mode from `%" PATH_FMT "'", path);
         n = fread ( tmp, 1, 10, f );
         if (n != 10)
-            barf("loadArchive: Failed reading size from `%s'", path);
+            barf("loadArchive: Failed reading size from `%" PATH_FMT "'", path);
         tmp[10] = '\0';
         for (n = 0; isdigit(tmp[n]); n++);
         tmp[n] = '\0';
@@ -2668,9 +1974,9 @@ static HsInt loadArchive_ (pathchar *path)
         IF_DEBUG(linker, debugBelch("loadArchive: size of this archive member is %d\n", memberSize));
         n = fread ( tmp, 1, 2, f );
         if (n != 2)
-            barf("loadArchive: Failed reading magic from `%s'", path);
+            barf("loadArchive: Failed reading magic from `%" PATH_FMT "'", path);
         if (strncmp(tmp, "\x60\x0A", 2) != 0)
-            barf("loadArchive: Failed reading magic from `%s' at %ld. Got %c%c",
+            barf("loadArchive: Failed reading magic from `%" PATH_FMT "' at %ld. Got %c%c",
                  path, ftell(f), tmp[0], tmp[1]);
 
         isGnuIndex = 0;
@@ -2690,7 +1996,7 @@ static HsInt loadArchive_ (pathchar *path)
                 }
                 n = fread ( fileName, 1, thisFileNameSize, f );
                 if (n != (int)thisFileNameSize) {
-                    barf("loadArchive: Failed reading filename from `%s'",
+                    barf("loadArchive: Failed reading filename from `%" PATH_FMT "'",
                          path);
                 }
                 fileName[thisFileNameSize] = 0;
@@ -2780,9 +2086,32 @@ static HsInt loadArchive_ (pathchar *path)
         IF_DEBUG(linker,
                  debugBelch("loadArchive: Found member file `%s'\n", fileName));
 
-        isObject = thisFileNameSize >= 2
-                && fileName[thisFileNameSize - 2] == '.'
-                && fileName[thisFileNameSize - 1] == 'o';
+        isObject = (thisFileNameSize >= 2 && strncmp(fileName + thisFileNameSize - 2, ".o"  , 2) == 0)
+                || (thisFileNameSize >= 4 && strncmp(fileName + thisFileNameSize - 4, ".p_o", 4) == 0);
+
+#if defined(OBJFORMAT_PEi386)
+        /*
+        * Note [MSVC import files (ext .lib)]
+        * MSVC compilers store the object files in
+        * the import libraries with extension .dll
+        * so on Windows we should look for those too.
+        * The PE COFF format doesn't specify any specific file name
+        * for sections. So on windows, just try to load it all.
+        *
+        * Linker members (e.g. filename / are skipped since they are not needed)
+        */
+        isImportLib = thisFileNameSize >= 4 && strncmp(fileName + thisFileNameSize - 4, ".dll", 4) == 0;
+
+        /*
+         * Note [GCC import files (ext .dll.a)]
+         * GCC stores import information in the same binary format
+         * as the object file normally has. The only difference is that
+         * all the information are put in .idata sections. The only real
+         * way to tell if we're dealing with an import lib is by looking
+         * at the file extension.
+         */
+        isImportLib = isImportLib || endsWithPath(path, WSTR(".dll.a"));
+#endif // windows
 
         IF_DEBUG(linker, debugBelch("loadArchive: \tthisFileNameSize = %d\n", (int)thisFileNameSize));
         IF_DEBUG(linker, debugBelch("loadArchive: \tisObject = %d\n", isObject));
@@ -2792,61 +2121,46 @@ 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)
-        // TODO: We would like to use allocateExec here, but allocateExec
-        //       cannot currently allocate blocks large enough.
-            image = allocateImageAndTrampolines(path, fileName,
-#if defined(x86_64_HOST_ARCH)
-               f,
-#endif
-               memberSize);
+#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, f, memberSize,
+                                                isThin);
 #elif defined(darwin_HOST_OS)
-            /* See loadObj() */
-            misalignment = machoGetMisalignment(f);
-            image = stgMallocBytes(memberSize + misalignment, "loadArchive(image)");
-            image += misalignment;
-#else
+            if (RTS_LINKER_USE_MMAP)
+                image = mmapForLinker(memberSize, MAP_ANONYMOUS, -1, 0);
+            else {
+                /* See loadObj() */
+                misalignment = machoGetMisalignment(f);
+                image = stgMallocBytes(memberSize + misalignment,
+                                        "loadArchive(image)");
+                image += misalignment;
+            }
+
+#else // not windows or darwin
             image = stgMallocBytes(memberSize, "loadArchive(image)");
 #endif
-
-#if !defined(mingw32_HOST_OS)
-            /*
-             * Note [thin archives on Windows]
-             * This doesn't compile on Windows because it assumes
-             * char* pathnames, and we use wchar_t* on Windows.  It's
-             * not trivial to fix, so I'm leaving it disabled on
-             * Windows for now --SDM
-             */
             if (isThin) {
                 FILE *member;
-                char *pathCopy, *dirName, *memberPath;
+                pathchar *pathCopy, *dirName, *memberPath, *objFileName;
 
                 /* Allocate and setup the dirname of the archive.  We'll need
-                   this to locate the thin member */
-                pathCopy = stgMallocBytes(strlen(path) + 1, "loadArchive(file)");
-                strcpy(pathCopy, path);
-                dirName = dirname(pathCopy);
+                    this to locate the thin member */
+                pathCopy = pathdup(path); // Convert the char* to a pathchar*
+                dirName  = pathdir(pathCopy);
 
                 /* Append the relative member name to the dirname.  This should be
                    be the full path to the actual thin member. */
-                memberPath = stgMallocBytes(
-                    strlen(path) + 1 + strlen(fileName) + 1, "loadArchive(file)");
-                strcpy(memberPath, dirName);
-                memberPath[strlen(dirName)] = '/';
-                strcpy(memberPath + strlen(dirName) + 1, fileName);
+                int memberLen = pathlen(dirName) + 1 + strlen(fileName) + 1;
+                memberPath    = stgMallocBytes(pathsize * memberLen, "loadArchive(file)");
+                objFileName   = mkPath(fileName);
+                pathprintf(memberPath, memberLen, WSTR("%" PATH_FMT "%" PATH_FMT), dirName, objFileName);
+                stgFree(objFileName);
+                stgFree(dirName);
 
                 member = pathopen(memberPath, WSTR("rb"));
                 if (!member)
-                    barf("loadObj: can't read `%s'", path);
+                    barf("loadObj: can't read thin archive `%" PATH_FMT "'", memberPath);
 
                 n = fread ( image, 1, memberSize, member );
                 if (n != memberSize) {
@@ -2858,11 +2172,10 @@ static HsInt loadArchive_ (pathchar *path)
                 stgFree(pathCopy);
             }
             else
-#endif
             {
                 n = fread ( image, 1, memberSize, f );
                 if (n != memberSize) {
-                    barf("loadArchive: error whilst reading `%s'", path);
+                    barf("loadArchive: error whilst reading `%" PATH_FMT "'", path);
                 }
             }
 
@@ -2871,13 +2184,8 @@ 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
-                     , misalignment
-#endif
-#endif
-                     );
+            oc = mkOc(path, image, memberSize, rtsFalse, archiveMemberName
+                     , misalignment);
 
             stgFree(archiveMemberName);
 
@@ -2886,8 +2194,20 @@ static HsInt loadArchive_ (pathchar *path)
                 fclose(f);
                 return 0;
             } else {
-                oc->next = objects;
-                objects = oc;
+#if defined(OBJFORMAT_PEi386)
+                if (isImportLib)
+                {
+                    findAndLoadImportLibrary(oc);
+                    stgFree(oc);
+                    oc = NULL;
+                    break;
+                } else {
+#endif
+                    oc->next = objects;
+                    objects = oc;
+#if defined(OBJFORMAT_PEi386)
+                }
+#endif
             }
         }
         else if (isGnuIndex) {
@@ -2895,24 +2215,38 @@ static HsInt loadArchive_ (pathchar *path)
                 barf("loadArchive: GNU-variant index found, but already have an index, while reading filename from `%s'", path);
             }
             IF_DEBUG(linker, debugBelch("loadArchive: Found GNU-variant file index\n"));
-#ifdef USE_MMAP
-            gnuFileIndex = mmapForLinker(memberSize + 1, MAP_ANONYMOUS, -1);
+#if RTS_LINKER_USE_MMAP
+            gnuFileIndex = mmapForLinker(memberSize + 1, MAP_ANONYMOUS, -1, 0);
 #else
             gnuFileIndex = stgMallocBytes(memberSize + 1, "loadArchive(image)");
 #endif
             n = fread ( gnuFileIndex, 1, memberSize, f );
             if (n != memberSize) {
-                barf("loadArchive: error whilst reading `%s'", path);
+                barf("loadArchive: error whilst reading `%" PATH_FMT "'", path);
             }
             gnuFileIndex[memberSize] = '/';
             gnuFileIndexSize = memberSize;
         }
+        else if (isImportLib) {
+#if defined(OBJFORMAT_PEi386)
+            if (checkAndLoadImportLibrary(path, fileName, f)) {
+                IF_DEBUG(linker, debugBelch("loadArchive: Member is an import file section... Corresponding DLL has been loaded...\n"));
+            }
+            else {
+                IF_DEBUG(linker, debugBelch("loadArchive: Member is not a valid import file section... Skipping...\n"));
+                n = fseek(f, memberSize, SEEK_CUR);
+                if (n != 0)
+                    barf("loadArchive: error whilst seeking by %d in `%" PATH_FMT "'",
+                    memberSize, path);
+            }
+#endif
+        }
         else {
             IF_DEBUG(linker, debugBelch("loadArchive: '%s' does not appear to be an object file\n", fileName));
             if (!isThin || thisFileNameSize == 0) {
                 n = fseek(f, memberSize, SEEK_CUR);
                 if (n != 0)
-                    barf("loadArchive: error whilst seeking by %d in `%s'",
+                    barf("loadArchive: error whilst seeking by %d in `%" PATH_FMT "'",
                          memberSize, path);
             }
         }
@@ -2927,7 +2261,7 @@ static HsInt loadArchive_ (pathchar *path)
                     break;
                 }
                 else {
-                    barf("loadArchive: Failed reading padding from `%s'", path);
+                    barf("loadArchive: Failed reading padding from `%" PATH_FMT "'", path);
                 }
             }
             IF_DEBUG(linker, debugBelch("loadArchive: successfully read one pad byte\n"));
@@ -2939,13 +2273,16 @@ static HsInt loadArchive_ (pathchar *path)
 
     stgFree(fileName);
     if (gnuFileIndex != NULL) {
-#ifdef USE_MMAP
+#if RTS_LINKER_USE_MMAP
         munmap(gnuFileIndex, gnuFileIndexSize + 1);
 #else
         stgFree(gnuFileIndex);
 #endif
     }
 
+    if (RTS_LINKER_USE_MMAP)
+        m32_allocator_flush();
+
     IF_DEBUG(linker, debugBelch("loadArchive: done\n"));
     return 1;
 }
@@ -2958,90 +2295,74 @@ 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)
-   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 */
-   }
+   void *image;
+   ObjectCode *oc;
+   int misalignment = 0;
 
    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. */
+#if RTS_LINKER_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 */
+#else /* !RTS_LINKER_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;
+       errorBelch("loadObj: can't preload `%" PATH_FMT "'", path);
+       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",
-#if defined(x86_64_HOST_ARCH)
-       f,
-#endif
-       fileSize);
+    image = allocateImageAndTrampolines(path, "itself", f, fileSize,
+                                        HS_BOOL_FALSE);
     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
@@ -3054,29 +2375,52 @@ 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
-            , misalignment
-#endif
-#endif
-            );
+#endif /* RTS_LINKER_USE_MMAP */
+
+   oc = mkOc(path, image, fileSize, rtsTrue, NULL, misalignment);
+
+   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
@@ -3099,8 +2443,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"));
@@ -3120,20 +2464,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 */
@@ -3151,57 +2497,103 @@ loadOc( ObjectCode* oc ) {
        return r;
    }
 
-   /* loaded, but not resolved yet */
-   oc->status = OBJECT_LOADED;
+   /* loaded, but not resolved yet, ensure the OC is in a consistent state */
+   setOcInitialStatus( oc );
    IF_DEBUG(linker, debugBelch("loadOc: done.\n"));
 
    return 1;
 }
 
 /* -----------------------------------------------------------------------------
- * resolve all the currently unlinked objects in memory
- *
- * Returns: 1 if ok, 0 on error.
- */
-static HsInt resolveObjs_ (void)
-{
-    ObjectCode *oc;
+* try to load and initialize an ObjectCode into memory
+*
+* Returns: 1 if ok, 0 on error.
+*/
+int ocTryLoad (ObjectCode* oc) {
     int r;
 
-    IF_DEBUG(linker, debugBelch("resolveObjs: start\n"));
+    if (oc->status != OBJECT_NEEDED) {
+        return 1;
+    }
+
+    /*  Check for duplicate symbols by looking into `symhash`.
+        Duplicate symbols are any symbols which exist
+        in different ObjectCodes that have both been loaded, or
+        are to be loaded by this call.
+
+        This call is intended to have no side-effects when a non-duplicate
+        symbol is re-inserted.
+
+        We set the Address to NULL since that is not used to distinguish
+        symbols. Duplicate symbols are distinguished by name and oc.
+    */
+    int x;
+    SymbolName* symbol;
+    for (x = 0; x < oc->n_symbols; x++) {
+        symbol = oc->symbols[x];
+        if (   symbol
+            && !ghciInsertSymbolTable(oc->fileName, symhash, symbol, NULL, isSymbolWeak(oc, symbol), oc)) {
+            return 0;
+        }
+    }
 
-    for (oc = objects; oc; oc = oc->next) {
-        if (oc->status != OBJECT_RESOLVED) {
 #           if defined(OBJFORMAT_ELF)
-            r = ocResolve_ELF ( oc );
+        r = ocResolve_ELF ( oc );
 #           elif defined(OBJFORMAT_PEi386)
-            r = ocResolve_PEi386 ( oc );
+        r = ocResolve_PEi386 ( oc );
 #           elif defined(OBJFORMAT_MACHO)
-            r = ocResolve_MachO ( oc );
+        r = ocResolve_MachO ( oc );
 #           else
-            barf("resolveObjs: not implemented on this platform");
+    barf("ocTryLoad: not implemented on this platform");
 #           endif
-            if (!r) { return r; }
+        if (!r) { return r; }
 
-            // run init/init_array/ctors/mod_init_func
+        // run init/init_array/ctors/mod_init_func
 
-            loading_obj = oc; // tells foreignExportStablePtr what to do
+        loading_obj = oc; // tells foreignExportStablePtr what to do
 #if defined(OBJFORMAT_ELF)
-            r = ocRunInit_ELF ( oc );
+        r = ocRunInit_ELF ( oc );
 #elif defined(OBJFORMAT_PEi386)
-            r = ocRunInit_PEi386 ( oc );
+        r = ocRunInit_PEi386 ( oc );
 #elif defined(OBJFORMAT_MACHO)
-            r = ocRunInit_MachO ( oc );
+        r = ocRunInit_MachO ( oc );
 #else
-            barf("resolveObjs: initializers not implemented on this platform");
+    barf("ocTryLoad: initializers not implemented on this platform");
 #endif
-            loading_obj = NULL;
+        loading_obj = NULL;
+
+        if (!r) { return r; }
+
+    oc->status = OBJECT_RESOLVED;
+
+    return 1;
+}
+
+/* -----------------------------------------------------------------------------
+ * resolve all the currently unlinked objects in memory
+ *
+ * Returns: 1 if ok, 0 on error.
+ */
+static HsInt resolveObjs_ (void)
+{
+    ObjectCode *oc;
+    int r;
 
-            if (!r) { return r; }
+    IF_DEBUG(linker, debugBelch("resolveObjs: start\n"));
 
-            oc->status = OBJECT_RESOLVED;
+    for (oc = objects; oc; oc = oc->next) {
+        r = ocTryLoad(oc);
+        if (!r)
+        {
+            return r;
         }
     }
+
+#ifdef PROFILING
+    // collect any new cost centres & CCSs that were defined during runInit
+    initProfiling2();
+#endif
+
     IF_DEBUG(linker, debugBelch("resolveObjs: done\n"));
     return 1;
 }
@@ -3336,18 +2728,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 ));
 }
 
 
@@ -3359,7 +2756,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)
 
 /*
@@ -3383,77 +2780,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;
-#ifndef USE_MMAP
-  int misalignment = 0;
-#ifdef darwin_HOST_OS
-  misalignment = oc->misalignment;
-#endif
-#endif
-
-  if( count > 0 )
-  {
-    // 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 );
+  size_t n;
+
+  if (RTS_LINKER_USE_MMAP && 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 if( count > 0 ) {
+    if (RTS_LINKER_USE_MMAP) {
+        n = roundUpToPage(oc->fileSize);
 
-    /* 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;
-        }
+        oc->symbol_extras = m32_alloc(sizeof(SymbolExtra) * count, 8);
+        if (oc->symbol_extras == NULL) return 0;
     }
-    else
-    {
-        oc->symbol_extras = (SymbolExtra *) (oc->image + aligned);
-    }
-#else
-    oc->image -= misalignment;
-    oc->image = stgReallocBytes( oc->image,
+    else {
+        // round up to the nearest 4
+        int aligned = (oc->fileSize + 3) & ~3;
+        int misalignment = oc->misalignment;
+
+        oc->image -= misalignment;
+        oc->image = stgReallocBytes( oc->image,
                                  misalignment +
                                  aligned + sizeof (SymbolExtra) * count,
                                  "ocAllocateSymbolExtras" );
-    oc->image += misalignment;
+        oc->image += misalignment;
 
-    oc->symbol_extras = (SymbolExtra *) (oc->image + aligned);
-#endif /* USE_MMAP */
+        oc->symbol_extras = (SymbolExtra *) (oc->image + aligned);
+    }
+  }
 
-    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;
@@ -3462,17 +2837,27 @@ 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)
 
 static void
 ocFlushInstructionCache( ObjectCode *oc )
 {
+    int i;
     // Object code
-    __clear_cache(oc->image, oc->image + oc->fileSize);
+    for (i=0; i < oc->n_sections; i++) {
+        Section *s = &oc->sections[i];
+        // This is a bit too broad but we don't have any way to determine what
+        // is certainly code
+        if (s->kind == SECTIONKIND_CODE_OR_RODATA)
+            __clear_cache(s->start, (void*) ((uintptr_t) s->start + s->size));
+    }
+
     // Jump islands
-    __clear_cache(oc->symbol_extras, &oc->symbol_extras[oc->n_symbol_extras]);
+    // Note the (+1) to ensure that the last symbol extra is covered by the
+    // flush.
+    __clear_cache(oc->symbol_extras, &oc->symbol_extras[oc->n_symbol_extras+1]);
 }
 
 #endif
@@ -3622,11 +3007,7 @@ static void
 ocFlushInstructionCache( ObjectCode *oc )
 {
     /* The main object code */
-    ocFlushInstructionCacheFrom(oc->image
-#ifdef darwin_HOST_OS
-            + oc->misalignment
-#endif
-            , oc->fileSize);
+    ocFlushInstructionCacheFrom(oc->image + oc->misalignment, oc->fileSize);
 
     /* Jump Islands */
     ocFlushInstructionCacheFrom(oc->symbol_extras, sizeof(SymbolExtra) * oc->n_symbol_extras);
@@ -3635,21 +3016,17 @@ ocFlushInstructionCache( ObjectCode *oc )
 
 
 /* --------------------------------------------------------------------------
- * PEi386 specifics (Win32 targets)
+ * PEi386(+) specifics (Win32 targets)
  * ------------------------------------------------------------------------*/
 
 /* The information for this linker comes from
       Microsoft Portable Executable
       and Common Object File Format Specification
-      revision 5.1 January 1998
-   which SimonM says comes from the MS Developer Network CDs.
+      revision 8.3 February 2013
 
-   It can be found there (on older CDs), but can also be found
-   online at:
+   It can be found online at:
 
-      http://www.microsoft.com/hwdev/hardware/PECOFF.asp
-
-   (this is Rev 6.0 from February 1999).
+      https://msdn.microsoft.com/en-us/windows/hardware/gg463119.aspx
 
    Things move, so if that fails, try searching for it via
 
@@ -3670,159 +3047,207 @@ ocFlushInstructionCache( ObjectCode *oc )
 
    John Levine's book "Linkers and Loaders" contains useful
    info on PE too.
+
+   The PE specification doesn't specify how to do the actual
+   relocations. For this reason, and because both PE and ELF are
+   based on COFF, the relocations for the PEi386+ code is based on
+   the ELF relocations for the equivalent relocation type.
+
+   The ELF ABI can be found at
+
+   http://www.x86-64.org/documentation/abi.pdf
+
+   The current code is based on version 0.99.6 - October 2013
 */
 
 
 #if defined(OBJFORMAT_PEi386)
 
+static int verifyCOFFHeader ( COFF_header *hdr, pathchar *filename);
 
+/* We assume file pointer is right at the
+   beginning of COFF object.
+ */
+static char *
+allocateImageAndTrampolines (
+   pathchar* arch_name, char* member_name,
+   FILE* f USED_IF_x86_64_HOST_ARCH,
+   int size,
+   int isThin USED_IF_x86_64_HOST_ARCH)
+{
+   char* image;
+#if defined(x86_64_HOST_ARCH)
+   if (!isThin)
+   {
+       /* PeCoff contains number of symbols right in it's header, so
+          we can reserve the room for symbolExtras right here. */
+       COFF_header hdr;
+       size_t n;
+
+       n = fread(&hdr, 1, sizeof_COFF_header, f);
+       if (n != sizeof(COFF_header)) {
+           errorBelch("getNumberOfSymbols: error whilst reading `%s' header in `%S'",
+               member_name, arch_name);
+           return NULL;
+       }
+       fseek(f, -sizeof_COFF_header, SEEK_CUR);
 
-typedef unsigned char          UChar;
-typedef unsigned short         UInt16;
-typedef unsigned int           UInt32;
-typedef          int           Int32;
-typedef unsigned long long int UInt64;
+       if (!verifyCOFFHeader(&hdr, arch_name)) {
+           return 0;
+       }
 
+       /* We get back 8-byte aligned memory (is that guaranteed?), but
+          the offsets to the sections within the file are all 4 mod 8
+          (is that guaranteed?). We therefore need to offset the image
+          by 4, so that all the pointers are 8-byte aligned, so that
+          pointer tagging works. */
+       /* For 32-bit case we don't need this, hence we use macro PEi386_IMAGE_OFFSET,
+          which equals to 4 for 64-bit case and 0 for 32-bit case. */
+       /* We allocate trampolines area for all symbols right behind
+          image data, aligned on 8. */
+       size = ((PEi386_IMAGE_OFFSET + size + 0x7) & ~0x7)
+           + hdr.NumberOfSymbols * sizeof(SymbolExtra);
+   }
+#endif
+   image = VirtualAlloc(NULL, size,
+                        MEM_RESERVE | MEM_COMMIT,
+                        PAGE_EXECUTE_READWRITE);
 
-typedef
-   struct {
-      UInt16 Machine;
-      UInt16 NumberOfSections;
-      UInt32 TimeDateStamp;
-      UInt32 PointerToSymbolTable;
-      UInt32 NumberOfSymbols;
-      UInt16 SizeOfOptionalHeader;
-      UInt16 Characteristics;
+   if (image == NULL) {
+       errorBelch("%" PATH_FMT ": failed to allocate memory for image for %s",
+                  arch_name, member_name);
+       return NULL;
    }
-   COFF_header;
 
-#define sizeof_COFF_header 20
+   return image + PEi386_IMAGE_OFFSET;
+}
+
+static int findAndLoadImportLibrary(ObjectCode* oc)
+{
+    int i;
 
+    COFF_header*  hdr;
+    COFF_section* sectab;
+    COFF_symbol*  symtab;
+    UChar*        strtab;
 
-typedef
-   struct {
-      UChar  Name[8];
-      UInt32 VirtualSize;
-      UInt32 VirtualAddress;
-      UInt32 SizeOfRawData;
-      UInt32 PointerToRawData;
-      UInt32 PointerToRelocations;
-      UInt32 PointerToLinenumbers;
-      UInt16 NumberOfRelocations;
-      UInt16 NumberOfLineNumbers;
-      UInt32 Characteristics;
-   }
-   COFF_section;
+    hdr = (COFF_header*)(oc->image);
+    sectab = (COFF_section*)(
+        ((UChar*)(oc->image))
+        + sizeof_COFF_header + hdr->SizeOfOptionalHeader
+        );
 
-#define sizeof_COFF_section 40
+    symtab = (COFF_symbol*)(
+        ((UChar*)(oc->image))
+        + hdr->PointerToSymbolTable
+        );
 
+    strtab = ((UChar*)symtab)
+        + hdr->NumberOfSymbols * sizeof_COFF_symbol;
 
-typedef
-   struct {
-      UChar  Name[8];
-      UInt32 Value;
-      UInt16 SectionNumber;
-      UInt16 Type;
-      UChar  StorageClass;
-      UChar  NumberOfAuxSymbols;
-   }
-   COFF_symbol;
+    for (i = 0; i < oc->n_sections; i++)
+    {
+        COFF_section* sectab_i
+            = (COFF_section*)myindex(sizeof_COFF_section, sectab, i);
 
-#define sizeof_COFF_symbol 18
+        char *secname = cstring_from_section_name(sectab_i->Name, strtab);
 
+        // Find the first entry containing a valid .idata$7 section.
+        if (strcmp(secname, ".idata$7") == 0) {
+            /* First load the containing DLL if not loaded. */
+            Section section = oc->sections[i];
 
-typedef
-   struct {
-      UInt32 VirtualAddress;
-      UInt32 SymbolTableIndex;
-      UInt16 Type;
-   }
-   COFF_reloc;
+            pathchar* dirName = pathdir(oc->fileName);
+            HsPtr token       = addLibrarySearchPath(dirName);
+            stgFree(dirName);
+            char* dllName = (char*)section.start;
+
+            if (strlen(dllName) == 0 || dllName[0] == ' ')
+            {
+                continue;
+            }
 
-#define sizeof_COFF_reloc 10
+            IF_DEBUG(linker, debugBelch("lookupSymbol: on-demand '%ls' => `%s'\n", oc->fileName, dllName));
 
+            pathchar* dll = mkPath(dllName);
+            removeLibrarySearchPath(token);
 
-/* From PE spec doc, section 3.3.2 */
-/* Note use of MYIMAGE_* since IMAGE_* are already defined in
-   windows.h -- for the same purpose, but I want to know what I'm
-   getting, here. */
-#define MYIMAGE_FILE_RELOCS_STRIPPED     0x0001
-#define MYIMAGE_FILE_EXECUTABLE_IMAGE    0x0002
-#define MYIMAGE_FILE_DLL                 0x2000
-#define MYIMAGE_FILE_SYSTEM              0x1000
-#define MYIMAGE_FILE_BYTES_REVERSED_HI   0x8000
-#define MYIMAGE_FILE_BYTES_REVERSED_LO   0x0080
-#define MYIMAGE_FILE_32BIT_MACHINE       0x0100
+            const char* result = addDLL(dll);
+            stgFree(dll);
 
-/* From PE spec doc, section 5.4.2 and 5.4.4 */
-#define MYIMAGE_SYM_CLASS_EXTERNAL       2
-#define MYIMAGE_SYM_CLASS_STATIC         3
-#define MYIMAGE_SYM_UNDEFINED            0
+            if (result != NULL) {
+                errorBelch("Could not load `%s'. Reason: %s\n", (char*)dllName, result);
+                return 0;
+            }
 
-/* From PE spec doc, section 4.1 */
-#define MYIMAGE_SCN_CNT_CODE             0x00000020
-#define MYIMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040
-#define MYIMAGE_SCN_LNK_NRELOC_OVFL      0x01000000
+            break;
+        }
 
-/* From PE spec doc, section 5.2.1 */
-#define MYIMAGE_REL_I386_DIR32           0x0006
-#define MYIMAGE_REL_I386_REL32           0x0014
+        stgFree(secname);
+    }
 
-static int verifyCOFFHeader ( COFF_header *hdr, pathchar *filename);
+    return 1;
+}
 
-/* We assume file pointer is right at the
-   beginning of COFF object.
- */
-static char *
-allocateImageAndTrampolines (
-   pathchar* arch_name, char* member_name,
-#if defined(x86_64_HOST_ARCH)
-   FILE* f,
-#endif
-   int size )
+static int checkAndLoadImportLibrary( pathchar* arch_name, char* member_name, FILE* f)
 {
-   char* image;
-#if defined(x86_64_HOST_ARCH)
-   /* PeCoff contains number of symbols right in it's header, so
-      we can reserve the room for symbolExtras right here. */
-   COFF_header hdr;
-   size_t n;
-
-   n = fread ( &hdr, 1, sizeof_COFF_header, f );
-   if (n != sizeof( COFF_header )) {
-       errorBelch("getNumberOfSymbols: error whilst reading `%s' header in `%S'",
-                  member_name, arch_name);
-       return NULL;
-   }
-   fseek( f, -sizeof_COFF_header, SEEK_CUR );
+    char* image;
+    static HsBool load_dll_warn = HS_BOOL_FALSE;
+
+    if (load_dll_warn) { return 0; }
 
-   if (!verifyCOFFHeader(&hdr, arch_name)) {
-       return 0;
-   }
+    /* Based on Import Library specification. PE Spec section 7.1 */
 
-   /* We get back 8-byte aligned memory (is that guaranteed?), but
-      the offsets to the sections within the file are all 4 mod 8
-      (is that guaranteed?). We therefore need to offset the image
-      by 4, so that all the pointers are 8-byte aligned, so that
-      pointer tagging works. */
-   /* For 32-bit case we don't need this, hence we use macro PEi386_IMAGE_OFFSET,
-      which equals to 4 for 64-bit case and 0 for 32-bit case. */
-   /* We allocate trampolines area for all symbols right behind
-      image data, aligned on 8. */
-   size = ((PEi386_IMAGE_OFFSET + size + 0x7) & ~0x7)
-              + hdr.NumberOfSymbols * sizeof(SymbolExtra);
-#endif
-   image = VirtualAlloc(NULL, size,
-                        MEM_RESERVE | MEM_COMMIT,
-                        PAGE_EXECUTE_READWRITE);
+    COFF_import_header hdr;
+    size_t n;
 
-   if (image == NULL) {
-       errorBelch("%" PATH_FMT ": failed to allocate memory for image for %s",
-                  arch_name, member_name);
-       return NULL;
-   }
+    n = fread(&hdr, 1, sizeof_COFF_import_Header, f);
+    if (n != sizeof(COFF_header)) {
+        errorBelch("getNumberOfSymbols: error whilst reading `%s' header in `%" PATH_FMT "'\n",
+            member_name, arch_name);
+        return 0;
+    }
 
-   return image + PEi386_IMAGE_OFFSET;
+    if (hdr.Sig1 != 0x0 || hdr.Sig2 != 0xFFFF) {
+        fseek(f, -sizeof_COFF_import_Header, SEEK_CUR);
+        IF_DEBUG(linker, debugBelch("loadArchive: Object `%s` is not an import lib. Skipping...\n", member_name));
+        return 0;
+    }
+
+    IF_DEBUG(linker, debugBelch("loadArchive: reading %d bytes at %ld\n", hdr.SizeOfData, ftell(f)));
+
+    image = malloc(hdr.SizeOfData);
+    n = fread(image, 1, hdr.SizeOfData, f);
+    if (n != hdr.SizeOfData) {
+        errorBelch("loadArchive: error whilst reading `%s' header in `%" PATH_FMT "'. Did not read enough bytes.\n",
+            member_name, arch_name);
+    }
+
+    char* symbol  = strtok(image, "\0");
+    int symLen    = strlen(symbol) + 1;
+    int nameLen   = n - symLen;
+    char* dllName = malloc(sizeof(char) * nameLen);
+    dllName       = strncpy(dllName, image + symLen, nameLen);
+    pathchar* dll = malloc(sizeof(wchar_t) * nameLen);
+    mbstowcs(dll, dllName, nameLen);
+    free(dllName);
+
+    IF_DEBUG(linker, debugBelch("loadArchive: read symbol %s from lib `%ls'\n", symbol, dll));
+    const char* result = addDLL(dll);
+
+    free(image);
+
+    if (result != NULL) {
+        errorBelch("Could not load `%ls'. Reason: %s\n", dll, result);
+        load_dll_warn = HS_BOOL_TRUE;
+
+        free(dll);
+        fseek(f, -(n + sizeof_COFF_import_Header), SEEK_CUR);
+        return 0;
+    }
+
+    free(dll);
+    return 1;
 }
 
 /* We use myindex to calculate array addresses, rather than
@@ -3930,62 +3355,8 @@ cstring_from_section_name (UChar* name, UChar* strtab)
     }
 }
 
-/* Just compares the short names (first 8 chars) */
-static COFF_section *
-findPEi386SectionCalled ( ObjectCode* oc,  UChar* name, UChar* strtab )
-{
-   int i;
-   rtsBool long_name = rtsFalse;
-   COFF_header* hdr
-      = (COFF_header*)(oc->image);
-   COFF_section* sectab
-      = (COFF_section*) (
-           ((UChar*)(oc->image))
-           + sizeof_COFF_header + hdr->SizeOfOptionalHeader
-        );
-   // String is longer than 8 bytes, swap in the proper
-   // (NULL-terminated) version, and make a note that this
-   // is a long name.
-   if (name[0]==0 && name[1]==0 && name[2]==0 && name[3]==0) {
-      UInt32 strtab_offset = * (UInt32*)(name+4);
-      name = ((UChar*)strtab) + strtab_offset;
-      long_name = rtsTrue;
-   }
-   for (i = 0; i < hdr->NumberOfSections; i++) {
-      UChar* n1;
-      UChar* n2;
-      COFF_section* section_i
-         = (COFF_section*)
-           myindex ( sizeof_COFF_section, sectab, i );
-      n1 = (UChar*) &(section_i->Name);
-      n2 = name;
-      // Long section names are prefixed with a slash, see
-      // also cstring_from_section_name
-      if (n1[0] == '/' && long_name) {
-         // Long name check
-         // We don't really want to make an assumption that the string
-         // table indexes are the same, so we'll do a proper check.
-         int n1_strtab_offset = strtol((char*)n1+1,NULL,10);
-         n1 = (UChar*) (((char*)strtab) + n1_strtab_offset);
-         if (0==strcmp((const char*)n1, (const char*)n2)) {
-            return section_i;
-         }
-      } else if (n1[0] != '/' && !long_name) {
-         // Short name check
-         if (n1[0]==n2[0] && n1[1]==n2[1] && n1[2]==n2[2] &&
-             n1[3]==n2[3] && n1[4]==n2[4] && n1[5]==n2[5] &&
-             n1[6]==n2[6] && n1[7]==n2[7]) {
-            return section_i;
-         }
-      } else {
-         // guaranteed to mismatch, because we never attempt to link
-         // in an executable where the section name may be truncated
-      }
-   }
-
-   return NULL;
-}
-
+/* See Note [mingw-w64 name decoration scheme] */
+#ifndef x86_64_HOST_ARCH
 static void
 zapTrailingAtSign ( UChar* sym )
 {
@@ -4000,27 +3371,44 @@ zapTrailingAtSign ( UChar* sym )
    if (j > 0 && sym[j] == '@' && j != i) sym[j] = 0;
 #  undef my_isdigit
 }
+#endif
 
-static void *
+/* See Note [mingw-w64 name decoration scheme] */
+#ifndef x86_64_HOST_ARCH
+#define STRIP_LEADING_UNDERSCORE 1
+#else
+#define STRIP_LEADING_UNDERSCORE 0
+#endif
+
+/*
+  Note [mingw-w64 name decoration scheme]
+
+  What's going on with name decoration? Well, original code
+  have some crufty and ad-hocish paths related mostly to very old
+  mingw gcc/binutils/runtime combinations. Now mingw-w64 offers pretty
+  uniform and MS-compatible decoration scheme across its tools and runtime.
+
+  The scheme is pretty straightforward: on 32 bit objects symbols are exported
+  with underscore prepended (and @ + stack size suffix appended for stdcall
+  functions), on 64 bits no underscore is prepended and no suffix is appended
+  because we have no stdcall convention on 64 bits.
+
+  See #9218
+*/
+
+static SymbolAddr*
 lookupSymbolInDLLs ( UChar *lbl )
 {
     OpenedDLL* o_dll;
-    void *sym;
+    SymbolAddr* sym;
 
     for (o_dll = opened_dlls; o_dll != NULL; o_dll = o_dll->next) {
-        /* debugBelch("look in %s for %s\n", o_dll->name, lbl); */
+        /* debugBelch("look in %ls for %s\n", o_dll->name, lbl); */
 
-        if (lbl[0] == '_') {
-            /* HACK: if the name has an initial underscore, try stripping
-               it off & look that up first. I've yet to verify whether there's
-               a Rule that governs whether an initial '_' *should always* be
-               stripped off when mapping from import lib name to the DLL name.
-            */
-            sym = GetProcAddress(o_dll->instance, (char*)(lbl+1));
-            if (sym != NULL) {
-                /*debugBelch("found %s in %s\n", lbl+1,o_dll->name);*/
-                return sym;
-            }
+        sym = GetProcAddress(o_dll->instance, (char*)(lbl+STRIP_LEADING_UNDERSCORE));
+        if (sym != NULL) {
+            /*debugBelch("found %s in %s\n", lbl+1,o_dll->name);*/
+            return sym;
         }
 
         /* Ticket #2283.
@@ -4031,15 +3419,16 @@ lookupSymbolInDLLs ( UChar *lbl )
              the same semantics as in __imp_foo = GetProcAddress(..., "foo")
          */
         if (sym == NULL && strncmp ((const char*)lbl, "__imp_", 6) == 0) {
-            sym = GetProcAddress(o_dll->instance, (char*)(lbl+6));
+            sym = GetProcAddress(o_dll->instance, (char*)(lbl+6+STRIP_LEADING_UNDERSCORE));
             if (sym != NULL) {
                 IndirectAddr* ret;
                 ret = stgMallocBytes( sizeof(IndirectAddr), "lookupSymbolInDLLs" );
                 ret->addr = sym;
                 ret->next = indirects;
                 indirects = ret;
-                errorBelch("warning: %s from %S is linked instead of %s",
-                              (char*)(lbl+6), o_dll->name, (char*)lbl);
+                IF_DEBUG(linker,
+                  debugBelch("warning: %s from %S is linked instead of %s\n",
+                             (char*)(lbl+6+STRIP_LEADING_UNDERSCORE), o_dll->name, (char*)lbl));
                 return (void*) & ret->addr;
                }
         }
@@ -4132,14 +3521,37 @@ ocVerifyImage_PEi386 ( ObjectCode* oc )
    }
 #endif
 
+   /* .BSS Section is initialized in ocGetNames_PEi386
+      but we need the Sections array initialized here already. */
+   Section *sections;
+   sections = (Section*)stgCallocBytes(
+       sizeof(Section),
+       hdr->NumberOfSections + 1, /* +1 for the global BSS section see ocGetNames_PEi386 */
+       "ocVerifyImage_PEi386(sections)");
+   oc->sections = sections;
+   oc->n_sections = hdr->NumberOfSections + 1;
+
+   /* Initialize the Sections */
+   for (i = 0; i < hdr->NumberOfSections; i++) {
+       COFF_section* sectab_i
+           = (COFF_section*)
+           myindex(sizeof_COFF_section, sectab, i);
+
+       /* Calculate the start of the data section */
+       sections[i].start = oc->image + sectab_i->PointerToRawData;
+   }
+
    /* No further verification after this point; only debug printing. */
    i = 0;
    IF_DEBUG(linker, i=1);
    if (i == 0) return 1;
 
-   debugBelch( "sectab offset = %" FMT_Int "\n", ((UChar*)sectab) - ((UChar*)hdr) );
-   debugBelch( "symtab offset = %" FMT_Int "\n", ((UChar*)symtab) - ((UChar*)hdr) );
-   debugBelch( "strtab offset = %" FMT_Int "\n", ((UChar*)strtab) - ((UChar*)hdr) );
+   debugBelch("sectab offset = %" FMT_SizeT "\n",
+              ((UChar*)sectab) - ((UChar*)hdr) );
+   debugBelch("symtab offset = %" FMT_SizeT "\n",
+              ((UChar*)symtab) - ((UChar*)hdr) );
+   debugBelch("strtab offset = %" FMT_SizeT "\n",
+              ((UChar*)strtab) - ((UChar*)hdr) );
 
    debugBelch("\n" );
    debugBelch( "Machine:           0x%x\n", (UInt32)(hdr->Machine) );
@@ -4157,6 +3569,7 @@ ocVerifyImage_PEi386 ( ObjectCode* oc )
       COFF_section* sectab_i
          = (COFF_section*)
            myindex ( sizeof_COFF_section, sectab, i );
+      Section section = sections[i];
       debugBelch(
                 "\n"
                 "section %d\n"
@@ -4169,14 +3582,14 @@ ocVerifyImage_PEi386 ( ObjectCode* oc )
                 "    vsize %d\n"
                 "    vaddr %d\n"
                 "  data sz %d\n"
-                " data off %d\n"
+                " data off 0x%p\n"
                 "  num rel %d\n"
                 "  off rel %d\n"
                 "  ptr raw 0x%x\n",
                 sectab_i->VirtualSize,
                 sectab_i->VirtualAddress,
                 sectab_i->SizeOfRawData,
-                sectab_i->PointerToRawData,
+                section.start,
                 sectab_i->NumberOfRelocations,
                 sectab_i->PointerToRelocations,
                 sectab_i->PointerToRawData
@@ -4270,9 +3683,9 @@ ocGetNames_PEi386 ( ObjectCode* oc )
    COFF_symbol*  symtab;
    UChar*        strtab;
 
-   UChar* sname;
-   void*  addr;
-   int    i;
+   UChar*     sname;
+   SymbolAddr* addr;
+   int        i;
 
    hdr = (COFF_header*)(oc->image);
    sectab = (COFF_section*) (
@@ -4322,13 +3735,12 @@ ocGetNames_PEi386 ( ObjectCode* oc )
        * triggered this is libraries/base/cbits/dirUtils.c:__hscore_getFolderPath())
        */
       if (sectab_i->VirtualSize == 0 && sectab_i->SizeOfRawData == 0) continue;
-      /* This is a non-empty .bss section.  Allocate zeroed space for
-         it, and set its PointerToRawData field such that oc->image +
-         PointerToRawData == addr_of_zeroed_space.  */
+      /* This is a non-empty .bss section.
+         Allocate zeroed space for it */
       bss_sz = sectab_i->VirtualSize;
       if ( bss_sz < sectab_i->SizeOfRawData) { bss_sz = sectab_i->SizeOfRawData; }
       zspace = stgCallocBytes(1, bss_sz, "ocGetNames_PEi386(anonymous bss)");
-      sectab_i->PointerToRawData = ((UChar*)zspace) - ((UChar*)(oc->image));
+      oc->sections[i].start = zspace;
       addProddableBlock(oc, zspace, bss_sz);
       /* debugBelch("BSS anon section at 0x%x\n", zspace); */
    }
@@ -4340,41 +3752,32 @@ ocGetNames_PEi386 ( ObjectCode* oc )
       UChar* end;
       UInt32 sz;
 
+      /* By default consider all section as CODE or DATA, which means we want to load them. */
       SectionKind kind
-         = SECTIONKIND_OTHER;
+          = SECTIONKIND_CODE_OR_RODATA;
       COFF_section* sectab_i
          = (COFF_section*)
            myindex ( sizeof_COFF_section, sectab, i );
+      Section section = oc->sections[i];
 
       char *secname = cstring_from_section_name(sectab_i->Name, strtab);
 
       IF_DEBUG(linker, debugBelch("section name = %s\n", secname ));
 
-#     if 0
-      /* I'm sure this is the Right Way to do it.  However, the
-         alternative of testing the sectab_i->Name field seems to
-         work ok with Cygwin.
-
-         EZY: We should strongly consider using this style, because
-         it lets us pick up sections that should be added (e.g.
-         for a while the linker did not work due to missing .eh_frame
-         in this section.)
-      */
+      /* The PE file section flag indicates whether the section contains code or data. */
       if (sectab_i->Characteristics & MYIMAGE_SCN_CNT_CODE ||
           sectab_i->Characteristics & MYIMAGE_SCN_CNT_INITIALIZED_DATA)
          kind = SECTIONKIND_CODE_OR_RODATA;
-#     endif
 
-      if (0==strcmp(".text",(char*)secname) ||
-          0==strcmp(".text.startup",(char*)secname) ||
-          0==strcmp(".text.unlikely", (char*)secname) ||
-          0==strcmp(".rdata",(char*)secname)||
-          0==strcmp(".eh_frame", (char*)secname)||
-          0==strcmp(".rodata",(char*)secname))
-         kind = SECTIONKIND_CODE_OR_RODATA;
-      if (0==strcmp(".data",(char*)secname) ||
-          0==strcmp(".bss",(char*)secname))
+      /* Check next if it contains any uninitialized data */
+      if (sectab_i->Characteristics & MYIMAGE_SCN_CNT_UNINITIALIZED_DATA)
          kind = SECTIONKIND_RWDATA;
+
+      /* Finally check if it can be discarded. This will also ignore .debug sections */
+      if (sectab_i->Characteristics & MYIMAGE_SCN_MEM_DISCARDABLE ||
+          sectab_i->Characteristics & MYIMAGE_SCN_LNK_REMOVE)
+          kind = SECTIONKIND_OTHER;
+
       if (0==strcmp(".ctors", (char*)secname))
          kind = SECTIONKIND_INIT_ARRAY;
 
@@ -4382,39 +3785,12 @@ ocGetNames_PEi386 ( ObjectCode* oc )
       sz = sectab_i->SizeOfRawData;
       if (sz < sectab_i->VirtualSize) sz = sectab_i->VirtualSize;
 
-      start = ((UChar*)(oc->image)) + sectab_i->PointerToRawData;
+      start = section.start;
       end   = start + sz - 1;
 
-      if (kind == SECTIONKIND_OTHER
-          /* Ignore sections called which contain stabs debugging
-             information. */
-          && 0 != strcmp(".stab", (char*)secname)
-          && 0 != strcmp(".stabstr", (char*)secname)
-          /* Ignore sections called which contain exception information. */
-          && 0 != strncmp(".pdata", (char*)secname, 6)
-          && 0 != strncmp(".xdata", (char*)secname, 6)
-          /* ignore section generated from .ident */
-          && 0!= strncmp(".debug", (char*)secname, 6)
-          /* ignore unknown section that appeared in gcc 3.4.5(?) */
-          && 0!= strcmp(".reloc", (char*)secname)
-          && 0 != strcmp(".rdata$zzz", (char*)secname)
-          /* ignore linker directive sections */
-          && 0 != strcmp(".drectve", (char*)secname)
-         ) {
-         errorBelch("Unknown PEi386 section name `%s' (while processing: %" PATH_FMT")", secname, oc->fileName);
-         stgFree(secname);
-         return 0;
-      }
-
       if (kind != SECTIONKIND_OTHER && end >= start) {
-          if ((((size_t)(start)) % 4) != 0) {
-              errorBelch("Misaligned section %s: %p", (char*)secname, start);
-              stgFree(secname);
-              return 0;
-          }
-
-         addSection(oc, kind, start, end);
-         addProddableBlock(oc, start, end - start + 1);
+          addSection(&oc->sections[i], kind, SECTION_NOMEM, start, sz, 0, 0, 0);
+          addProddableBlock(oc, start, sz);
       }
 
       stgFree(secname);
@@ -4423,23 +3799,47 @@ 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(SymbolName*), 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;
 
-   i = 0;
-   while (1) {
+   /* 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
+           && symtab_i->StorageClass != MYIMAGE_SYM_CLASS_SECTION) {
+           globalBssSize += symtab_i->Value;
+       }
+       i += symtab_i->NumberOfAuxSymbols;
+   }
+
+   /* Allocate BSS space */
+   SymbolAddr* bss = NULL;
+   if (globalBssSize > 0) {
+       bss = stgCallocBytes(1, globalBssSize,
+                            "ocGetNames_PEi386(non-anonymous bss)");
+       addSection(&oc->sections[oc->n_sections-1],
+                  SECTIONKIND_RWDATA, SECTION_MALLOC,
+                  bss, globalBssSize, 0, 0, 0);
+       IF_DEBUG(linker, debugBelch("bss @ %p %" FMT_Word "\n", bss, globalBssSize));
+       addProddableBlock(oc, bss, globalBssSize);
+   } else {
+       addSection(&oc->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;
-      if (i >= (Int32)(hdr->NumberOfSymbols)) break;
       symtab_i = (COFF_symbol*)
                  myindex ( sizeof_COFF_symbol, symtab, i );
 
       addr  = NULL;
-
-      if (symtab_i->StorageClass == MYIMAGE_SYM_CLASS_EXTERNAL
-          && symtab_i->SectionNumber != MYIMAGE_SYM_UNDEFINED) {
+      HsBool isWeak = HS_BOOL_FALSE;
+      if (   symtab_i->SectionNumber != MYIMAGE_SYM_UNDEFINED
+          && symtab_i->SectionNumber > 0) {
          /* This symbol is global and defined, viz, exported */
          /* for MYIMAGE_SYMCLASS_EXTERNAL
                 && !MYIMAGE_SYM_UNDEFINED,
@@ -4450,35 +3850,50 @@ ocGetNames_PEi386 ( ObjectCode* oc )
             = (COFF_section*) myindex ( sizeof_COFF_section,
                                         sectab,
                                         symtab_i->SectionNumber-1 );
-         addr = ((UChar*)(oc->image))
-                + (sectabent->PointerToRawData
-                   + symtab_i->Value);
+         if (symtab_i->StorageClass == MYIMAGE_SYM_CLASS_EXTERNAL
+            || (   symtab_i->StorageClass == MYIMAGE_SYM_CLASS_STATIC
+                && sectabent->Characteristics & MYIMAGE_SCN_LNK_COMDAT)
+            ) {
+                 addr = (void*)((size_t)oc->sections[symtab_i->SectionNumber-1].start
+                      + symtab_i->Value);
+                 if (sectabent->Characteristics & MYIMAGE_SCN_LNK_COMDAT) {
+                    isWeak = HS_BOOL_TRUE;
+              }
+         }
       }
-      else
-      if (symtab_i->SectionNumber == MYIMAGE_SYM_UNDEFINED
-          && symtab_i->Value > 0) {
+      else if (symtab_i->StorageClass == MYIMAGE_SYM_CLASS_WEAK_EXTERNAL) {
+          isWeak = HS_BOOL_TRUE;
+      }
+      else 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 = (SymbolAddr*)((StgWord)bss + (StgWord)symtab_i->Value);
+          IF_DEBUG(linker, debugBelch("bss symbol @ %p %u\n", addr, symtab_i->Value));
       }
 
-      if (addr != NULL ) {
-         sname = cstring_from_COFF_symbol_name ( symtab_i->Name, strtab );
-         /* debugBelch("addSymbol %p `%s \n", addr,sname);  */
+      sname = cstring_from_COFF_symbol_name(symtab_i->Name, strtab);
+      if (addr != NULL || isWeak == HS_BOOL_TRUE) {
+
+         /* debugBelch("addSymbol %p `%s' Weak:%lld \n", addr, sname, isWeak); */
          IF_DEBUG(linker, debugBelch("addSymbol %p `%s'\n", addr,sname);)
          ASSERT(i >= 0 && i < oc->n_symbols);
          /* cstring_from_COFF_symbol_name always succeeds. */
-         oc->symbols[i] = (char*)sname;
-         if (! ghciInsertSymbolTable(oc->fileName, symhash, (char*)sname, addr,
-                                     HS_BOOL_FALSE, oc)) {
+         oc->symbols[i] = (SymbolName*)sname;
+         if (isWeak == HS_BOOL_TRUE) {
+             setWeakSymbol(oc, sname);
+         }
+
+         if (! ghciInsertSymbolTable(oc->fileName, symhash, (SymbolName*)sname, addr,
+                                     isWeak, oc)) {
              return 0;
          }
       } else {
+          /* We're skipping the symbol, but if we ever load this
+          object file we'll want to skip it then too. */
+          oc->symbols[i] = NULL;
+
 #        if 0
          debugBelch(
                    "IGNORING symbol %d\n"
@@ -4503,7 +3918,6 @@ ocGetNames_PEi386 ( ObjectCode* oc )
       }
 
       i += symtab_i->NumberOfAuxSymbols;
-      i++;
    }
 
    return 1;
@@ -4560,7 +3974,7 @@ ocResolve_PEi386 ( ObjectCode* oc )
 
    UInt32        A;
    size_t        S;
-   void *        pP;
+   SymbolAddr*    pP;
 
    int i;
    UInt32 j, noRelocs;
@@ -4591,19 +4005,19 @@ ocResolve_PEi386 ( ObjectCode* oc )
          = (COFF_reloc*) (
               ((UChar*)(oc->image)) + sectab_i->PointerToRelocations
            );
+      Section section = oc->sections[i];
 
       char *secname = cstring_from_section_name(sectab_i->Name, strtab);
 
-      /* Ignore sections called which contain stabs debugging
-         information. */
-      if (0 == strcmp(".stab", (char*)secname)
-          || 0 == strcmp(".stabstr", (char*)secname)
-          || 0 == strncmp(".pdata", (char*)secname, 6)
-          || 0 == strncmp(".xdata", (char*)secname, 6)
-          || 0 == strncmp(".debug", (char*)secname, 6)
-          || 0 == strcmp(".rdata$zzz", (char*)secname)) {
-          stgFree(secname);
-          continue;
+      /* Ignore sections called which contain stabs debugging information. */
+      if (    0 == strcmp(".stab", (char*)secname)
+           || 0 == strcmp(".stabstr", (char*)secname)
+           || 0 == strncmp(".pdata", (char*)secname, 6)
+           || 0 == strncmp(".xdata", (char*)secname, 6)
+           || 0 == strncmp(".debug", (char*)secname, 6)
+           || 0 == strcmp(".rdata$zzz", (char*)secname)) {
+           stgFree(secname);
+           continue;
       }
 
       stgFree(secname);
@@ -4643,11 +4057,10 @@ ocResolve_PEi386 ( ObjectCode* oc )
               myindex ( sizeof_COFF_reloc, reltab, j );
 
          /* the location to patch */
-         pP = (
-                 ((UChar*)(oc->image))
-                 + (sectab_i->PointerToRawData
-                    + reltab_j->VirtualAddress
-                    - sectab_i->VirtualAddress )
+         pP = (void*)(
+                   (size_t)section.start
+                 + reltab_j->VirtualAddress
+                 - sectab_i->VirtualAddress
               );
          /* the existing contents of pP */
          A = *(UInt32*)pP;
@@ -4666,30 +4079,24 @@ ocResolve_PEi386 ( ObjectCode* oc )
                             debugBelch("'\n" ));
 
          if (sym->StorageClass == MYIMAGE_SYM_CLASS_STATIC) {
-            COFF_section* section_sym
-               = findPEi386SectionCalled ( oc, sym->Name, strtab );
-            if (!section_sym) {
-               errorBelch("%" PATH_FMT ": can't find section named: ", oc->fileName);
-               printName(sym->Name, strtab);
-               errorBelch(" in %s", secname);
-               return 0;
-            }
-            S = ((size_t)(oc->image))
-              + ((size_t)(section_sym->PointerToRawData))
+            Section section = oc->sections[sym->SectionNumber-1];
+            S = ((size_t)(section.start))
               + ((size_t)(sym->Value));
          } else {
             copyName ( sym->Name, strtab, symbol, 1000-1 );
             S = (size_t) lookupSymbol_( (char*)symbol );
-            if ((void*)S != NULL) goto foundit;
-            errorBelch("%" PATH_FMT ": unknown symbol `%s'", oc->fileName, symbol);
-            return 0;
-           foundit:;
+            if ((void*)S == NULL) {
+
+                errorBelch("%" PATH_FMT ": unknown symbol `%s'\n", oc->fileName, symbol);
+                return 0;
+            }
          }
          /* All supported relocations write at least 4 bytes */
          checkProddableBlock(oc, pP, 4);
          switch (reltab_j->Type) {
 #if defined(i386_HOST_ARCH)
             case MYIMAGE_REL_I386_DIR32:
+            case MYIMAGE_REL_I386_DIR32NB:
                *(UInt32 *)pP = ((UInt32)S) + A;
                break;
             case MYIMAGE_REL_I386_REL32:
@@ -4721,8 +4128,17 @@ ocResolve_PEi386 ( ObjectCode* oc )
                *(UInt32 *)pP = ((UInt32)S) + A - ((UInt32)(size_t)pP) - 4;
                break;
 #elif defined(x86_64_HOST_ARCH)
-            case 2:  /* R_X86_64_32 */
-            case 17: /* R_X86_64_32S */
+            case 1: /* R_X86_64_64 (ELF constant 1) - IMAGE_REL_AMD64_ADDR64 (PE constant 1) */
+               {
+                   UInt64 A;
+                   checkProddableBlock(oc, pP, 8);
+                   A = *(UInt64*)pP;
+                   *(UInt64 *)pP = ((UInt64)S) + ((UInt64)A);
+                   break;
+               }
+            case 2: /* R_X86_64_32 (ELF constant 10) - IMAGE_REL_AMD64_ADDR32 (PE constant 2) */
+            case 3: /* R_X86_64_32S (ELF constant 11) - IMAGE_REL_AMD64_ADDR32NB (PE constant 3) */
+            case 17: /* R_X86_64_32S ELF constant, no PE mapping. See note [ELF constant in PE file] */
                {
                    size_t v;
                    v = S + ((size_t)A);
@@ -4732,14 +4148,14 @@ ocResolve_PEi386 ( ObjectCode* oc )
                        /* And retry */
                        v = S + ((size_t)A);
                        if (v >> 32) {
-                           barf("R_X86_64_32[S]: High bits are set in %zx for %s",
+                           barf("IMAGE_REL_AMD64_ADDR32[NB]: High bits are set in %zx for %s",
                                 v, (char *)symbol);
                        }
                    }
                    *(UInt32 *)pP = (UInt32)v;
                    break;
                }
-            case 4: /* R_X86_64_PC32 */
+            case 4: /* R_X86_64_PC32 (ELF constant 2) - IMAGE_REL_AMD64_REL32 (PE constant 4) */
                {
                    intptr_t v;
                    v = ((intptr_t)S) + ((intptr_t)(Int32)A) - ((intptr_t)pP) - 4;
@@ -4750,24 +4166,16 @@ ocResolve_PEi386 ( ObjectCode* oc )
                        /* And retry */
                        v = ((intptr_t)S) + ((intptr_t)(Int32)A) - ((intptr_t)pP) - 4;
                        if ((v >> 32) && ((-v) >> 32)) {
-                           barf("R_X86_64_PC32: High bits are set in %zx for %s",
+                           barf("IMAGE_REL_AMD64_REL32: High bits are set in %zx for %s",
                                 v, (char *)symbol);
                        }
                    }
                    *(UInt32 *)pP = (UInt32)v;
                    break;
                }
-            case 1: /* R_X86_64_64 */
-               {
-                 UInt64 A;
-                 checkProddableBlock(oc, pP, 8);
-                 A = *(UInt64*)pP;
-                 *(UInt64 *)pP = ((UInt64)S) + ((UInt64)A);
-                 break;
-               }
 #endif
             default:
-               debugBelch("%" PATH_FMT ": unhandled PEi386 relocation type %d",
+               debugBelch("%" PATH_FMT ": unhandled PEi386 relocation type %d\n",
                      oc->fileName, reltab_j->Type);
                return 0;
          }
@@ -4775,10 +4183,25 @@ ocResolve_PEi386 ( ObjectCode* oc )
       }
    }
 
-   IF_DEBUG(linker, debugBelch("completed %" PATH_FMT, oc->fileName));
+   IF_DEBUG(linker, debugBelch("completed %" PATH_FMT "\n", oc->fileName));
    return 1;
 }
 
+/*
+  Note [ELF constant in PE file]
+
+  For some reason, the PE files produced by GHC contain a linux
+  relocation constant 17 (0x11) in the object files. As far as I (Phyx-) can tell
+  this constant doesn't seem like it's coming from GHC, or at least I could not find
+  anything in the .s output that GHC produces which specifies the relocation type.
+
+  This leads me to believe that this is a bug in GAS. However because this constant is
+  there we must deal with it. This is done by mapping it to the equivalent in behaviour PE
+  relocation constant 0x03.
+
+  See #9907
+*/
+
 static int
 ocRunInit_PEi386 ( ObjectCode *oc )
 {
@@ -4802,13 +4225,20 @@ ocRunInit_PEi386 ( ObjectCode *oc )
     getProgArgv(&argc, &argv);
     getProgEnvv(&envc, &envv);
 
+    /* TODO: This part is just looking for .ctors section. This can be optimized
+       and should for objects compiled with function sections as these produce a
+       large amount of sections.
+
+       This can be done by saving the index of the .ctor section in the ObjectCode
+       from ocGetNames. Then this loop isn't needed. */
     for (i = 0; i < hdr->NumberOfSections; i++) {
         COFF_section* sectab_i
             = (COFF_section*)
                 myindex ( sizeof_COFF_section, sectab, i );
+        Section section = oc->sections[i];
         char *secname = cstring_from_section_name(sectab_i->Name, strtab);
         if (0 == strcmp(".ctors", (char*)secname)) {
-            UChar *init_startC = (UChar*)(oc->image) + sectab_i->PointerToRawData;
+            UChar *init_startC = section.start;
             init_t *init_start, *init_end, *init;
             init_start = (init_t*)init_startC;
             init_end = (init_t*)(init_startC + sectab_i->SizeOfRawData);
@@ -4842,7 +4272,11 @@ ocRunInit_PEi386 ( ObjectCode *oc )
 #  define ELF_TARGET_X64_64
 #  define ELF_64BIT
 #  define ELF_TARGET_AMD64 /* Used inside <elf.h> on Solaris 11 */
-#elif defined(powerpc64_HOST_ARCH)
+#elif defined(powerpc64_HOST_ARCH) || defined(powerpc64le_HOST_ARCH)
+#  define ELF_64BIT
+#elif defined(ia64_HOST_ARCH)
+#  define ELF_64BIT
+#elif defined(aarch64_HOST_ARCH)
 #  define ELF_64BIT
 #endif
 
@@ -4908,6 +4342,7 @@ ocRunInit_PEi386 ( ObjectCode *oc )
 #define Elf_Addr    Elf64_Addr
 #define Elf_Word    Elf64_Word
 #define Elf_Sword   Elf64_Sword
+#define Elf_Half    Elf64_Half
 #define Elf_Ehdr    Elf64_Ehdr
 #define Elf_Phdr    Elf64_Phdr
 #define Elf_Shdr    Elf64_Shdr
@@ -4931,6 +4366,7 @@ ocRunInit_PEi386 ( ObjectCode *oc )
 #define Elf_Addr    Elf32_Addr
 #define Elf_Word    Elf32_Word
 #define Elf_Sword   Elf32_Sword
+#define Elf_Half    Elf32_Half
 #define Elf_Ehdr    Elf32_Ehdr
 #define Elf_Phdr    Elf32_Phdr
 #define Elf_Shdr    Elf32_Shdr
@@ -5046,6 +4482,67 @@ PLTSize(void)
 }
 #endif
 
+/*
+
+   Note [Many ELF Sections]
+
+   The normal section number fields in ELF are limited to 16 bits, which runs
+   out of bits when you try to cram in more sections than that.
+
+   To solve this, the fields e_shnum and e_shstrndx in the ELF header have an
+   escape value (different for each case), and the actual section number is
+   stashed into unused fields in the first section header.
+
+   For symbols, there seems to have been no place in the actual symbol table
+   for the extra bits, so the indexes have been moved into an auxilliary
+   section instead.
+   For symbols in sections beyond 0xff00, the symbol's st_shndx will be an
+   escape value (SHN_XINDEX), and the actual 32-bit section number for symbol N
+   is stored at index N in the SHT_SYMTAB_SHNDX table.
+
+   These extensions seem to be undocumented in version 4.1 of the ABI and only
+   appear in the drafts for the "next" version:
+      https://refspecs.linuxfoundation.org/elf/gabi4+/contents.html
+
+*/
+
+static Elf_Word elf_shnum(Elf_Ehdr* ehdr)
+{
+   Elf_Shdr* shdr = (Elf_Shdr*) ((char*)ehdr + ehdr->e_shoff);
+   Elf_Half shnum = ehdr->e_shnum;
+   return shnum != SHN_UNDEF ? shnum : shdr[0].sh_size;
+}
+
+static Elf_Word elf_shstrndx(Elf_Ehdr* ehdr)
+{
+   Elf_Shdr* shdr = (Elf_Shdr*) ((char*)ehdr + ehdr->e_shoff);
+   Elf_Half shstrndx = ehdr->e_shstrndx;
+#if defined(SHN_XINDEX)
+   return shstrndx != SHN_XINDEX ? shstrndx : shdr[0].sh_link;
+#else
+   // some OSes do not support SHN_XINDEX yet, let's revert to
+   // old way
+   return shstrndx;
+#endif
+}
+
+#if defined(SHN_XINDEX)
+static Elf_Word*
+get_shndx_table(Elf_Ehdr* ehdr)
+{
+   Elf_Word  i;
+   char*     ehdrC    = (char*)ehdr;
+   Elf_Shdr* shdr     = (Elf_Shdr*) (ehdrC + ehdr->e_shoff);
+   const Elf_Word shnum = elf_shnum(ehdr);
+
+   for (i = 0; i < shnum; i++) {
+     if (shdr[i].sh_type == SHT_SYMTAB_SHNDX) {
+       return (Elf32_Word*)(ehdrC + shdr[i].sh_offset);
+     }
+   }
+   return NULL;
+}
+#endif
 
 /*
  * Generic ELF functions
@@ -5056,7 +4553,8 @@ ocVerifyImage_ELF ( ObjectCode* oc )
 {
    Elf_Shdr* shdr;
    Elf_Sym*  stab;
-   int i, j, nent, nstrtab, nsymtabs;
+   int j, nent, nstrtab, nsymtabs;
+   Elf_Word i, shnum, shstrndx;
    char* sh_strtab;
 
    char*     ehdrC = (char*)(oc->image);
@@ -5116,24 +4614,26 @@ ocVerifyImage_ELF ( ObjectCode* oc )
                      return 0;
    }
 
+   shnum = elf_shnum(ehdr);
    IF_DEBUG(linker,debugBelch(
              "\nSection header table: start %ld, n_entries %d, ent_size %d\n",
-             (long)ehdr->e_shoff, ehdr->e_shnum, ehdr->e_shentsize  ));
+             (long)ehdr->e_shoff, shnum, ehdr->e_shentsize  ));
 
-   ASSERT (ehdr->e_shentsize == sizeof(Elf_Shdr));
+   ASSERT(ehdr->e_shentsize == sizeof(Elf_Shdr));
 
    shdr = (Elf_Shdr*) (ehdrC + ehdr->e_shoff);
 
-   if (ehdr->e_shstrndx == SHN_UNDEF) {
+   shstrndx = elf_shstrndx(ehdr);
+   if (shstrndx == SHN_UNDEF) {
       errorBelch("%s: no section header string table", oc->fileName);
       return 0;
    } else {
       IF_DEBUG(linker,debugBelch( "Section header string table is section %d\n",
-                          ehdr->e_shstrndx));
-      sh_strtab = ehdrC + shdr[ehdr->e_shstrndx].sh_offset;
+                          shstrndx));
+      sh_strtab = ehdrC + shdr[shstrndx].sh_offset;
    }
 
-   for (i = 0; i < ehdr->e_shnum; i++) {
+   for (i = 0; i < shnum; i++) {
       IF_DEBUG(linker,debugBelch("%2d:  ", i ));
       IF_DEBUG(linker,debugBelch("type=%2d  ", (int)shdr[i].sh_type ));
       IF_DEBUG(linker,debugBelch("size=%4d  ", (int)shdr[i].sh_size ));
@@ -5142,7 +4642,7 @@ ocVerifyImage_ELF ( ObjectCode* oc )
                ehdrC + shdr[i].sh_offset,
                       ehdrC + shdr[i].sh_offset + shdr[i].sh_size - 1));
 
-#define SECTION_INDEX_VALID(ndx) (ndx > SHN_UNDEF && ndx < ehdr->e_shnum)
+#define SECTION_INDEX_VALID(ndx) (ndx > SHN_UNDEF && ndx < shnum)
 
       switch (shdr[i].sh_type) {
 
@@ -5201,10 +4701,10 @@ ocVerifyImage_ELF ( ObjectCode* oc )
 
    IF_DEBUG(linker,debugBelch( "\nString tables\n" ));
    nstrtab = 0;
-   for (i = 0; i < ehdr->e_shnum; i++) {
+   for (i = 0; i < shnum; i++) {
       if (shdr[i].sh_type == SHT_STRTAB
           /* Ignore the section header's string table. */
-          && i != ehdr->e_shstrndx
+          && i != shstrndx
           /* Ignore string tables named .stabstr, as they contain
              debugging info. */
           && 0 != memcmp(".stabstr", sh_strtab + shdr[i].sh_name, 8)
@@ -5216,10 +4716,12 @@ ocVerifyImage_ELF ( ObjectCode* oc )
    if (nstrtab == 0) {
       IF_DEBUG(linker,debugBelch("   no normal string tables (potentially, but not necessarily a problem)\n"));
    }
-
+#if defined(SHN_XINDEX)
+   Elf_Word* shndxTable = get_shndx_table(ehdr);
+#endif
    nsymtabs = 0;
    IF_DEBUG(linker,debugBelch( "Symbol tables\n" ));
-   for (i = 0; i < ehdr->e_shnum; i++) {
+   for (i = 0; i < shnum; i++) {
       if (shdr[i].sh_type != SHT_SYMTAB) continue;
       IF_DEBUG(linker,debugBelch( "section %d is a symbol table\n", i ));
       nsymtabs++;
@@ -5234,9 +4736,17 @@ ocVerifyImage_ELF ( ObjectCode* oc )
          return 0;
       }
       for (j = 0; j < nent; j++) {
+         Elf_Word secno = stab[j].st_shndx;
+#if defined(SHN_XINDEX)
+         /* See Note [Many ELF Sections] */
+         if (secno == SHN_XINDEX) {
+            ASSERT(shndxTable);
+            secno = shndxTable[j];
+         }
+#endif
          IF_DEBUG(linker,debugBelch("   %2d  ", j ));
          IF_DEBUG(linker,debugBelch("  sec=%-5d  size=%-3d  val=%5p  ",
-                             (int)stab[j].st_shndx,
+                             (int)secno,
                              (int)stab[j].st_size,
                              (char*)stab[j].st_value ));
 
@@ -5260,9 +4770,10 @@ ocVerifyImage_ELF ( ObjectCode* oc )
          }
          IF_DEBUG(linker,debugBelch("  " ));
 
-         IF_DEBUG(linker,debugBelch("name=%s\n",
+         IF_DEBUG(linker,debugBelch("other=%2x ", stab[j].st_other ));
+         IF_DEBUG(linker,debugBelch("name=%s [%x]\n",
                         ehdrC + shdr[shdr[i].sh_link].sh_offset
-                              + stab[j].st_name ));
+                              + stab[j].st_name, stab[j].st_name ));
       }
    }
 
@@ -5276,6 +4787,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;
@@ -5297,13 +4811,13 @@ static int getSectionKind_ELF( Elf_Shdr *hdr, int *is_bss )
         /* .rodata-style section */
         return SECTIONKIND_CODE_OR_RODATA;
     }
-
+#ifndef openbsd_HOST_OS
     if (hdr->sh_type == SHT_INIT_ARRAY
         && (hdr->sh_flags & SHF_ALLOC) && (hdr->sh_flags & SHF_WRITE)) {
        /* .init_array section */
         return SECTIONKIND_INIT_ARRAY;
     }
-
+#endif /* not OpenBSD */
     if (hdr->sh_type == SHT_NOBITS
         && (hdr->sh_flags & SHF_ALLOC) && (hdr->sh_flags & SHF_WRITE)) {
         /* .bss-style section */
@@ -5314,56 +4828,119 @@ 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;
+    size_t 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;
+   Elf_Word i;
+   int 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;
+#if defined(SHN_XINDEX)
+   Elf_Word* shndxTable = get_shndx_table(ehdr);
+#endif
+   const Elf_Word shnum = elf_shnum(ehdr);
 
    ASSERT(symhash != NULL);
 
-   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"). */
+   sections = (Section*)stgCallocBytes(sizeof(Section), shnum,
+                                       "ocGetNames_ELF(sections)");
+   oc->sections = sections;
+   oc->n_sections = 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 < shnum; i++) {
       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(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, start, 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);
 
       oc->n_symbols = nent;
-      oc->symbols = stgCallocBytes(oc->n_symbols, sizeof(char*),
+      oc->symbols = stgCallocBytes(oc->n_symbols, sizeof(SymbolName*),
                                    "ocGetNames_ELF(oc->symbols)");
       // Note calloc: if we fail partway through initializing symbols, we need
       // to undo the additions to the symbol table so far. We know which ones
@@ -5374,16 +4951,29 @@ ocGetNames_ELF ( ObjectCode* oc )
       // ie we should use j = shdr[i].sh_info
       for (j = 0; j < nent; j++) {
 
-         char  isLocal = FALSE; /* avoids uninit-var warning */
-         HsBool isWeak = HS_BOOL_FALSE;
-         char* ad      = NULL;
-         char* nm      = strtab + stab[j].st_name;
-         int   secno   = stab[j].st_shndx;
-
+         char  isLocal  = FALSE; /* avoids uninit-var warning */
+         HsBool isWeak  = HS_BOOL_FALSE;
+         SymbolAddr* ad  = NULL;
+         SymbolName* nm  = strtab + stab[j].st_name;
+         unsigned short shndx = stab[j].st_shndx;
+         Elf_Word secno;
+
+         /* See Note [Many ELF Sections] */
+         /* Note that future checks for special SHN_* numbers should check the
+          * shndx variable, not the section number in secno. Sections with the
+          * real number in the SHN_LORESERVE..HIRESERVE range will have shndx
+          * SHN_XINDEX and a secno with one of the reserved values. */
+         secno = shndx;
+#if defined(SHN_XINDEX)
+         if (shndx == SHN_XINDEX) {
+            ASSERT(shndxTable);
+            secno = shndxTable[j];
+         }
+#endif
          /* Figure out if we want to add it; if so, set ad to its
             address.  Otherwise leave ad == NULL. */
 
-         if (secno == SHN_COMMON) {
+         if (shndx == SHN_COMMON) {
             isLocal = FALSE;
             ad = stgCallocBytes(1, stab[j].st_size, "ocGetNames_ELF(COMMON)");
             /*
@@ -5399,9 +4989,13 @@ ocGetNames_ELF ( ObjectCode* oc )
                 || ELF_ST_BIND(stab[j].st_info)==STB_WEAK
               )
               /* and not an undefined symbol */
-              && stab[j].st_shndx != SHN_UNDEF
+              && shndx != SHN_UNDEF
               /* and not in a "special section" */
-              && stab[j].st_shndx < SHN_LORESERVE
+              && (shndx < SHN_LORESERVE
+#if defined(SHN_XINDEX)
+                  || shndx == SHN_XINDEX
+#endif
+                 )
               &&
               /* and it's a not a section or string table or anything silly */
               ( ELF_ST_TYPE(stab[j].st_info)==STT_FUNC ||
@@ -5410,14 +5004,15 @@ ocGetNames_ELF ( ObjectCode* oc )
               )
             ) {
             /* Section 0 is the undefined section, hence > and not >=. */
-            ASSERT(secno > 0 && secno < ehdr->e_shnum);
+            ASSERT(secno > 0 && secno < shnum);
             /*
             if (shdr[secno].sh_type == SHT_NOBITS) {
                debugBelch("   BSS symbol, size %d off %d name %s\n",
                                stab[j].st_size, stab[j].st_value, nm);
             }
             */
-            ad = ehdrC + shdr[ secno ].sh_offset + stab[j].st_value;
+            ad = (SymbolAddr*)((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;
@@ -5427,7 +5022,7 @@ ocGetNames_ELF ( ObjectCode* oc )
                 * descriptors, so to be consistent we store function descriptors
                 * in the symbol table */
                if (ELF_ST_TYPE(stab[j].st_info) == STT_FUNC)
-                   ad = (char *)allocateFunctionDesc((Elf_Addr)ad);
+                   ad = (SymbolAddr*)allocateFunctionDesc((Elf_Addr)ad);
 #endif
                IF_DEBUG(linker,debugBelch( "addOTabName(GLOB): %10p  %s %s\n",
                                       ad, oc->fileName, nm ));
@@ -5438,39 +5033,74 @@ ocGetNames_ELF ( ObjectCode* oc )
 
          /* And the decision is ... */
 
+         oc->symbols[j] = nm;
+
          if (ad != NULL) {
             ASSERT(nm != NULL);
             /* Acquire! */
             if (isLocal) {
-               /* Ignore entirely. */
+                /* Ignore entirely. */
+                oc->symbols[j] = NULL;
             } else {
+
+                if (isWeak == HS_BOOL_TRUE) {
+                    setWeakSymbol(oc, nm);
+                }
+
                 if (! ghciInsertSymbolTable(oc->fileName, symhash,
                                             nm, ad, isWeak, oc)) {
-                    return 0;
+                    goto fail;
                 }
-                oc->symbols[j] = nm;
             }
          } else {
             /* Skip. */
             IF_DEBUG(linker,debugBelch( "skipping `%s'\n",
-                                   strtab + stab[j].st_name ));
+                                   nm ));
+
+            /* We're skipping the symbol, but if we ever load this
+               object file we'll want to skip it then too. */
+            oc->symbols[j] = NULL;
+
             /*
             debugBelch(
-                    "skipping   bind = %d,  type = %d,  shndx = %d   `%s'\n",
+                    "skipping   bind = %d,  type = %d,  secno = %d   `%s'\n",
                     (int)ELF_ST_BIND(stab[j].st_info),
                     (int)ELF_ST_TYPE(stab[j].st_info),
-                    (int)stab[j].st_shndx,
-                    strtab + stab[j].st_name
+                    (int)secno,
+                    nm
                    );
             */
-            oc->symbols[j] = NULL;
          }
 
       }
    }
 
-   return 1;
+   result = 1;
+   goto end;
+
+fail:
+   result = 0;
+   goto end;
+
+end:
+   if (fd >= 0) close(fd);
+   return result;
+}
+
+#ifdef arm_HOST_ARCH
+// TODO: These likely belong in a library somewhere
+
+// Signed extend a number to a 32-bit int.
+static inline StgInt32 sign_extend32(uint32_t bits, StgWord32 x) {
+    return ((StgInt32) (x << (32 - bits))) >> (32 - bits);
+}
+
+// Does the given signed integer fit into the given bit width?
+static inline StgBool is_int(uint32_t bits, StgInt32 x) {
+    return bits > 32 || (-(1 << (bits-1)) <= x
+                         && x < (1 << (bits-1)));
 }
+#endif
 
 /* Do ELF relocations which lack an explicit addend.  All x86-linux
    and arm-linux relocations appear to be of this form. */
@@ -5479,7 +5109,7 @@ do_Elf_Rel_relocations ( ObjectCode* oc, char* ehdrC,
                          Elf_Shdr* shdr, int shnum )
 {
    int j;
-   char *symbol;
+   SymbolName* symbol;
    Elf_Word* targ;
    Elf_Rel*  rtab = (Elf_Rel*) (ehdrC + shdr[shnum].sh_offset);
    Elf_Sym*  stab;
@@ -5488,21 +5118,20 @@ do_Elf_Rel_relocations ( ObjectCode* oc, char* ehdrC,
    int target_shndx = shdr[shnum].sh_info;
    int symtab_shndx = shdr[shnum].sh_link;
    int strtab_shndx = shdr[symtab_shndx].sh_link;
+#if defined(SHN_XINDEX)
+   Elf_Word* shndx_table = get_shndx_table((Elf_Ehdr*)ehdrC);
+#endif
 
    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++) {
@@ -5523,7 +5152,7 @@ do_Elf_Rel_relocations ( ObjectCode* oc, char* ehdrC,
       int is_target_thm=0, T=0;
 #endif
 
-      IF_DEBUG(linker,debugBelch( "Rel entry %3d is raw(%6p %6p)",
+      IF_DEBUG(linker,debugBelch( "Rel entry %3d is raw(%6p %6p)",
                              j, (void*)offset, (void*)info ));
       if (!info) {
          IF_DEBUG(linker,debugBelch( " ZERO" ));
@@ -5535,14 +5164,19 @@ 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);
-
+            /* See Note [Many ELF Sections] */
+            Elf_Word secno = sym.st_shndx;
+#if defined(SHN_XINDEX)
+            if (secno == SHN_XINDEX) {
+               ASSERT(shndx_table);
+               secno = shndx_table[ELF_R_SYM(info)];
+            }
+#endif
+            S = (Elf_Addr)oc->sections[ secno ].start +
+                stab[ELF_R_SYM(info)].st_value;
          } else {
             symbol = strtab + sym.st_name;
             S_tmp = lookupSymbol_( symbol );
-            if (S_tmp == NULL) return 0;
             S = (Elf_Addr)S_tmp;
          }
          if (!S) {
@@ -5554,6 +5188,7 @@ do_Elf_Rel_relocations ( ObjectCode* oc, char* ehdrC,
 #ifdef arm_HOST_ARCH
          // Thumb instructions have bit 0 of symbol's st_value set
          is_target_thm = S & 0x1;
+
          T = sym.st_info & STT_FUNC && is_target_thm;
 
          // Make sure we clear bit 0. Strictly speaking we should have done
@@ -5563,15 +5198,16 @@ do_Elf_Rel_relocations ( ObjectCode* oc, char* ehdrC,
 #endif
       }
 
-      IF_DEBUG(linker,debugBelch( "Reloc: P = %p   S = %p   A = %p\n",
-                             (void*)P, (void*)S, (void*)A ));
+      int reloc_type = ELF_R_TYPE(info);
+      IF_DEBUG(linker,debugBelch( "Reloc: P = %p   S = %p   A = %p   type=%d\n",
+                             (void*)P, (void*)S, (void*)A, reloc_type ));
       checkProddableBlock ( oc, pP, sizeof(Elf_Word) );
 
 #ifdef i386_HOST_ARCH
       value = S + A;
 #endif
 
-      switch (ELF_R_TYPE(info)) {
+      switch (reloc_type) {
 #        ifdef i386_HOST_ARCH
          case R_386_32:   *pP = value;     break;
          case R_386_PC32: *pP = value - P; break;
@@ -5593,44 +5229,53 @@ do_Elf_Rel_relocations ( ObjectCode* oc, char* ehdrC,
          case R_ARM_CALL:
          case R_ARM_JUMP24:
          {
+            // N.B. LLVM's LLD linker's relocation implement is a fantastic
+            // resource
             StgWord32 *word = (StgWord32 *)P;
-            StgInt32 imm = (*word & 0x00ffffff) << 2;
-            StgInt32 offset;
-            int overflow;
+            StgInt32 imm = (*word & ((1<<24)-1)) << 2;
+
+            const StgBool is_blx = (*word & 0xf0000000) == 0xf0000000;
+            const StgWord32 hBit = is_blx ? ((*word >> 24) & 1) : 0;
+            imm |= hBit << 1;
 
-            // Sign extend 24 to 32 bits
-            if (imm & 0x02000000)
-               imm -= 0x04000000;
-            offset = ((S + imm) | T) - P;
+            // Sign extend to 32 bits
+            // I would have thought this would be 24 bits but LLD uses 26 here.
+            // Hmm.
+            imm = sign_extend32(26, imm);
 
-            overflow = offset <= (StgInt32)0xfe000000 || offset >= (StgInt32)0x02000000;
+            StgWord32 result = ((S + imm) | T) - P;
 
-            if ((is_target_thm && ELF_R_TYPE(info) == R_ARM_JUMP24) || overflow) {
+            const StgBool overflow = !is_int(26, (StgInt32) result);
+
+            // Handle overflow and Thumb interworking
+            const StgBool needs_veneer = (is_target_thm && ELF_R_TYPE(info) == R_ARM_JUMP24) || overflow;
+            if (needs_veneer) {
                // Generate veneer
                // The +8 below is to undo the PC-bias compensation done by the object producer
                SymbolExtra *extra = makeArmSymbolExtra(oc, ELF_R_SYM(info), S+imm+8, 0, is_target_thm);
                // The -8 below is to compensate for PC bias
-               offset = (StgWord32) &extra->jumpIsland - P - 8;
-               offset &= ~1; // Clear thumb indicator bit
-            } else if (is_target_thm && ELF_R_TYPE(info) == R_ARM_CALL) {
-               StgWord32 cond = (*word & 0xf0000000) >> 28;
-               if (cond == 0xe) {
-                  // Change instruction to BLX
-                  *word |= 0xf0000000; // Set first nibble
-                  *word = (*word & ~0x01ffffff)
-                        | ((offset >> 2) & 0x00ffffff)  // imm24
-                        | ((offset & 0x2) << 23);       // H
-                  break;
-               } else {
-                  errorBelch("%s: Can't transition from ARM to Thumb when cond != 0xe\n",
-                        oc->fileName);
+               result = (StgWord32) ((StgInt32) extra->jumpIsland - P - 8);
+               result &= ~1; // Clear thumb indicator bit
+               if (!is_int(26, (StgInt32) result)) {
+                  errorBelch("Unable to fixup overflow'd R_ARM_CALL: jump island=%p, reloc=%p\n",
+                             (void*) extra->jumpIsland, (void*) P);
                   return 0;
                }
             }
 
-            offset >>= 2;
+            // Update the branch target
+            const StgWord32 imm24 = (result & 0x03fffffc) >> 2;
             *word = (*word & ~0x00ffffff)
-                  | (offset & 0x00ffffff);
+                  | (imm24 & 0x00ffffff);
+
+            // Change the relocated branch into a BLX if necessary
+            const StgBool switch_mode = is_target_thm && (reloc_type == R_ARM_CALL);
+            if (!needs_veneer && switch_mode) {
+               const StgWord32 hBit = (result & 0x2) >> 1;
+               // Change instruction to BLX
+               *word = (*word & ~0xFF000000) | ((0xfa | hBit) << 24);
+               IF_DEBUG(linker, debugBelch("Changed BL to BLX at %p\n", word));
+            }
             break;
          }
 
@@ -5638,20 +5283,17 @@ do_Elf_Rel_relocations ( ObjectCode* oc, char* ehdrC,
          case R_ARM_MOVW_ABS_NC:
          {
             StgWord32 *word = (StgWord32 *)P;
-            StgInt32 offset = ((*word & 0xf0000) >> 4)
-                            | (*word & 0xfff);
-            // Sign extend from 16 to 32 bits
-            offset = (offset ^ 0x8000) - 0x8000;
+            StgWord32 imm12 = *word & 0xfff;
+            StgWord32 imm4 = (*word >> 16) & 0xf;
+            StgInt32 offset = imm4 << 12 | imm12;
+            StgWord32 result = (S + offset) | T;
 
-            offset += S;
-            if (ELF_R_TYPE(info) == R_ARM_MOVT_ABS)
-               offset >>= 16;
-            else
-               offset |= T;
+            if (reloc_type == R_ARM_MOVT_ABS)
+                result = (result & 0xffff0000) >> 16;
 
-            *word = (*word & 0xfff0f000)
-                  | ((offset & 0xf000) << 4)
-                  | (offset & 0x0fff);
+            StgWord32 result12 = result & 0xfff;
+            StgWord32 result4 = (result >> 12) & 0xf;
+            *word = (*word & ~0xf0fff) | (result4 << 16) | result12;
             break;
          }
 
@@ -5784,36 +5426,42 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
                           Elf_Shdr* shdr, int shnum )
 {
    int j;
-   char *symbol = NULL;
+   SymbolName* symbol = NULL;
    Elf_Rela* rtab = (Elf_Rela*) (ehdrC + shdr[shnum].sh_offset);
    Elf_Sym*  stab;
    char*     strtab;
    int         nent = shdr[shnum].sh_size / sizeof(Elf_Rela);
    int symtab_shndx = shdr[shnum].sh_link;
    int strtab_shndx = shdr[symtab_shndx].sh_link;
-#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. */
-   Elf_Addr targ;
    int target_shndx = shdr[shnum].sh_info;
+#if defined(SHN_XINDEX)
+   Elf_Word* shndx_table = get_shndx_table((Elf_Ehdr*)ehdrC);
+#endif
+#if defined(DEBUG) || defined(sparc_HOST_ARCH) || defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH)
+   /* This #ifdef only serves to avoid unused-var warnings. */
+   Elf_Addr targ = (Elf_Addr) oc->sections[target_shndx].start;
 #endif
 
    stab  = (Elf_Sym*) (ehdrC + shdr[ symtab_shndx ].sh_offset);
    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);
-#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)
+#if defined(DEBUG) || defined(sparc_HOST_ARCH) || defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH)
       /* This #ifdef only serves to avoid unused-var warnings. */
       Elf_Addr  offset = rtab[j].r_offset;
       Elf_Addr  P      = targ + offset;
       Elf_Addr  A      = rtab[j].r_addend;
 #endif
-#if defined(sparc_HOST_ARCH) || defined(ia64_HOST_ARCH) || defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH)
+#if defined(sparc_HOST_ARCH) || defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH)
       Elf_Addr  value;
 #endif
       Elf_Addr  info   = rtab[j].r_info;
@@ -5839,9 +5487,15 @@ 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);
+            /* See Note [Many ELF Sections] */
+            Elf_Word secno = sym.st_shndx;
+#if defined(SHN_XINDEX)
+            if (secno == SHN_XINDEX) {
+              secno = shndx_table[ELF_R_SYM(info)];
+            }
+#endif
+            S = (Elf_Addr)oc->sections[secno].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) {
@@ -5869,11 +5523,14 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
          IF_DEBUG(linker,debugBelch( "`%s' resolves to %p\n", symbol, (void*)S ));
       }
 
+#if defined(DEBUG) || defined(sparc_HOST_ARCH) || defined(powerpc_HOST_ARCH) \
+    || defined(x86_64_HOST_ARCH)
       IF_DEBUG(linker,debugBelch("Reloc: P = %p   S = %p   A = %p\n",
                                         (void*)P, (void*)S, (void*)A ));
-      /* checkProddableBlock ( oc, (void*)P ); */
+      checkProddableBlock(oc, (void*)P, sizeof(Elf_Word));
+#endif
 
-#if defined(sparc_HOST_ARCH) || defined(ia64_HOST_ARCH) || defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH)
+#if defined(sparc_HOST_ARCH) || defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH)
       value = S + A;
 #endif
 
@@ -5945,6 +5602,9 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
             *(Elf32_Word *) P = value - P;
             break;
 
+         case R_PPC_PLTREL24:
+            value -= 0x8000; /* See Note [.LCTOC1 in PPC PIC code] */
+            /* fallthrough */
          case R_PPC_REL24:
             delta = value - P;
 
@@ -5965,6 +5625,18 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
             *(Elf_Word *) P = (*(Elf_Word *) P & 0xfc000003)
                                           | (delta & 0x3fffffc);
             break;
+
+         case R_PPC_REL16_LO:
+            *(Elf32_Half*) P = value - P;
+            break;
+
+         case R_PPC_REL16_HI:
+            *(Elf32_Half*) P = (value - P) >> 16;
+            break;
+
+         case R_PPC_REL16_HA:
+            *(Elf32_Half*) P = (value + 0x8000 - P) >> 16;
+            break;
 #        endif
 
 #if x86_64_HOST_ARCH
@@ -5979,15 +5651,17 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
 #else
           StgInt64 off = value - P;
           if (off >= 0x7fffffffL || off < -0x80000000L) {
-#if X86_64_ELF_NONPIC_HACK
-              StgInt64 pltAddress = (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S)
+              if (X86_64_ELF_NONPIC_HACK) {
+                  StgInt64 pltAddress =
+                      (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S)
                                                 -> jumpIsland;
-              off = pltAddress + A - P;
-#else
-              errorBelch("R_X86_64_PC32 relocation out of range: %s = %p\nRecompile %s with -fPIC.",
-                         symbol, off, oc->fileName );
-              return 0;
-#endif
+                  off = pltAddress + A - P;
+              } else {
+                  errorBelch("R_X86_64_PC32 relocation out of range: %s = %"
+                             PRId64 "d\nRecompile %s with -fPIC.",
+                             symbol, off, oc->fileName );
+                  return 0;
+              }
           }
           *(Elf64_Word *)P = (Elf64_Word)off;
 #endif
@@ -6006,15 +5680,17 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
           barf("R_X86_64_32 relocation, but ALWAYS_PIC.");
 #else
           if (value >= 0x7fffffffL) {
-#if X86_64_ELF_NONPIC_HACK
-              StgInt64 pltAddress = (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S)
+              if (X86_64_ELF_NONPIC_HACK) {
+                  StgInt64 pltAddress =
+                      (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S)
                                                 -> jumpIsland;
-              value = pltAddress + A;
-#else
-              errorBelch("R_X86_64_32 relocation out of range: %s = %p\nRecompile %s with -fPIC.",
+                  value = pltAddress + A;
+              } else {
+                  errorBelch("R_X86_64_32 relocation out of range: %s = %"
+                         PRId64 "d\nRecompile %s with -fPIC.",
                          symbol, value, oc->fileName );
-              return 0;
-#endif
+                  return 0;
+              }
           }
           *(Elf64_Word *)P = (Elf64_Word)value;
 #endif
@@ -6025,20 +5701,28 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
           barf("R_X86_64_32S relocation, but ALWAYS_PIC.");
 #else
           if ((StgInt64)value > 0x7fffffffL || (StgInt64)value < -0x80000000L) {
-#if X86_64_ELF_NONPIC_HACK
-              StgInt64 pltAddress = (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S)
+              if (X86_64_ELF_NONPIC_HACK) {
+                  StgInt64 pltAddress =
+                      (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S)
                                                 -> jumpIsland;
-              value = pltAddress + A;
-#else
-              errorBelch("R_X86_64_32S relocation out of range: %s = %p\nRecompile %s with -fPIC.",
+                  value = pltAddress + A;
+              } else {
+                  errorBelch("R_X86_64_32S relocation out of range: %s = %"
+                         PRId64 "d\nRecompile %s with -fPIC.",
                          symbol, value, oc->fileName );
-              return 0;
-#endif
+                  return 0;
+              }
           }
           *(Elf64_Sword *)P = (Elf64_Sword)value;
 #endif
           break;
-
+/* These two relocations were introduced in glibc 2.23 and binutils 2.26.
+    But in order to use them the system which compiles the bindist for GHC needs
+    to have glibc >= 2.23. So only use them if they're defined. */
+#if defined(R_X86_64_REX_GOTPCRELX) && defined(R_X86_64_GOTPCRELX)
+      case R_X86_64_REX_GOTPCRELX:
+      case R_X86_64_GOTPCRELX:
+#endif
       case R_X86_64_GOTPCREL:
       {
           StgInt64 gotAddress = (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S)->addr;
@@ -6098,20 +5782,22 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
 static int
 ocResolve_ELF ( ObjectCode* oc )
 {
-   int   shnum, ok;
+   int       ok;
+   Elf_Word  i;
    char*     ehdrC = (char*)(oc->image);
    Elf_Ehdr* ehdr  = (Elf_Ehdr*) ehdrC;
    Elf_Shdr* shdr  = (Elf_Shdr*) (ehdrC + ehdr->e_shoff);
+   const Elf_Word shnum = elf_shnum(ehdr);
 
    /* Process the relocation sections. */
-   for (shnum = 0; shnum < ehdr->e_shnum; shnum++) {
-      if (shdr[shnum].sh_type == SHT_REL) {
-         ok = do_Elf_Rel_relocations ( oc, ehdrC, shdr, shnum );
+   for (i = 0; i < shnum; i++) {
+      if (shdr[i].sh_type == SHT_REL) {
+         ok = do_Elf_Rel_relocations ( oc, ehdrC, shdr, i );
          if (!ok) return ok;
       }
       else
-      if (shdr[shnum].sh_type == SHT_RELA) {
-         ok = do_Elf_Rela_relocations ( oc, ehdrC, shdr, shnum );
+      if (shdr[i].sh_type == SHT_RELA) {
+         ok = do_Elf_Rela_relocations ( oc, ehdrC, shdr, i );
          if (!ok) return ok;
       }
    }
@@ -6125,11 +5811,11 @@ ocResolve_ELF ( ObjectCode* oc )
 
 static int ocRunInit_ELF( ObjectCode *oc )
 {
-   int   i;
+   Elf_Word i;
    char*     ehdrC = (char*)(oc->image);
    Elf_Ehdr* ehdr  = (Elf_Ehdr*) ehdrC;
    Elf_Shdr* shdr  = (Elf_Shdr*) (ehdrC + ehdr->e_shoff);
-   char* sh_strtab = ehdrC + shdr[ehdr->e_shstrndx].sh_offset;
+   char* sh_strtab = ehdrC + shdr[elf_shstrndx(ehdr)].sh_offset;
    int argc, envc;
    char **argv, **envv;
 
@@ -6140,18 +5826,18 @@ static int ocRunInit_ELF( ObjectCode *oc )
    // special!  See DL_DT_INIT_ADDRESS macro in glibc
    // as well as ELF_FUNCTION_PTR_IS_SPECIAL.  We've not handled
    // it here, please file a bug report if it affects you.
-   for (i = 0; i < ehdr->e_shnum; i++) {
+   for (i = 0; i < elf_shnum(ehdr); i++) {
       init_t *init_start, *init_end, *init;
       int is_bss = FALSE;
       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++) {
@@ -6163,7 +5849,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
@@ -6181,22 +5867,24 @@ 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 )
 {
   Elf_Ehdr *ehdr;
   Elf_Shdr* shdr;
-  int i;
+  Elf_Word i, shnum;
 
   ehdr = (Elf_Ehdr *) oc->image;
   shdr = (Elf_Shdr *) ( ((char *)oc->image) + ehdr->e_shoff );
 
-  for( i = 0; i < ehdr->e_shnum; i++ )
+  shnum = elf_shnum(ehdr);
+
+  for( i = 0; i < shnum; i++ )
     if( shdr[i].sh_type == SHT_SYMTAB )
       break;
 
-  if( i == ehdr->e_shnum )
+  if( i == shnum )
   {
     // Not having a symbol table is not in principle a problem.
     // When an object file has no symbols then the 'strip' program
@@ -6217,7 +5905,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 */
 
@@ -6391,14 +6079,14 @@ resolveImports(
     {
         // according to otool, reserved1 contains the first index into the indirect symbol table
         struct nlist *symbol = &nlist[indirectSyms[sect->reserved1+i]];
-        char *nm = image + symLC->stroff + symbol->n_un.n_strx;
-        void *addr = NULL;
+        SymbolName* nm = image + symLC->stroff + symbol->n_un.n_strx;
+        SymbolAddr* addr = NULL;
 
         IF_DEBUG(linker, debugBelch("resolveImports: resolving %s\n", nm));
 
         if ((symbol->n_type & N_TYPE) == N_UNDF
             && (symbol->n_type & N_EXT) && (symbol->n_value != 0)) {
-            addr = (void*) (symbol->n_value);
+            addr = (SymbolAddr*) (symbol->n_value);
             IF_DEBUG(linker, debugBelch("resolveImports: undefined external %s has value %p\n", nm, addr));
         } else {
             addr = lookupSymbol_(nm);
@@ -6419,7 +6107,7 @@ resolveImports(
 
             *(image + sect->offset + i * itemSize) = 0xe9; // jmp opcode
             *(unsigned*)(image + sect->offset + i*itemSize + 1)
-                = (char*)addr - (image + sect->offset + i*itemSize + 5);
+                = (SymbolAddr*)addr - (image + sect->offset + i*itemSize + 5);
         }
         else
 #endif
@@ -6541,8 +6229,8 @@ relocateSection(
          || type == X86_64_RELOC_GOT_LOAD)
         {
             struct nlist *symbol = &nlist[reloc->r_symbolnum];
-            char *nm = image + symLC->stroff + symbol->n_un.n_strx;
-            void *addr = NULL;
+            SymbolName* nm = image + symLC->stroff + symbol->n_un.n_strx;
+            SymbolAddr* addr = NULL;
 
             IF_DEBUG(linker, debugBelch("relocateSection: making jump island for %s, extern = %d, X86_64_RELOC_GOT\n", nm, reloc->r_extern));
 
@@ -6594,8 +6282,8 @@ relocateSection(
         else if (reloc->r_extern)
         {
             struct nlist *symbol = &nlist[reloc->r_symbolnum];
-            char *nm = image + symLC->stroff + symbol->n_un.n_strx;
-            void *addr = NULL;
+            SymbolName* nm = image + symLC->stroff + symbol->n_un.n_strx;
+            SymbolAddr* addr = NULL;
 
             IF_DEBUG(linker, debugBelch("relocateSection: looking up external symbol %s\n", nm));
             IF_DEBUG(linker, debugBelch("               : type  = %d\n", symbol->n_type));
@@ -7033,7 +6721,7 @@ ocGetNames_MachO(ObjectCode* oc)
     struct symtab_command *symLC = NULL;
     struct nlist *nlist;
     unsigned long commonSize = 0;
-    char    *commonStorage = NULL;
+    SymbolAddr* commonStorage = NULL;
     unsigned long commonCounter;
 
     IF_DEBUG(linker,debugBelch("ocGetNames_MachO: start\n"));
@@ -7058,6 +6746,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++)
     {
@@ -7068,16 +6764,18 @@ ocGetNames_MachO(ObjectCode* oc)
             continue;
         }
 
-        if((sections[i].flags & SECTION_TYPE) == S_ZEROFILL)
-        {
-#ifdef USE_MMAP
-            char * zeroFillArea = mmapForLinker(sections[i].size, MAP_ANONYMOUS, -1);
-            if (zeroFillArea == NULL) return 0;
-            memset(zeroFillArea, 0, sections[i].size);
-#else
-            char * zeroFillArea = stgCallocBytes(1,sections[i].size,
+        if((sections[i].flags & SECTION_TYPE) == S_ZEROFILL) {
+            char * zeroFillArea;
+            if (RTS_LINKER_USE_MMAP) {
+                zeroFillArea = mmapForLinker(sections[i].size, MAP_ANONYMOUS,
+                                            -1, 0);
+                if (zeroFillArea == NULL) return 0;
+                memset(zeroFillArea, 0, sections[i].size);
+            }
+            else {
+                zeroFillArea = stgCallocBytes(1,sections[i].size,
                                       "ocGetNames_MachO(common symbols)");
-#endif
+            }
             sections[i].offset = zeroFillArea - image;
         }
 
@@ -7094,11 +6792,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);
@@ -7125,7 +6823,7 @@ ocGetNames_MachO(ObjectCode* oc)
         }
     }
     IF_DEBUG(linker, debugBelch("ocGetNames_MachO: %d external symbols\n", oc->n_symbols));
-    oc->symbols = stgMallocBytes(oc->n_symbols * sizeof(char*),
+    oc->symbols = stgMallocBytes(oc->n_symbols * sizeof(SymbolName*),
                                    "ocGetNames_MachO(oc->symbols)");
 
     if(symLC)
@@ -7138,7 +6836,7 @@ ocGetNames_MachO(ObjectCode* oc)
             {
                 if(nlist[i].n_type & N_EXT)
                 {
-                    char *nm = image + symLC->stroff + nlist[i].n_un.n_strx;
+                    SymbolName* nm = image + symLC->stroff + nlist[i].n_un.n_strx;
                     if ((nlist[i].n_desc & N_WEAK_DEF) && lookupSymbol_(nm)) {
                         // weak definition, and we already have a definition
                         IF_DEBUG(linker, debugBelch("    weak: %s\n", nm));
@@ -7146,14 +6844,20 @@ ocGetNames_MachO(ObjectCode* oc)
                     else
                     {
                             IF_DEBUG(linker, debugBelch("ocGetNames_MachO: inserting %s\n", nm));
-                            ghciInsertSymbolTable(oc->fileName, symhash, nm,
-                                                    image
-                                                    + sections[nlist[i].n_sect-1].offset
-                                                    - sections[nlist[i].n_sect-1].addr
-                                                    + nlist[i].n_value,
-                                                    HS_BOOL_FALSE,
-                                                    oc);
-                            oc->symbols[curSymbol++] = nm;
+                            SymbolAddr* addr = image
+                                       + sections[nlist[i].n_sect - 1].offset
+                                       - sections[nlist[i].n_sect - 1].addr
+                                       + nlist[i].n_value;
+
+                            ghciInsertSymbolTable( oc->fileName
+                                                 , symhash
+                                                 , nm
+                                                 , addr
+                                                 , HS_BOOL_FALSE
+                                                 , oc);
+
+                            oc->symbols[curSymbol] = nm;
+                            curSymbol++;
                     }
                 }
                 else
@@ -7177,7 +6881,7 @@ ocGetNames_MachO(ObjectCode* oc)
              && (nlist[i].n_type & N_EXT)
              && (nlist[i].n_value != 0)) {
 
-                char *nm = image + symLC->stroff + nlist[i].n_un.n_strx;
+                SymbolName* nm = image + symLC->stroff + nlist[i].n_un.n_strx;
                 unsigned long sz = nlist[i].n_value;
 
                 nlist[i].n_value = commonCounter;
@@ -7185,7 +6889,8 @@ ocGetNames_MachO(ObjectCode* oc)
                 IF_DEBUG(linker, debugBelch("ocGetNames_MachO: inserting common symbol: %s\n", nm));
                 ghciInsertSymbolTable(oc->fileName, symhash, nm,
                                        (void*)commonCounter, HS_BOOL_FALSE, oc);
-                oc->symbols[curSymbol++] = nm;
+                oc->symbols[curSymbol] = nm;
+                curSymbol++;
 
                 commonCounter += sz;
             }
@@ -7287,7 +6992,7 @@ static int ocRunInit_MachO ( ObjectCode *oc )
     struct load_command *lc = (struct load_command*) (image + sizeof(struct mach_header));
     struct segment_command *segLC = NULL;
     struct section *sections;
-    nat i;
+    uint32_t i;
 
     for (i = 0; i < header->ncmds; i++) {
         if (lc->cmd == LC_SEGMENT || lc->cmd == LC_SEGMENT_64) {
@@ -7345,24 +7050,35 @@ machoInitSymbolsWithoutUnderscore(void)
     __asm__ volatile(".globl _symbolsWithoutUnderscore\n.data\n_symbolsWithoutUnderscore:");
 
 #undef SymI_NeedsProto
+#undef SymI_NeedsDataProto
+
 #define SymI_NeedsProto(x)  \
     __asm__ volatile(".long " # x);
 
+#define SymI_NeedsDataProto(x) \
+    SymI_NeedsProto(x)
+
     RTS_MACHO_NOUNDERLINE_SYMBOLS
 
     __asm__ volatile(".text");
 
 #undef SymI_NeedsProto
+#undef SymI_NeedsDataProto
+
 #define SymI_NeedsProto(x)  \
     ghciInsertSymbolTable("(GHCi built-in symbols)", symhash, #x, *p++, HS_BOOL_FALSE, NULL);
 
+#define SymI_NeedsDataProto(x) \
+    SymI_NeedsProto(x)
+
     RTS_MACHO_NOUNDERLINE_SYMBOLS
 
 #undef SymI_NeedsProto
+#undef SymI_NeedsDataProto
 }
 #endif
 
-#ifndef USE_MMAP
+#if defined(OBJFORMAT_MACHO)
 /*
  * Figure out by how much to shift the entire Mach-O file in memory
  * when loading so that its single segment ends up 16-byte-aligned