Big-obj support for the Windows runtime linker
authorTamar Christina <tamar@zhox.com>
Sat, 8 Jul 2017 08:57:55 +0000 (09:57 +0100)
committerTamar Christina <tamar@zhox.com>
Sat, 8 Jul 2017 16:00:27 +0000 (17:00 +0100)
Summary:
The normal object file on Windows has a limit of `2^16`
sections that can be in an object-file.

The `big-obj` format raises this to `2^32` sections.

The implementation is made difficult because we now need to support
two header formats and two section formats that differ only by a single
element size within each. The element that's different is in the middle
of the structs and since the structs are used to map regions of memory
directly, it means we need to know which struct it is when we do the
mapping or pointer arithmetics.

This is the final Object-Code format which Windows compilers can generate
which we do not support yet in GHCI. All other major compilers on the platforms
can produce it and all linkers consume it (bfd and lld).

See http://tinyurl.com/bigobj

This patch abstracts away retrieving the fields to functions which all take
an struct which describes which object format is currently being parsed.
These functions are always in-lined as they're small but would looks messy
being copy-pasted everywhere.

Test Plan:
./validate and new test `big-obj`

```
Tamar@Rage MINGW64 /r
$ gcc -c -Wa,-mbig-obj foo.c -o foo.o

Tamar@Rage MINGW64 /r
$ objdump -h foo.o

foo.o:     file format pe-bigobj-x86-64

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         00000010  0000000000000000  0000000000000000  00000128  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000000  0000000000000000  0000000000000000  00000000  2**4
                  ALLOC, LOAD, DATA
  2 .bss          00000000  0000000000000000  0000000000000000  00000000  2**4
                  ALLOC
  3 .xdata        00000008  0000000000000000  0000000000000000  00000138  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .pdata        0000000c  0000000000000000  0000000000000000  00000140  2**2
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
  5 .rdata$zzz    00000030  0000000000000000  0000000000000000  0000014c  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, DATA

Tamar@Rage MINGW64 /r
$ echo main | ~/ghc/inplace/bin/ghc-stage2.exe --interactive bar.hs foo.o
GHCi, version 8.3.20170430: http://www.haskell.org/ghc/  :? for help
[1 of 1] Compiling Main             ( bar.hs, interpreted )
Ok, modules loaded: Main.
*Main> 17
*Main> Leaving GHCi.
```

Reviewers: austin, bgamari, erikd, simonmar

Subscribers: awson, rwbarton, thomie, #ghc_windows_task_force

GHC Trac Issues: #13815

Differential Revision: https://phabricator.haskell.org/D3523

docs/users_guide/8.4.1-notes.rst
rts/linker/PEi386.c
rts/linker/PEi386.h
testsuite/tests/ghci/linking/dyn/Makefile
testsuite/tests/ghci/linking/dyn/all.T
testsuite/tests/ghci/linking/dyn/big-obj-c.c [new file with mode: 0644]
testsuite/tests/ghci/linking/dyn/big-obj.hs [new file with mode: 0644]
testsuite/tests/ghci/linking/dyn/big-obj.stdout [new file with mode: 0644]

index c3b41c3..9b9d79f 100644 (file)
@@ -99,6 +99,8 @@ Runtime system
   by dlltool. The limitation of them needing to be named with the suffix .dll.a is also removed.
   See :ghc-ticket:`13606`, :ghc-ticket:`12499`, :ghc-ticket:`12498`
 
+- The GHCi runtime linker on Windows now supports the `big-obj` file format.
+
 Template Haskell
 ~~~~~~~~~~~~~~~~
 
index 5301eb1..22258fe 100644 (file)
 
    The current code is based on version 0.99.6 - October 2013
 
+   The current GHCi linker supports the following four object file formats:
+
+   * PE/PE+ obj - The normal COFF_ANON_OBJ format which is generated by default
+     from Windows compilers
+
+   * PE/PE+ big-obj - The big object format COFF_ANON_BIG_OBJ which extends the
+     number of sections to 2^31 and the number of symbols in each section. This
+     requires a flag but all Windows compilers can produce it.
+
+   * PE Import format - The import library format defined in the PE standard
+     COFF_IMPORT_LIB and commonly has the file extension .lib
+
+   * GNU BFD import format - The import library format defined and used by GNU
+     tools. See note below.
+
    Note [BFD import library]
 
    On Windows, compilers don't link directly to dynamic libraries.
@@ -151,8 +166,9 @@ static void addDLLHandle(
     HINSTANCE instance);
 
 static bool verifyCOFFHeader(
-    COFF_header *hdr,
-    pathchar *filename);
+    uint16_t machine,
+    IMAGE_FILE_HEADER *hdr,
+    pathchar *fileName);
 
 static bool checkIfDllLoaded(
     HINSTANCE instance);
@@ -275,9 +291,204 @@ void freePreloadObjectFile_PEi386(ObjectCode *oc)
     indirects = NULL;
 }
 
