Fix ExtraSymbols jump table on Windows.
authorTamar Christina <tamar@zhox.com>
Tue, 14 Feb 2017 14:44:53 +0000 (09:44 -0500)
committerBen Gamari <ben@smart-cactus.org>
Tue, 14 Feb 2017 15:53:01 +0000 (10:53 -0500)
This corrects the `jump islands` calculations for Windows.  The code was
incorrectly creating a new entry for every `usage` of a symbol instead
of every used symbol. e.g. if a symbol is used 5 times it used to create
5 jump islands. This is incorrect and not in line with what the `ELF`
and `Mach-O` linkers do. Also since we allocate `n` spaces where `n` is
number of symbols, we would quickly run out of space and abort.

Test Plan: ./validate

Reviewers: simonmar, hvr, erikd, bgamari, austin

Reviewed By: bgamari

Subscribers: thomie, #ghc_windows_task_force

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

rts/linker/PEi386.c

index bfac34f..b62f1eb 100644 (file)
@@ -73,6 +73,7 @@ static uint8_t* cstring_from_COFF_symbol_name(
 #if defined(x86_64_HOST_ARCH)
 static size_t makeSymbolExtra_PEi386(
     ObjectCode* oc,
+    uint64_t index,
     size_t s,
     SymbolName* symbol);
 #endif
@@ -346,7 +347,7 @@ bool removeLibrarySearchPath_PEi386(HsPtr dll_path_index)
         }
     }
 
-    return result == 0;
+    return !result;
 }
 
 
@@ -869,8 +870,7 @@ ocVerifyImage_PEi386 ( ObjectCode* oc )
                    rel->VirtualAddress );
          sym = (COFF_symbol*)
                myindex ( sizeof_COFF_symbol, symtab, rel->SymbolTableIndex );
-         /* Hmm..mysterious looking offset - what's it for? SOF */
-         printName ( sym->N.ShortName, strtab -10 );
+         printName ( sym->N.ShortName, strtab );
          debugBelch("'\n" );
       }
 
@@ -1185,24 +1185,25 @@ ocAllocateSymbolExtras_PEi386 ( ObjectCode* oc )
 }
 
 static size_t
-makeSymbolExtra_PEi386( ObjectCode* oc, size_t s, char* symbol )
+makeSymbolExtra_PEi386( ObjectCode* oc, uint64_t index, size_t s, char* symbol )
 {
     unsigned int curr_thunk;
     SymbolExtra *extra;
-
-    curr_thunk = oc->first_symbol_extra;
-    if (curr_thunk >= oc->n_symbol_extras) {
-      barf("Can't allocate thunk for %s", symbol);
+    curr_thunk = oc->first_symbol_extra + index;
+    if (index >= oc->n_symbol_extras) {
+      IF_DEBUG(linker, debugBelch("makeSymbolExtra first:%d, num:%lu, member:%s, index:%llu\n", curr_thunk, oc->n_symbol_extras, oc->archiveMemberName, index));
+      barf("Can't allocate thunk for `%s' in `%" PATH_FMT "' with member `%s'", symbol, oc->fileName, oc->archiveMemberName);
     }
 
     extra = oc->symbol_extras + curr_thunk;
 
-    // jmp *-14(%rip)
-    static uint8_t jmp[] = { 0xFF, 0x25, 0xF2, 0xFF, 0xFF, 0xFF };
-    extra->addr = (uint64_t)s;
-    memcpy(extra->jumpIsland, jmp, 6);
-
-    oc->first_symbol_extra++;
+    if (!extra->addr)
+    {
+        // jmp *-14(%rip)
+        static uint8_t jmp[] = { 0xFF, 0x25, 0xF2, 0xFF, 0xFF, 0xFF };
+        extra->addr = (uint64_t)s;
+        memcpy(extra->jumpIsland, jmp, 6);
+    }
 
     return (size_t)extra->jumpIsland;
 }
@@ -1313,6 +1314,10 @@ ocResolve_PEi386 ( ObjectCode* oc )
          sym = (COFF_symbol*)
                myindex ( sizeof_COFF_symbol,
                          symtab, reltab_j->SymbolTableIndex );
+         uint64_t symIndex = ((uint64_t)myindex(sizeof_COFF_symbol, symtab,
+                                                reltab_j->SymbolTableIndex)
+                                        - (uint64_t)symtab) / sizeof_COFF_symbol;
+
          IF_DEBUG(linker,
                   debugBelch(
                             "reloc sec %2d num %3d:  type 0x%-4x   "
@@ -1389,7 +1394,7 @@ ocResolve_PEi386 ( ObjectCode* oc )
                    v = S + ((size_t)A);
                    if (v >> 32) {
                        copyName ( sym->N.ShortName, strtab, symbol, 1000-1 );
-                       S = makeSymbolExtra_PEi386(oc, S, (char *)symbol);
+                       S = makeSymbolExtra_PEi386(oc, symIndex, S, (char *)symbol);
                        /* And retry */
                        v = S + ((size_t)A);
                        if (v >> 32) {
@@ -1407,7 +1412,7 @@ ocResolve_PEi386 ( ObjectCode* oc )
                    if ((v >> 32) && ((-v) >> 32)) {
                        /* Make the trampoline then */
                        copyName ( sym->N.ShortName, strtab, symbol, 1000-1 );
-                       S = makeSymbolExtra_PEi386(oc, S, (char *)symbol);
+                       S = makeSymbolExtra_PEi386(oc, symIndex, S, (char *)symbol);
                        /* And retry */
                        v = ((intptr_t)S) + ((intptr_t)(int32_t)A) - ((intptr_t)pP) - 4;
                        if ((v >> 32) && ((-v) >> 32)) {