-/* Loads the DLL specified by DLL_NAME, and if successful
-   adds the DLL to the internal linker map and returns the instance handle
-   of the loaded dll in LOADED if LOADED is not NULL. */
+/*************
+ * This function determines what kind of COFF image we are dealing with.
+ * This is needed in order to correctly load and verify objects and their
+ * sections.
+ *************/
+COFF_OBJ_TYPE getObjectType ( char* image, pathchar* fileName )
+{
+    /* {D1BAA1C7-BAEE-4ba9-AF20-FAF66AA4DCB8} */
+    static const char header_bigobj_classid[16] =
+    {
+      0xC7, 0xA1, 0xBA, 0xD1,
+      0xEE, 0xBA,
+      0xa9, 0x4b,
+      0xAF, 0x20,
+      0xFA, 0xF6, 0x6A, 0xA4, 0xDC, 0xB8
+    };
+
+    WORD machine;
+    COFF_OBJ_TYPE ret = COFF_UNKNOWN;
+    /* First check if we have an ANON_OBJECT_HEADER signature.  */
+    ANON_OBJECT_HEADER* anon = (ANON_OBJECT_HEADER*)image;
+    if (   anon->Sig1 == IMAGE_FILE_MACHINE_UNKNOWN
+        && anon->Sig2 == IMPORT_OBJECT_HDR_SIG2)
+    {
+        machine = anon->Machine;
+        if (verifyCOFFHeader (machine, NULL, fileName))
+        {
+            switch (anon->Version)
+            {
+                case 0:
+                    ret = COFF_IMPORT_LIB;
+                    break;
+                case 1:
+                    ret = COFF_ANON_OBJ;
+                    break;
+                case 2:
+                    if (memcmp (&anon->ClassID, header_bigobj_classid, 16) == 0)
+                        ret = COFF_ANON_BIG_OBJ;
+                    break;
+                default:
+                    break;
+            }
+        }
+    } else {
+        /* If it's not an ANON_OBJECT then try an image file.  */
+        IMAGE_FILE_HEADER* img = (IMAGE_FILE_HEADER*)image;
+        machine = img->Machine;
+        if (verifyCOFFHeader (machine, img, fileName))
+            ret = COFF_IMAGE;
+    }
+    return ret;
+}
+
+/*************
+ * Retrieve common header information
+ *************/
+COFF_HEADER_INFO* getHeaderInfo ( ObjectCode* oc )
+{
+   COFF_OBJ_TYPE coff_type = getObjectType (oc->image, oc->fileName);
+
+   COFF_HEADER_INFO* info
+     = stgMallocBytes (sizeof(COFF_HEADER_INFO), "getHeaderInfo");
+   memset (info, 0, sizeof(COFF_HEADER_INFO));
+   info->type = coff_type;
+   switch (coff_type)
+   {
+       case COFF_IMAGE:
+        {
+         IMAGE_FILE_HEADER* hdr = (IMAGE_FILE_HEADER*)oc->image;
+         info->sizeOfHeader         = sizeof(IMAGE_FILE_HEADER);
+         info->sizeOfOptionalHeader = hdr->SizeOfOptionalHeader;
+         info->pointerToSymbolTable = hdr->PointerToSymbolTable;
+         info->numberOfSymbols      = hdr->NumberOfSymbols;
+         info->numberOfSections     = hdr->NumberOfSections;
+        }
+        break;
+       case COFF_ANON_BIG_OBJ:
+        {
+         ANON_OBJECT_HEADER_BIGOBJ* hdr = (ANON_OBJECT_HEADER_BIGOBJ*)oc->image;
+         info->sizeOfHeader         = sizeof(ANON_OBJECT_HEADER_BIGOBJ);
+         info->sizeOfOptionalHeader = 0;
+         info->pointerToSymbolTable = hdr->PointerToSymbolTable;
+         info->numberOfSymbols      = hdr->NumberOfSymbols;
+         info->numberOfSections     = hdr->NumberOfSections;
+        }
+        break;
+       default:
+        {
+         stgFree (info);
+         info = NULL;
+         errorBelch ("Unknown COFF %d type in getHeaderInfo.", coff_type);
+        }
+        break;
+   }
+
+   return info;
+}
+
+/*************
+ * Symbol utility functions
+ *************/
+__attribute__ ((always_inline)) inline
+size_t getSymbolSize ( COFF_HEADER_INFO *info )
+{
+    ASSERT (info);
+    switch (info->type)
+    {
+        case COFF_ANON_BIG_OBJ:
+            return sizeof_COFF_symbol_ex;
+        default:
+            return sizeof_COFF_symbol_og;
+    }
+}
+
+__attribute__ ((always_inline)) inline
+int32_t getSymSectionNumber ( COFF_HEADER_INFO *info, COFF_symbol* sym )
+{
+    ASSERT (info);
+    ASSERT (sym);
+    switch (info->type)
+    {
+        case COFF_ANON_BIG_OBJ:
+            return sym->ex.SectionNumber;
+        default:
+            return sym->og.SectionNumber;
+    }
+}
+
+__attribute__ ((always_inline)) inline
+uint32_t getSymValue ( COFF_HEADER_INFO *info, COFF_symbol* sym )
+{
+    ASSERT (info);
+    ASSERT (sym);
+    switch (info->type)
+    {
+        case COFF_ANON_BIG_OBJ:
+            return sym->ex.Value;
+        default:
+            return sym->og.Value;
+    }
+}
+
+__attribute__ ((always_inline)) inline
+uint8_t getSymStorageClass ( COFF_HEADER_INFO *info, COFF_symbol* sym )
+{
+    ASSERT (info);
+    ASSERT (sym);
+    switch (info->type)
+    {
+        case COFF_ANON_BIG_OBJ:
+            return sym->ex.StorageClass;
+        default:
+            return sym->og.StorageClass;
+    }
+}
+
+__attribute__ ((always_inline)) inline
+uint8_t getSymNumberOfAuxSymbols ( COFF_HEADER_INFO *info, COFF_symbol* sym )
+{
+    ASSERT (info);
+    ASSERT (sym);
+    switch (info->type)
+    {
+        case COFF_ANON_BIG_OBJ:
+            return sym->ex.NumberOfAuxSymbols;
+        default:
+            return sym->og.NumberOfAuxSymbols;
+    }
+}
+
+__attribute__ ((always_inline)) inline
+uint16_t getSymType ( COFF_HEADER_INFO *info, COFF_symbol* sym )
+{
+    ASSERT (info);
+    ASSERT (sym);
+    switch (info->type)
+    {
+        case COFF_ANON_BIG_OBJ:
+            return sym->ex.Type;
+        default:
+            return sym->og.Type;
+    }
+}
+
+__attribute__ ((always_inline)) inline
+uint8_t* getSymShortName ( COFF_HEADER_INFO *info, COFF_symbol* sym )
+{
+    ASSERT (info);
+    ASSERT (sym);
+    switch (info->type)
+    {
+        case COFF_ANON_BIG_OBJ:
+            return sym->ex.N.ShortName;
+        default:
+            return sym->og.N.ShortName;
+    }
+}
+
 const char *
 addDLL_PEi386( pathchar *dll_name, HINSTANCE *loaded )
 {
@@ -488,19 +699,76 @@ allocateImageAndTrampolines (
    {
        /* 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 `%" PATH_FMT "'",
-               member_name, arch_name);
+       /* Minimum header size to read.  */
+       const size_t MIN_HEADER_SIZE = sizeof(ANON_OBJECT_HEADER);
+       char* tmp = stgMallocBytes (MIN_HEADER_SIZE, "allocateImageAndTrampolines");
+       n = fread (tmp, 1, MIN_HEADER_SIZE, f);
+       if (n != MIN_HEADER_SIZE) {
+           stgFree (tmp);
+           errorBelch ("getNumberOfSymbols: error whilst reading `%s' header "
+                       "in `%" PATH_FMT "'",
+                       member_name, arch_name);
            return NULL;
        }
-       fseek(f, -(long int)sizeof_COFF_header, SEEK_CUR);
-
-       if (!verifyCOFFHeader(&hdr, arch_name)) {
-           return 0;
+       fseek(f, -(long int)MIN_HEADER_SIZE, SEEK_CUR);
+
+       COFF_OBJ_TYPE objType = getObjectType (tmp, arch_name);
+       stgFree (tmp);
+       uint32_t numberOfSymbols = 0;
+       switch (objType)
+       {
+           case COFF_IMAGE:
+            {
+                IMAGE_FILE_HEADER hdr;
+                n = fread (&hdr, 1, sizeof(IMAGE_FILE_HEADER), f);
+                if (n != sizeof(IMAGE_FILE_HEADER))
+                {
+                  errorBelch ("getNumberOfSymbols: error whilst reading `%s' "
+                              "image header in `%" PATH_FMT "'",
+                              member_name, arch_name);
+                  return NULL;
+                }
+                fseek (f, -(long int)sizeof(IMAGE_FILE_HEADER), SEEK_CUR);
+                if (!verifyCOFFHeader (hdr.Machine, &hdr, arch_name)) {
+                    return NULL;
+                }
+                numberOfSymbols = hdr.NumberOfSymbols;
+            }
+            break;
+           case COFF_ANON_BIG_OBJ:
+            {
+                ANON_OBJECT_HEADER_BIGOBJ hdr;
+                n = fread (&hdr, 1, sizeof(ANON_OBJECT_HEADER_BIGOBJ), f);
+                if (n != sizeof(ANON_OBJECT_HEADER_BIGOBJ))
+                {
+                  errorBelch ("getNumberOfSymbols: error whilst reading `%s' "
+                              "big obj header in `%" PATH_FMT "'",
+                              member_name, arch_name);
+                  return NULL;
+                }
+                fseek (f, -(long int)sizeof(ANON_OBJECT_HEADER_BIGOBJ), SEEK_CUR);
+                if (!verifyCOFFHeader (hdr.Machine, NULL, arch_name)) {
+                    return NULL;
+                }
+                numberOfSymbols = hdr.NumberOfSymbols;
+            }
+            break;
+           case COFF_ANON_OBJ:
+             barf ("COFF_ANON_OBJ should not be allocated with "
+                   "allocateImageAndTrampolines. It is not specific enough.\n");
+           case COFF_IMPORT_LIB:
+             barf ("COFF_IMPORT_LIB should not be allocated with "
+                   "allocateImageAndTrampolines. It is read-only.\n");
+           case COFF_UNKNOWN:
+           default:
+            {
+              errorBelch (
+                  "getNumberOfSymbols: error whilst reading `%s' header "
+                  "in `%" PATH_FMT "': Unknown COFF_OBJ_TYPE.",
+                  member_name, arch_name);
+              return NULL;
+            }
        }
 
        /* We get back 8-byte aligned memory (is that guaranteed?), but
@@ -513,7 +781,7 @@ allocateImageAndTrampolines (
        /* 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);
+           + numberOfSymbols * sizeof(SymbolExtra);
    }
 #endif
    image = VirtualAlloc(NULL, size,
@@ -529,6 +797,14 @@ allocateImageAndTrampolines (
    return image + PEi386_IMAGE_OFFSET;
 }
 
+/* -----------------------
+ * This loads import libraries following Microsoft's official standard in the PE
+ * documentation. This is a smaller more efficient format which is just a list
+ * of symbol name => dll.
+ *
+ * This function must fail gracefully and if it does, the filestream needs to
+ * be reset to what it was when the function was called.
+ */
 bool checkAndLoadImportLibrary( pathchar* arch_name, char* member_name, FILE* f )
 {
     char* image;
@@ -542,13 +818,17 @@ bool checkAndLoadImportLibrary( pathchar* arch_name, char* member_name, FILE* f
     size_t n;
 
     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);
+    if (n != sizeof_COFF_import_Header)  {
+        errorBelch("loadImportLibrary: error whilst reading `%s' header "
+                   "in `%" PATH_FMT "'\n",
+                   member_name, arch_name);
+        fseek(f, -(long int)sizeof_COFF_import_Header, SEEK_CUR);
         return false;
     }
 
-    if (hdr.Sig1 != 0x0 || hdr.Sig2 != IMPORT_OBJECT_HDR_SIG2) {
+    if (   hdr.Sig1 != IMAGE_FILE_MACHINE_UNKNOWN
+        || hdr.Sig2 != IMPORT_OBJECT_HDR_SIG2
+        || getObjectType ((char*)&hdr, arch_name) != COFF_IMPORT_LIB) {
         fseek(f, -(long int)sizeof_COFF_import_Header, SEEK_CUR);
         IF_DEBUG(linker, debugBelch("loadArchive: Object `%s` is not an import lib. Skipping...\n", member_name));
         return false;
@@ -561,6 +841,8 @@ bool checkAndLoadImportLibrary( pathchar* arch_name, char* member_name, FILE* 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);
+        fseek(f, -(n + sizeof_COFF_import_Header), SEEK_CUR);
+        return false;
     }
 
     char* symbol  = strtok(image, "\0");
@@ -744,37 +1026,39 @@ lookupSymbolInDLLs ( uint8_t *lbl )
 }
 
 static bool
-verifyCOFFHeader ( COFF_header *hdr, pathchar *fileName )
+verifyCOFFHeader ( uint16_t machine, IMAGE_FILE_HEADER *hdr,
+                   pathchar *fileName )
 {
 #if defined(i386_HOST_ARCH)
-   if (hdr->Machine != IMAGE_FILE_MACHINE_I386) {
-      errorBelch("%" PATH_FMT ": Not x86 PEi386", fileName);
+   if (machine != IMAGE_FILE_MACHINE_I386) {
+      errorBelch("%" PATH_FMT ": Not a x86 PE file.", fileName);
       return false;
    }
 #elif defined(x86_64_HOST_ARCH)
-   if (hdr->Machine != IMAGE_FILE_MACHINE_AMD64) {
-      errorBelch("%" PATH_FMT ": Not x86_64 PEi386", fileName);
+   if (machine != IMAGE_FILE_MACHINE_AMD64) {
+      errorBelch("%" PATH_FMT ": Not a x86_64 PE+ file.", fileName);
       return false;
    }
 #else
-   errorBelch("PEi386 not supported on this arch");
+   errorBelch("PE/PE+ not supported on this arch.");
 #endif
 
+   if (!hdr)
+     return true;
+
    if (hdr->SizeOfOptionalHeader != 0) {
-      errorBelch("%" PATH_FMT ": PEi386 with nonempty optional header",
+      errorBelch("%" PATH_FMT ": PE/PE+ with nonempty optional header",
                  fileName);
       return 0;
    }
-   if ( /* (hdr->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) || */
-        (hdr->Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) ||
+   if ( (hdr->Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) ||
         (hdr->Characteristics & IMAGE_FILE_DLL             ) ||
         (hdr->Characteristics & IMAGE_FILE_SYSTEM          ) ) {
-      errorBelch("%" PATH_FMT ": Not a PEi386 object file", fileName);
+      errorBelch("%" PATH_FMT ": Not a PE/PE+ object file", fileName);
       return false;
    }
-   if ( (hdr->Characteristics & IMAGE_FILE_BYTES_REVERSED_HI)
-        /* || !(hdr->Characteristics & IMAGE_FILE_32BIT_MACHINE) */ ) {
-      errorBelch("%" PATH_FMT ": Invalid PEi386 word size or endiannness: %d",
+   if ( (hdr->Characteristics & IMAGE_FILE_BYTES_REVERSED_HI)) {
+      errorBelch("%" PATH_FMT ": Invalid PE/PE+ word size or endiannness: %d",
                  fileName,
                  (int)(hdr->Characteristics));
       return false;
@@ -785,28 +1069,24 @@ verifyCOFFHeader ( COFF_header *hdr, pathchar *fileName )
 bool
 ocVerifyImage_PEi386 ( ObjectCode* oc )
 {
-   int i;
+   unsigned int i;
    uint32_t j, noRelocs;
-   COFF_header*  hdr;
    COFF_section* sectab;
    COFF_symbol*  symtab;
-   uint8_t*        strtab;
-   /* debugBelch("\nLOADING %s\n", oc->fileName); */
-   hdr = (COFF_header*)(oc->image);
+   uint8_t*      strtab;
+
+   COFF_HEADER_INFO *info = getHeaderInfo (oc);
+
    sectab = (COFF_section*) (
                ((uint8_t*)(oc->image))
-               + sizeof_COFF_header + hdr->SizeOfOptionalHeader
+               + info->sizeOfHeader + info->sizeOfOptionalHeader
             );
    symtab = (COFF_symbol*) (
                ((uint8_t*)(oc->image))
-               + hdr->PointerToSymbolTable
+               + info->pointerToSymbolTable
             );
    strtab = ((uint8_t*)symtab)
-            + hdr->NumberOfSymbols * sizeof_COFF_symbol;
-
-   if (!verifyCOFFHeader(hdr, oc->fileName)) {
-       return false;
-   }
+            + info->numberOfSymbols * getSymbolSize (info);
 
    /* If the string table size is way crazy, this might indicate that
       there are more than 64k relocations, despite claims to the
@@ -827,13 +1107,13 @@ ocVerifyImage_PEi386 ( ObjectCode* oc )
    Section *sections;
    sections = (Section*)stgCallocBytes(
        sizeof(Section),
-       hdr->NumberOfSections + 1, /* +1 for the global BSS section see ocGetNames_PEi386 */
+       info->numberOfSections + 1, /* +1 for the global BSS section see ocGetNames_PEi386 */
        "ocVerifyImage_PEi386(sections)");
    oc->sections = sections;
-   oc->n_sections = hdr->NumberOfSections + 1;
+   oc->n_sections = info->numberOfSections + 1;
 
    /* Initialize the Sections */
-   for (i = 0; i < hdr->NumberOfSections; i++) {
+   for (i = 0; i < info->numberOfSections; i++) {
        COFF_section* sectab_i
            = (COFF_section*)
            myindex(sizeof_COFF_section, sectab, i);
@@ -845,27 +1125,64 @@ ocVerifyImage_PEi386 ( ObjectCode* oc )
    /* No further verification after this point; only debug printing. */
    i = 0;
    IF_DEBUG(linker, i=1);
-   if (i == 0) return true;
+   if (i == 0)
+    {
+      stgFree (info);
+      return true;
+    }
 
    debugBelch("sectab offset = %" FMT_SizeT "\n",
-              ((uint8_t*)sectab) - ((uint8_t*)hdr) );
+              ((uint8_t*)sectab) - ((uint8_t*)oc->image) );
    debugBelch("symtab offset = %" FMT_SizeT "\n",
-              ((uint8_t*)symtab) - ((uint8_t*)hdr) );
+              ((uint8_t*)symtab) - ((uint8_t*)oc->image) );
    debugBelch("strtab offset = %" FMT_SizeT "\n",
-              ((uint8_t*)strtab) - ((uint8_t*)hdr) );
+              ((uint8_t*)strtab) - ((uint8_t*)oc->image) );
 
    debugBelch("\n" );
-   debugBelch( "Machine:           0x%x\n", (uint32_t)(hdr->Machine) );
-   debugBelch( "# sections:        %d\n",   (uint32_t)(hdr->NumberOfSections) );
-   debugBelch( "time/date:         0x%x\n", (uint32_t)(hdr->TimeDateStamp) );
-   debugBelch( "symtab offset:     %d\n",   (uint32_t)(hdr->PointerToSymbolTable) );
-   debugBelch( "# symbols:         %d\n",   (uint32_t)(hdr->NumberOfSymbols) );
-   debugBelch( "sz of opt hdr:     %d\n",   (uint32_t)(hdr->SizeOfOptionalHeader) );
-   debugBelch( "characteristics:   0x%x\n", (uint32_t)(hdr->Characteristics) );
+   if (info->type == COFF_IMAGE)
+    {
+      IMAGE_FILE_HEADER* hdr = (IMAGE_FILE_HEADER*)oc->image;
+      debugBelch( "COFF Type:         IMAGE_FILE_HEADER\n");
+      debugBelch( "Machine:           0x%x\n",
+                  (uint32_t)(hdr->Machine) );
+      debugBelch( "# sections:        %d\n",
+                  (uint32_t)(hdr->NumberOfSections) );
+      debugBelch( "time/date:         0x%x\n",
+                  (uint32_t)(hdr->TimeDateStamp) );
+      debugBelch( "symtab offset:     %d\n",
+                  (uint32_t)(hdr->PointerToSymbolTable) );
+      debugBelch( "# symbols:         %d\n",
+                  (uint32_t)(hdr->NumberOfSymbols) );
+      debugBelch( "sz of opt hdr:     %d\n",
+                  (uint32_t)(hdr->SizeOfOptionalHeader) );
+      debugBelch( "characteristics:   0x%x\n",
+                  (uint32_t)(hdr->Characteristics) );
+    }
+   else if (info->type == COFF_ANON_BIG_OBJ)
+    {
+      ANON_OBJECT_HEADER_BIGOBJ* hdr = (ANON_OBJECT_HEADER_BIGOBJ*)oc->image;
+      debugBelch( "COFF Type:         ANON_OBJECT_HEADER_BIGOBJ\n");
+      debugBelch( "Machine:           0x%x\n",
+                  (uint32_t)(hdr->Machine) );
+      debugBelch( "# sections:        %d\n",
+                  (uint32_t)(hdr->NumberOfSections) );
+      debugBelch( "time/date:         0x%x\n",
+                  (uint32_t)(hdr->TimeDateStamp) );
+      debugBelch( "symtab offset:     %d\n",
+                  (uint32_t)(hdr->PointerToSymbolTable) );
+      debugBelch( "# symbols:         %d\n",
+                  (uint32_t)(hdr->NumberOfSymbols) );
+    }
+   else
+    {
+      debugBelch( "COFF Type:         UNKNOWN\n");
+      stgFree (info);
+      return false;
+    }
 
    /* Print the section table. */
    debugBelch("\n" );
-   for (i = 0; i < hdr->NumberOfSections; i++) {
+   for (i = 0; i < info->numberOfSections; i++) {
       COFF_reloc* reltab;
       COFF_section* sectab_i
          = (COFF_section*)
@@ -923,8 +1240,8 @@ ocVerifyImage_PEi386 ( ObjectCode* oc )
                    (uint32_t)rel->Type,
                    rel->VirtualAddress );
          sym = (COFF_symbol*)
-               myindex ( sizeof_COFF_symbol, symtab, rel->SymbolTableIndex );
-         printName ( sym->N.ShortName, strtab );
+               myindex ( getSymbolSize (info), symtab, rel->SymbolTableIndex );
+         printName ( getSymShortName (info, sym), strtab );
          debugBelch("'\n" );
       }
 
@@ -933,7 +1250,7 @@ ocVerifyImage_PEi386 ( ObjectCode* oc )
    debugBelch("\n" );
    debugBelch("string table has size 0x%x\n", * (uint32_t*)strtab );
    debugBelch("---START of string table---\n");
-   for (i = 4; i < *(int32_t*)strtab; i++) {
+   for (i = 4; i < *(uint32_t*)strtab; i++) {
       if (strtab[i] == 0)
          debugBelch("\n"); else
          debugBelch("%c", strtab[i] );
@@ -944,40 +1261,40 @@ ocVerifyImage_PEi386 ( ObjectCode* oc )
    i = 0;
    while (1) {
       COFF_symbol* symtab_i;
-      if (i >= (int32_t)(hdr->NumberOfSymbols)) break;
+      if (i >= info->numberOfSymbols) break;
       symtab_i = (COFF_symbol*)
-                 myindex ( sizeof_COFF_symbol, symtab, i );
+                 myindex ( getSymbolSize (info), symtab, i );
       debugBelch(
                 "symbol %d\n"
                 "     name `",
                 i
               );
-      printName ( symtab_i->N.ShortName, strtab );
+      printName ( getSymShortName (info, symtab_i), strtab );
       debugBelch(
                 "'\n"
-                "    value 0x%lx\n"
+                "    value 0x%x\n"
                 "   1+sec# %d\n"
                 "     type 0x%x\n"
                 "   sclass 0x%x\n"
                 "     nAux %d\n",
-                symtab_i->Value,
-                (int32_t)(symtab_i->SectionNumber),
-                (uint32_t)symtab_i->Type,
-                (uint32_t)symtab_i->StorageClass,
-                (uint32_t)symtab_i->NumberOfAuxSymbols
+                getSymValue (info, symtab_i),
+                getSymSectionNumber (info, symtab_i),
+                getSymType (info, symtab_i),
+                getSymStorageClass (info, symtab_i),
+                getSymNumberOfAuxSymbols (info, symtab_i)
               );
-      i += symtab_i->NumberOfAuxSymbols;
+      i += getSymNumberOfAuxSymbols (info, symtab_i);
       i++;
    }
 
    debugBelch("\n" );
+   stgFree (info);
    return true;
 }
 
 bool
 ocGetNames_PEi386 ( ObjectCode* oc )
 {
-   COFF_header*  hdr;
    COFF_section* sectab;
    COFF_symbol*  symtab;
    uint8_t*        strtab;
@@ -985,24 +1302,25 @@ ocGetNames_PEi386 ( ObjectCode* oc )
 
    uint8_t*     sname;
    SymbolAddr* addr;
-   int        i;
+   unsigned int   i;
+
+   COFF_HEADER_INFO *info = getHeaderInfo (oc);
 
-   hdr = (COFF_header*)(oc->image);
    sectab = (COFF_section*) (
                ((uint8_t*)(oc->image))
-               + sizeof_COFF_header + hdr->SizeOfOptionalHeader
+               + info->sizeOfHeader + info->sizeOfOptionalHeader
             );
    symtab = (COFF_symbol*) (
                ((uint8_t*)(oc->image))
-               + hdr->PointerToSymbolTable
+               + info->pointerToSymbolTable
             );
    strtab = ((uint8_t*)(oc->image))
-            + hdr->PointerToSymbolTable
-            + hdr->NumberOfSymbols * sizeof_COFF_symbol;
+            + info->pointerToSymbolTable
+            + info->numberOfSymbols * getSymbolSize (info);
 
    /* Allocate space for any (local, anonymous) .bss sections. */
 
-   for (i = 0; i < hdr->NumberOfSections; i++) {
+   for (i = 0; i < info->numberOfSections; i++) {
       uint32_t bss_sz;
       uint8_t* zspace;
       COFF_section* sectab_i
@@ -1047,7 +1365,7 @@ ocGetNames_PEi386 ( ObjectCode* oc )
 
    /* Copy section information into the ObjectCode. */
 
-   for (i = 0; i < hdr->NumberOfSections; i++) {
+   for (i = 0; i < info->numberOfSections; i++) {
       uint8_t* start;
       uint8_t* end;
       uint32_t sz;
@@ -1099,9 +1417,10 @@ ocGetNames_PEi386 ( ObjectCode* oc )
              of DLLs.  */
           sname = ((uint8_t*)section.start)+2;
           COFF_symbol* symtab_i = (COFF_symbol*)
-                myindex ( sizeof_COFF_symbol, symtab, hdr->NumberOfSymbols-1 );
-          addr = (char*)cstring_from_COFF_symbol_name(symtab_i->N.ShortName,
-                                                      strtab);
+                myindex ( getSymbolSize(info), symtab, info->numberOfSymbols-1 );
+          addr = (char*)cstring_from_COFF_symbol_name(
+                               getSymShortName (info, symtab_i),
+                               strtab);
 
           IF_DEBUG(linker,
                    debugBelch("addImportSymbol `%s' => `%s'\n",
@@ -1134,24 +1453,26 @@ ocGetNames_PEi386 ( ObjectCode* oc )
 
    /* Copy exported symbols into the ObjectCode. */
 
-   oc->n_symbols = hdr->NumberOfSymbols;
+   oc->n_symbols = info->numberOfSymbols;
    oc->symbols   = stgCallocBytes(sizeof(SymbolName*), oc->n_symbols,
                                   "ocGetNames_PEi386(oc->symbols)");
 
    /* Work out the size of the global BSS section */
    StgWord globalBssSize = 0;
-   for (i=0; i < (int)hdr->NumberOfSymbols; i++) {
+   for (i=0; i < info->numberOfSymbols; i++) {
       COFF_symbol* symtab_i;
        symtab_i = (COFF_symbol*)
-           myindex ( sizeof_COFF_symbol, symtab, i );
-       if (symtab_i->SectionNumber == IMAGE_SYM_UNDEFINED
-           && symtab_i->Value > 0
-           && symtab_i->StorageClass != IMAGE_SYM_CLASS_SECTION) {
-           globalBssSize += symtab_i->Value;
+           myindex ( getSymbolSize (info), symtab, i );
+       if (getSymSectionNumber (info, symtab_i) == IMAGE_SYM_UNDEFINED
+           && getSymValue (info, symtab_i) > 0
+           && getSymStorageClass (info, symtab_i) != IMAGE_SYM_CLASS_SECTION) {
+           globalBssSize += getSymValue (info, symtab_i);
        }
-       i += symtab_i->NumberOfAuxSymbols;
+       i += getSymNumberOfAuxSymbols (info, symtab_i);
    }
 
+   stgFree (info);
+
    /* Allocate BSS space */
    SymbolAddr* bss = NULL;
    if (globalBssSize > 0) {
@@ -1167,20 +1488,24 @@ ocGetNames_PEi386 ( ObjectCode* oc )
                   SECTIONKIND_OTHER, SECTION_NOMEM, NULL, 0, 0, 0, 0);
    }
 
-   for (i = 0; i < oc->n_symbols; i++) {
+   for (i = 0; i < (uint32_t)oc->n_symbols; i++) {
       COFF_symbol* symtab_i;
       symtab_i = (COFF_symbol*)
-                 myindex ( sizeof_COFF_symbol, symtab, i );
+                 myindex ( getSymbolSize (info), symtab, i );
+
+      int32_t secNumber = getSymSectionNumber (info, symtab_i);
+      uint32_t symValue = getSymValue (info, symtab_i);
+      uint8_t symStorageClass = getSymStorageClass (info, symtab_i);
 
       addr = NULL;
       bool isWeak = false;
-      Section *section = symtab_i->SectionNumber > 0
-                       ? &oc->sections[symtab_i->SectionNumber-1]
+      Section *section = secNumber > 0
+                       ? &oc->sections[secNumber-1]
                        : NULL;
-      sname = cstring_from_COFF_symbol_name(symtab_i->N.ShortName, strtab);
+      sname = cstring_from_COFF_symbol_name(getSymShortName (info, symtab_i), strtab);
 
-      if (   symtab_i->SectionNumber != IMAGE_SYM_UNDEFINED
-          && symtab_i->SectionNumber > 0
+      if (   secNumber != IMAGE_SYM_UNDEFINED
+          && secNumber > 0
           && section
           && section->kind != SECTIONKIND_IMPORT_LIBRARY) {
          /* This symbol is global and defined, viz, exported */
@@ -1191,32 +1516,30 @@ ocGetNames_PEi386 ( ObjectCode* oc )
          */
          COFF_section* sectabent
             = (COFF_section*) myindex ( sizeof_COFF_section,
-                                        sectab,
-                                        symtab_i->SectionNumber-1 );
-         if (symtab_i->StorageClass == IMAGE_SYM_CLASS_EXTERNAL
-            || (   symtab_i->StorageClass == IMAGE_SYM_CLASS_STATIC
+                                        sectab, secNumber-1 );
+         if (symStorageClass == IMAGE_SYM_CLASS_EXTERNAL
+            || (   symStorageClass == IMAGE_SYM_CLASS_STATIC
                 && sectabent->Characteristics & IMAGE_SCN_LNK_COMDAT
                 && section)
             ) {
                  addr = (void*)((size_t)section->start
-                      + symtab_i->Value);
+                      + symValue);
                  if (sectabent->Characteristics & IMAGE_SCN_LNK_COMDAT) {
                     isWeak = true;
               }
          }
       }
-      else if (symtab_i->StorageClass == IMAGE_SYM_CLASS_WEAK_EXTERNAL) {
+      else if (symStorageClass == IMAGE_SYM_CLASS_WEAK_EXTERNAL) {
           isWeak = true;
       }
-      else if (  symtab_i->SectionNumber == IMAGE_SYM_UNDEFINED
-              && symtab_i->Value > 0) {
+      else if (  secNumber == IMAGE_SYM_UNDEFINED && symValue > 0) {
          /* This symbol isn't in any section at all, ie, global bss.
             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 %lu\n", addr, symtab_i->Value));
+          bss = (SymbolAddr*)((StgWord)bss + (StgWord)symValue);
+          IF_DEBUG(linker, debugBelch("bss symbol @ %p %u\n", addr, symValue));
       }
-      else if (symtab_i->SectionNumber > 0
+      else if (secNumber > 0
                && section
                && section->kind == SECTIONKIND_IMPORT_LIBRARY) {
           /* This is an import section. We should load the dll and lookup
@@ -1231,8 +1554,8 @@ ocGetNames_PEi386 ( ObjectCode* oc )
           stgFree(dirName);
 
           symtab_i = (COFF_symbol*)
-                 myindex ( sizeof_COFF_symbol, symtab, oc->n_symbols-1 );
-          sname = cstring_from_COFF_symbol_name(symtab_i->N.ShortName, strtab);
+                 myindex ( getSymbolSize (info), symtab, oc->n_symbols-1 );
+          sname = cstring_from_COFF_symbol_name(getSymShortName (info, symtab_i), strtab);
 
           IF_DEBUG(linker,
                    debugBelch("loading symbol `%s' from dll: '%ls' => `%s'\n",
@@ -1285,7 +1608,7 @@ ocGetNames_PEi386 ( ObjectCode* oc )
          && (!section || (section && section->kind != SECTIONKIND_IMPORT))) {
          /* 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);
+         ASSERT(i < (uint32_t)oc->n_symbols);
          /* cstring_from_COFF_symbol_name always succeeds. */
          oc->symbols[i] = (SymbolName*)sname;
          if (isWeak) {
@@ -1307,7 +1630,7 @@ ocGetNames_PEi386 ( ObjectCode* oc )
                    "     name `",
                    i
                  );
-         printName ( symtab_i->N.ShortName, strtab );
+         printName ( getSymShortName (info, symtab_i), strtab );
          debugBelch(
                    "'\n"
                    "    value 0x%x\n"
@@ -1315,16 +1638,16 @@ ocGetNames_PEi386 ( ObjectCode* oc )
                    "     type 0x%x\n"
                    "   sclass 0x%x\n"
                    "     nAux %d\n",
-                   symtab_i->Value,
-                   (int32_t)(symtab_i->SectionNumber),
-                   (uint32_t)symtab_i->Type,
-                   (uint32_t)symtab_i->StorageClass,
-                   (uint32_t)symtab_i->NumberOfAuxSymbols
+                   symValue,
+                   getSymSectionNumber (info, symtab_i),
+                   getSymType (info, symtab_i),
+                   getSymStorageClass (info, symtab_i),
+                   getSymNumberOfAuxSymbols (info, symtab_i)
                  );
 #        endif
       }
 
-      i += symtab_i->NumberOfAuxSymbols;
+      i += getSymNumberOfAuxSymbols (info, symtab_i);
    }
 
    return true;
@@ -1341,7 +1664,9 @@ ocAllocateSymbolExtras_PEi386 ( ObjectCode* oc )
    oc->symbol_extras = (SymbolExtra*)(oc->image - PEi386_IMAGE_OFFSET
                                       + ((PEi386_IMAGE_OFFSET + oc->fileSize + 0x7) & ~0x7));
    oc->first_symbol_extra = 0;
-   oc->n_symbol_extras = ((COFF_header*)oc->image)->NumberOfSymbols;
+   COFF_HEADER_INFO *info = getHeaderInfo (oc);
+   oc->n_symbol_extras = info->numberOfSymbols;
+   stgFree (info);
 
    return true;
 }
@@ -1375,7 +1700,6 @@ makeSymbolExtra_PEi386( ObjectCode* oc, uint64_t index, size_t s, char* symbol )
 bool
 ocResolve_PEi386 ( ObjectCode* oc )
 {
-   COFF_header*  hdr;
    COFF_section* sectab;
    COFF_symbol*  symtab;
    uint8_t*      strtab;
@@ -1384,7 +1708,7 @@ ocResolve_PEi386 ( ObjectCode* oc )
    size_t      S;
    SymbolAddr* pP;
 
-   int i;
+   unsigned int i;
    uint32_t j, noRelocs;
 
    /* ToDo: should be variable-sized?  But is at least safe in the
@@ -1392,20 +1716,23 @@ ocResolve_PEi386 ( ObjectCode* oc )
    uint8_t symbol[1000];
    /* debugBelch("resolving for %s\n", oc->fileName); */
 
-   hdr = (COFF_header*)(oc->image);
+   COFF_HEADER_INFO *info = getHeaderInfo (oc);
+
    sectab = (COFF_section*) (
                ((uint8_t*)(oc->image))
-               + sizeof_COFF_header + hdr->SizeOfOptionalHeader
+               + info->sizeOfHeader + info->sizeOfOptionalHeader
             );
    symtab = (COFF_symbol*) (
                ((uint8_t*)(oc->image))
-               + hdr->PointerToSymbolTable
+               + info->pointerToSymbolTable
             );
    strtab = ((uint8_t*)(oc->image))
-            + hdr->PointerToSymbolTable
-            + hdr->NumberOfSymbols * sizeof_COFF_symbol;
+            + info->pointerToSymbolTable
+            + info->numberOfSymbols * getSymbolSize (info);
+
+   uint32_t numberOfSections = info->numberOfSections;
 
-   for (i = 0; i < hdr->NumberOfSections; i++) {
+   for (i = 0; i < numberOfSections; i++) {
       COFF_section* sectab_i
          = (COFF_section*)
            myindex ( sizeof_COFF_section, sectab, i );
@@ -1474,12 +1801,12 @@ ocResolve_PEi386 ( ObjectCode* oc )
          A = *(uint32_t*)pP;
          /* the symbol to connect to */
          sym = (COFF_symbol*)
-               myindex ( sizeof_COFF_symbol,
+               myindex ( getSymbolSize (info),
                          symtab, reltab_j->SymbolTableIndex );
 #if defined(x86_64_HOST_ARCH)
-         uint64_t symIndex = ((uint64_t)myindex(sizeof_COFF_symbol, symtab,
+         uint64_t symIndex = ((uint64_t)myindex(getSymbolSize (info), symtab,
                                                 reltab_j->SymbolTableIndex)
-                                        - (uint64_t)symtab) / sizeof_COFF_symbol;
+                                        - (uint64_t)symtab) / getSymbolSize (info);
 #endif
 
          IF_DEBUG(linker,
@@ -1489,18 +1816,19 @@ ocResolve_PEi386 ( ObjectCode* oc )
                             i, j,
                             (uint32_t)reltab_j->Type,
                             reltab_j->VirtualAddress );
-                            printName ( sym->N.ShortName, strtab );
+                            printName ( getSymShortName (info, sym), strtab );
                             debugBelch("'\n" ));
 
-         if (sym->StorageClass == IMAGE_SYM_CLASS_STATIC) {
-            Section section = oc->sections[sym->SectionNumber-1];
+         if (getSymStorageClass (info, sym) == IMAGE_SYM_CLASS_STATIC) {
+            Section section = oc->sections[getSymSectionNumber (info, sym)-1];
             S = ((size_t)(section.start))
-              + ((size_t)(sym->Value));
+              + ((size_t)(getSymValue (info, sym)));
          } else {
-            copyName ( sym->N.ShortName, strtab, symbol, 1000-1 );
+            copyName ( getSymShortName (info, sym), strtab, symbol, 1000-1 );
             S = (size_t) lookupSymbol_( (char*)symbol );
             if ((void*)S == NULL) {
                 errorBelch(" | %" PATH_FMT ": unknown symbol `%s'", oc->fileName, symbol);
+                stgFree (info);
                 return false;
             }
          }
@@ -1556,7 +1884,7 @@ ocResolve_PEi386 ( ObjectCode* oc )
                    size_t v;
                    v = S + ((size_t)A);
                    if (v >> 32) {
-                       copyName ( sym->N.ShortName, strtab, symbol, 1000-1 );
+                       copyName ( getSymShortName (info, sym), strtab, symbol, 1000-1 );
                        S = makeSymbolExtra_PEi386(oc, symIndex, S, (char *)symbol);
                        /* And retry */
                        v = S + ((size_t)A);
@@ -1574,7 +1902,7 @@ ocResolve_PEi386 ( ObjectCode* oc )
                    v = ((intptr_t)S) + ((intptr_t)(int32_t)A) - ((intptr_t)pP) - 4;
                    if ((v >> 32) && ((-v) >> 32)) {
                        /* Make the trampoline then */
-                       copyName ( sym->N.ShortName, strtab, symbol, 1000-1 );
+                       copyName ( getSymShortName (info, sym), strtab, symbol, 1000-1 );
                        S = makeSymbolExtra_PEi386(oc, symIndex, S, (char *)symbol);
                        /* And retry */
                        v = ((intptr_t)S) + ((intptr_t)(int32_t)A) - ((intptr_t)pP) - 4;
@@ -1590,12 +1918,14 @@ ocResolve_PEi386 ( ObjectCode* oc )
             default:
                debugBelch("%" PATH_FMT ": unhandled PEi386 relocation type %d\n",
                      oc->fileName, reltab_j->Type);
+               stgFree (info);
                return false;
          }
 
       }
    }
 
+   stgFree (info);
    IF_DEBUG(linker, debugBelch("completed %" PATH_FMT "\n", oc->fileName));
    return true;
 }
@@ -1618,19 +1948,18 @@ ocResolve_PEi386 ( ObjectCode* oc )
 bool
 ocRunInit_PEi386 ( ObjectCode *oc )
 {
-    COFF_header*  hdr;
     COFF_section* sectab;
     uint8_t*        strtab;
-    int i;
+    unsigned int i;
 
-    hdr = (COFF_header*)(oc->image);
+    COFF_HEADER_INFO *info = getHeaderInfo (oc);
     sectab = (COFF_section*) (
                 ((uint8_t*)(oc->image))
-                + sizeof_COFF_header + hdr->SizeOfOptionalHeader
+                + info->sizeOfHeader + info->sizeOfOptionalHeader
              );
     strtab = ((uint8_t*)(oc->image))
-             + hdr->PointerToSymbolTable
-             + hdr->NumberOfSymbols * sizeof_COFF_symbol;
+             + info->pointerToSymbolTable
+             + info->numberOfSymbols * getSymbolSize (info);
 
     int argc, envc;
     char **argv, **envv;
@@ -1644,7 +1973,7 @@ ocRunInit_PEi386 ( ObjectCode *oc )
 
        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++) {
+    for (i = 0; i < info->numberOfSections; i++) {
         COFF_section* sectab_i
             = (COFF_section*)
                 myindex ( sizeof_COFF_section, sectab, i );
@@ -1661,6 +1990,7 @@ ocRunInit_PEi386 ( ObjectCode *oc )
             }
         }
     }
+    stgFree (info);
     freeProgEnvv(envc, envv);
     return true;
 }
index 44f280f..e84e052 100644 (file)
 #define PEi386_IMAGE_OFFSET 0
 #endif
 
+/********************************************
+ * COFF/PE types
+ ********************************************/
+
+typedef enum _COFF_OBJ_TYPE {
+    COFF_IMAGE,
+    COFF_ANON_OBJ,
+    COFF_IMPORT_LIB,
+    COFF_ANON_BIG_OBJ,
+    COFF_UNKNOWN
+} COFF_OBJ_TYPE;
+
+typedef struct _COFF_HEADER_INFO {
+   COFF_OBJ_TYPE type;
+   uint16_t sizeOfOptionalHeader;
+   uint16_t sizeOfHeader;
+   uint32_t pointerToSymbolTable;
+   uint32_t numberOfSymbols;
+   uint32_t numberOfSections;
+} COFF_HEADER_INFO;
+
+/********************************************
+ * COFF/PE prototypes
+ ********************************************/
+
 void initLinker_PEi386( void );
 const char * addDLL_PEi386( pathchar *dll_name, HINSTANCE *instance  );
 void freePreloadObjectFile_PEi386( ObjectCode *oc );
@@ -43,9 +68,6 @@ allocateImageAndTrampolines (
 /********************************************
  * COFF/PE headers
  ********************************************/
-typedef IMAGE_FILE_HEADER COFF_header;
-#define sizeof_COFF_header sizeof(COFF_header)
-
 /* Section 7.1 PE Specification */
 typedef IMPORT_OBJECT_HEADER COFF_import_header;
 #define sizeof_COFF_import_Header sizeof(COFF_import_header)
@@ -54,9 +76,11 @@ typedef IMAGE_SECTION_HEADER COFF_section;
 #define sizeof_COFF_section sizeof(COFF_section)
 
 
-typedef IMAGE_SYMBOL COFF_symbol;
-#define sizeof_COFF_symbol sizeof(COFF_symbol)
+typedef IMAGE_SYMBOL COFF_symbol_og;
+#define sizeof_COFF_symbol_og sizeof(COFF_symbol_og)
 
+typedef IMAGE_SYMBOL_EX COFF_symbol_ex;
+#define sizeof_COFF_symbol_ex sizeof(COFF_symbol_ex)
 
 typedef IMAGE_RELOCATION COFF_reloc;
 #define sizeof_COFF_reloc sizeof(COFF_reloc)
@@ -65,6 +89,13 @@ typedef IMAGE_RELOCATION COFF_reloc;
 typedef DLL_DIRECTORY_COOKIE(WINAPI *LPAddDLLDirectory)(PCWSTR NewDirectory);
 typedef WINBOOL(WINAPI *LPRemoveDLLDirectory)(DLL_DIRECTORY_COOKIE Cookie);
 
+/* Combine union of possible symbol types.  */
+typedef
+union _COFF_symbol {
+    COFF_symbol_og og;
+    COFF_symbol_ex ex;
+} COFF_symbol;
+
 /* A record for storing handles into DLLs. */
 typedef
 struct _OpenedDLL {
@@ -80,6 +111,17 @@ struct _IndirectAddr {
     struct _IndirectAddr* next;
 } IndirectAddr;
 
+/* Util symbol handling functions.  */
+COFF_OBJ_TYPE getObjectType ( char* image, pathchar* fileName );
+COFF_HEADER_INFO* getHeaderInfo ( ObjectCode* oc );
+size_t getSymbolSize ( COFF_HEADER_INFO *info );
+int32_t getSymSectionNumber ( COFF_HEADER_INFO *info, COFF_symbol* sym );
+uint32_t getSymValue ( COFF_HEADER_INFO *info, COFF_symbol* sym );
+uint8_t getSymStorageClass ( COFF_HEADER_INFO *info, COFF_symbol* sym );
+uint8_t getSymNumberOfAuxSymbols ( COFF_HEADER_INFO *info, COFF_symbol* sym );
+uint16_t getSymType ( COFF_HEADER_INFO *info, COFF_symbol* sym );
+uint8_t* getSymShortName ( COFF_HEADER_INFO *info, COFF_symbol* sym );
+
 /* See Note [mingw-w64 name decoration scheme] */
 #if !defined(x86_64_HOST_ARCH)
 #define STRIP_LEADING_UNDERSCORE 1
index 63b1690..8a62791 100644 (file)
@@ -102,3 +102,8 @@ T1407:
 .PHONY: T13606
 T13606:
        echo "main" | '$(TEST_HC)' $(TEST_HC_OPTS_INTERACTIVE) -lD3DCompiler T13606.hs
+
+.PHONY: big-obj
+big-obj:
+       '$(TEST_CC)' -c -Wa,-mbig-obj big-obj-c.c -o big-obj-c.o
+       echo "main" | '$(TEST_HC)' $(TEST_HC_OPTS_INTERACTIVE) big-obj-c.o big-obj.hs
index 5da2d61..752dc78 100644 (file)
@@ -42,3 +42,7 @@ test('T11072msvc', [extra_files(['A.c', 'T11072.hs', 'libAS.def', 'i686/', 'x86_
 test('T13606', [extra_files(['Triangle.fx']),
                     unless(doing_ghci, skip), unless(opsys('mingw32'), skip)],
      run_command, ['$MAKE -s --no-print-directory T13606'])
+
+test('big-obj', [extra_files(['big-obj-c.c', 'big-obj.hs']),
+                    unless(doing_ghci, skip), unless(opsys('mingw32'), skip)],
+     run_command, ['$MAKE -s --no-print-directory big-obj'])
diff --git a/testsuite/tests/ghci/linking/dyn/big-obj-c.c b/testsuite/tests/ghci/linking/dyn/big-obj-c.c
new file mode 100644 (file)
index 0000000..bd82d5e
--- /dev/null
@@ -0,0 +1,4 @@
+int foo()
+{
+  return 17;
+}
diff --git a/testsuite/tests/ghci/linking/dyn/big-obj.hs b/testsuite/tests/ghci/linking/dyn/big-obj.hs
new file mode 100644 (file)
index 0000000..386f728
--- /dev/null
@@ -0,0 +1,3 @@
+foreign import ccall "foo" c_foo :: IO Int
+
+main = c_foo >>= print
diff --git a/testsuite/tests/ghci/linking/dyn/big-obj.stdout b/testsuite/tests/ghci/linking/dyn/big-obj.stdout
new file mode 100644 (file)
index 0000000..98d9bcb
--- /dev/null
@@ -0,0 +1 @@
+17