Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC

Commits:

15 changed files:

Changes:

  • rts/Hash.c
    ... ... @@ -94,13 +94,13 @@ hashWord(const HashTable *table, StgWord key)
    94 94
     }
    
    95 95
     
    
    96 96
     int
    
    97
    -hashStr(const HashTable *table, StgWord w)
    
    97
    +hashBuffer(const HashTable *table, const void *buf, size_t len)
    
    98 98
     {
    
    99
    -    const char *key = (char*) w;
    
    99
    +    const char *key = (char*) buf;
    
    100 100
     #if WORD_SIZE_IN_BITS == 64
    
    101
    -    StgWord h = XXH3_64bits_withSeed (key, strlen(key), 1048583);
    
    101
    +    StgWord h = XXH3_64bits_withSeed (key, len, 1048583);
    
    102 102
     #else
    
    103
    -    StgWord h = XXH32 (key, strlen(key), 1048583);
    
    103
    +    StgWord h = XXH32 (key, len, 1048583);
    
    104 104
     #endif
    
    105 105
     
    
    106 106
         /* Mod the size of the hash table (a power of 2) */
    
    ... ... @@ -114,6 +114,13 @@ hashStr(const HashTable *table, StgWord w)
    114 114
         return bucket;
    
    115 115
     }
    
    116 116
     
    
    117
    +int
    
    118
    +hashStr(const HashTable *table, StgWord w)
    
    119
    +{
    
    120
    +    const char *key = (char*) w;
    
    121
    +    return hashBuffer(table, key, strlen(key));
    
    122
    +}
    
    123
    +
    
    117 124
     STATIC_INLINE int
    
    118 125
     compareWord(StgWord key1, StgWord key2)
    
    119 126
     {
    

  • rts/Hash.h
    ... ... @@ -69,6 +69,10 @@ void * removeStrHashTable ( StrHashTable *table, const char * key,
    69 69
      */
    
    70 70
     typedef int HashFunction(const HashTable *table, StgWord key);
    
    71 71
     typedef int CompareFunction(StgWord key1, StgWord key2);
    
    72
    +
    
    73
    +// Helper for implementing hash functions
    
    74
    +int hashBuffer(const HashTable *table, const void *buf, size_t len);
    
    75
    +
    
    72 76
     int hashWord(const HashTable *table, StgWord key);
    
    73 77
     int hashStr(const HashTable *table, StgWord w);
    
    74 78
     void        insertHashTable_ ( HashTable *table, StgWord key,
    
    ... ... @@ -79,6 +83,7 @@ void * removeHashTable_ ( HashTable *table, StgWord key,
    79 83
                                    const void *data, HashFunction f,
    
    80 84
                                    CompareFunction cmp );
    
    81 85
     
    
    86
    +
    
    82 87
     /* Freeing hash tables
    
    83 88
      */
    
    84 89
     void freeHashTable ( HashTable *table, void (*freeDataFun)(void *) );
    

  • rts/Linker.c
    ... ... @@ -1194,7 +1194,7 @@ void freeObjectCode (ObjectCode *oc)
    1194 1194
             stgFree(oc->sections);
    
    1195 1195
         }
    
    1196 1196
     
    
    1197
    -    freeProddableBlocks(oc);
    
    1197
    +    freeProddableBlocks(&oc->proddables);
    
    1198 1198
         freeSegments(oc);
    
    1199 1199
     
    
    1200 1200
         /* Free symbol_extras.  On x86_64 Windows, symbol_extras are allocated
    
    ... ... @@ -1279,7 +1279,7 @@ mkOc( ObjectType type, pathchar *path, char *image, int imageSize,
    1279 1279
        oc->sections          = NULL;
    
    1280 1280
        oc->n_segments        = 0;
    
    1281 1281
        oc->segments          = NULL;
    
    1282
    -   oc->proddables        = NULL;
    
    1282
    +   initProddableBlockSet(&oc->proddables);
    
    1283 1283
        oc->foreign_exports   = NULL;
    
    1284 1284
     #if defined(NEED_SYMBOL_EXTRAS)
    
    1285 1285
        oc->symbol_extras     = NULL;
    
    ... ... @@ -1834,50 +1834,6 @@ OStatus getObjectLoadStatus (pathchar *path)
    1834 1834
         return r;
    
    1835 1835
     }
    
    1836 1836
     
    
    1837
    -/* -----------------------------------------------------------------------------
    
    1838
    - * Sanity checking.  For each ObjectCode, maintain a list of address ranges
    
    1839
    - * which may be prodded during relocation, and abort if we try and write
    
    1840
    - * outside any of these.
    
    1841
    - */
    
    1842
    -void
    
    1843
    -addProddableBlock ( ObjectCode* oc, void* start, int size )
    
    1844
    -{
    
    1845
    -   ProddableBlock* pb
    
    1846
    -      = stgMallocBytes(sizeof(ProddableBlock), "addProddableBlock");
    
    1847
    -
    
    1848
    -   IF_DEBUG(linker, debugBelch("addProddableBlock: %p %p %d\n", oc, start, size));
    
    1849
    -   ASSERT(size > 0);
    
    1850
    -   pb->start      = start;
    
    1851
    -   pb->size       = size;
    
    1852
    -   pb->next       = oc->proddables;
    
    1853
    -   oc->proddables = pb;
    
    1854
    -}
    
    1855
    -
    
    1856
    -void
    
    1857
    -checkProddableBlock (ObjectCode *oc, void *addr, size_t size )
    
    1858
    -{
    
    1859
    -   ProddableBlock* pb;
    
    1860
    -
    
    1861
    -   for (pb = oc->proddables; pb != NULL; pb = pb->next) {
    
    1862
    -      char* s = (char*)(pb->start);
    
    1863
    -      char* e = s + pb->size;
    
    1864
    -      char* a = (char*)addr;
    
    1865
    -      if (a >= s && (a+size) <= e) return;
    
    1866
    -   }
    
    1867
    -   barf("checkProddableBlock: invalid fixup in runtime linker: %p", addr);
    
    1868
    -}
    
    1869
    -
    
    1870
    -void freeProddableBlocks (ObjectCode *oc)
    
    1871
    -{
    
    1872
    -    ProddableBlock *pb, *next;
    
    1873
    -
    
    1874
    -    for (pb = oc->proddables; pb != NULL; pb = next) {
    
    1875
    -        next = pb->next;
    
    1876
    -        stgFree(pb);
    
    1877
    -    }
    
    1878
    -    oc->proddables = NULL;
    
    1879
    -}
    
    1880
    -
    
    1881 1837
     /* -----------------------------------------------------------------------------
    
    1882 1838
      * Section management.
    
    1883 1839
      */
    

  • rts/LinkerInternals.h
    ... ... @@ -12,6 +12,7 @@
    12 12
     #include "RtsSymbols.h"
    
    13 13
     #include "Hash.h"
    
    14 14
     #include "linker/M32Alloc.h"
    
    15
    +#include "linker/ProddableBlocks.h"
    
    15 16
     
    
    16 17
     #if RTS_LINKER_USE_MMAP
    
    17 18
     #include <sys/mman.h>
    
    ... ... @@ -175,14 +176,6 @@ struct _Section {
    175 176
       struct SectionFormatInfo* info;
    
    176 177
     };
    
    177 178
     
    
    178
    -typedef
    
    179
    -   struct _ProddableBlock {
    
    180
    -      void* start;
    
    181
    -      int   size;
    
    182
    -      struct _ProddableBlock* next;
    
    183
    -   }
    
    184
    -   ProddableBlock;
    
    185
    -
    
    186 179
     typedef struct _Segment {
    
    187 180
         void *start;                /* page aligned start address of a segment */
    
    188 181
         size_t size;                /* page rounded size of a segment */
    
    ... ... @@ -328,7 +321,7 @@ struct _ObjectCode {
    328 321
         /* SANITY CHECK ONLY: a list of the only memory regions which may
    
    329 322
            safely be prodded during relocation.  Any attempt to prod
    
    330 323
            outside one of these is an error in the linker. */
    
    331
    -    ProddableBlock* proddables;
    
    324
    +    ProddableBlockSet proddables;
    
    332 325
     
    
    333 326
     #if defined(NEED_SYMBOL_EXTRAS)
    
    334 327
         SymbolExtra    *symbol_extras;
    
    ... ... @@ -434,10 +427,6 @@ void exitLinker( void );
    434 427
     void freeObjectCode (ObjectCode *oc);
    
    435 428
     SymbolAddr* loadSymbol(SymbolName *lbl, RtsSymbolInfo *pinfo);
    
    436 429
     
    
    437
    -void addProddableBlock ( ObjectCode* oc, void* start, int size );
    
    438
    -void checkProddableBlock (ObjectCode *oc, void *addr, size_t size );
    
    439
    -void freeProddableBlocks (ObjectCode *oc);
    
    440
    -
    
    441 430
     void addSection (Section *s, SectionKind kind, SectionAlloc alloc,
    
    442 431
                      void* start, StgWord size, StgWord mapped_offset,
    
    443 432
                      void* mapped_start, StgWord mapped_size);
    

  • rts/PathUtils.c
    ... ... @@ -13,7 +13,7 @@
    13 13
     #include <wchar.h>
    
    14 14
     #endif
    
    15 15
     
    
    16
    -pathchar* pathdup(pathchar *path)
    
    16
    +pathchar* pathdup(const pathchar *path)
    
    17 17
     {
    
    18 18
         pathchar *ret;
    
    19 19
     #if defined(mingw32_HOST_OS)
    
    ... ... @@ -26,7 +26,7 @@ pathchar* pathdup(pathchar *path)
    26 26
         return ret;
    
    27 27
     }
    
    28 28
     
    
    29
    -pathchar* pathdir(pathchar *path)
    
    29
    +pathchar* pathdir(const pathchar *path)
    
    30 30
     {
    
    31 31
         pathchar *ret;
    
    32 32
     #if defined(mingw32_HOST_OS)
    
    ... ... @@ -40,7 +40,8 @@ pathchar* pathdir(pathchar *path)
    40 40
         stgFree(drive);
    
    41 41
         stgFree(dirName);
    
    42 42
     #else
    
    43
    -    pathchar* dirName = dirname(path);
    
    43
    +    // N.B. cast is safe as we do not modify dirName
    
    44
    +    const pathchar* dirName = dirname((pathchar *) path);
    
    44 45
         size_t memberLen  = pathlen(dirName);
    
    45 46
         ret = stgMallocBytes(pathsize * (memberLen + 2), "pathdir(path)");
    
    46 47
         strcpy(ret, dirName);
    
    ... ... @@ -50,7 +51,7 @@ pathchar* pathdir(pathchar *path)
    50 51
         return ret;
    
    51 52
     }
    
    52 53
     
    
    53
    -pathchar* mkPath(char* path)
    
    54
    +pathchar* mkPath(const char* path)
    
    54 55
     {
    
    55 56
     #if defined(mingw32_HOST_OS)
    
    56 57
         size_t required = mbstowcs(NULL, path, 0);
    
    ... ... @@ -66,7 +67,7 @@ pathchar* mkPath(char* path)
    66 67
     #endif
    
    67 68
     }
    
    68 69
     
    
    69
    -HsBool endsWithPath(pathchar* base, pathchar* str) {
    
    70
    +HsBool endsWithPath(const pathchar* base, const pathchar* str) {
    
    70 71
         int blen = pathlen(base);
    
    71 72
         int slen = pathlen(str);
    
    72 73
         return (blen >= slen) && (0 == pathcmp(base + blen - slen, str));
    

  • rts/PathUtils.h
    ... ... @@ -37,9 +37,9 @@
    37 37
     
    
    38 38
     #include "BeginPrivate.h"
    
    39 39
     
    
    40
    -pathchar* pathdup(pathchar *path);
    
    41
    -pathchar* pathdir(pathchar *path);
    
    42
    -pathchar* mkPath(char* path);
    
    43
    -HsBool endsWithPath(pathchar* base, pathchar* str);
    
    40
    +pathchar* pathdup(const pathchar *path);
    
    41
    +pathchar* pathdir(const pathchar *path);
    
    42
    +pathchar* mkPath(const char* path);
    
    43
    +HsBool endsWithPath(const pathchar* base, const pathchar* str);
    
    44 44
     
    
    45 45
     #include "EndPrivate.h"

  • rts/linker/Elf.c
    ... ... @@ -924,7 +924,7 @@ ocGetNames_ELF ( ObjectCode* oc )
    924 924
               oc->sections[i].info->stubs = NULL;
    
    925 925
     #endif
    
    926 926
     
    
    927
    -          addProddableBlock(oc, start, size);
    
    927
    +          addProddableBlock(&oc->proddables, start, size);
    
    928 928
           } else {
    
    929 929
               addSection(&oc->sections[i], kind, alloc, oc->image+offset, size,
    
    930 930
                          0, 0, 0);
    
    ... ... @@ -1272,7 +1272,7 @@ do_Elf_Rel_relocations ( ObjectCode* oc, char* ehdrC,
    1272 1272
                     debugBelch("Reloc: P = %p   S = %p   A = %p   type=%d\n",
    
    1273 1273
                                (void*)P, (void*)S, (void*)A, reloc_type ));
    
    1274 1274
     #if defined(DEBUG)
    
    1275
    -       checkProddableBlock ( oc, pP, sizeof(Elf_Word) );
    
    1275
    +       checkProddableBlock ( &oc->proddables, pP, sizeof(Elf_Word) );
    
    1276 1276
     #else
    
    1277 1277
            (void) pP; /* suppress unused varialbe warning in non-debug build */
    
    1278 1278
     #endif
    
    ... ... @@ -1684,7 +1684,7 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
    1684 1684
     #if defined(DEBUG)
    
    1685 1685
           IF_DEBUG(linker_verbose,debugBelch("Reloc: P = %p   S = %p   A = %p\n",
    
    1686 1686
                                              (void*)P, (void*)S, (void*)A ));
    
    1687
    -      checkProddableBlock(oc, (void*)P, sizeof(Elf_Word));
    
    1687
    +      checkProddableBlock(&oc->proddables, (void*)P, sizeof(Elf_Word));
    
    1688 1688
     #endif
    
    1689 1689
     
    
    1690 1690
     #if defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH)
    

  • rts/linker/MachO.c
    ... ... @@ -253,7 +253,7 @@ resolveImports(
    253 253
                 return 0;
    
    254 254
             }
    
    255 255
     
    
    256
    -        checkProddableBlock(oc,
    
    256
    +        checkProddableBlock(&oc->proddables,
    
    257 257
                                 ((void**)(oc->image + sect->offset)) + i,
    
    258 258
                                 sizeof(void *));
    
    259 259
             ((void**)(oc->image + sect->offset))[i] = addr;
    
    ... ... @@ -287,7 +287,7 @@ decodeAddend(ObjectCode * oc, Section * section, MachORelocationInfo * ri) {
    287 287
         /* the instruction. It is 32bit wide */
    
    288 288
         uint32_t * p = (uint32_t*)((uint8_t*)section->start + ri->r_address);
    
    289 289
     
    
    290
    -    checkProddableBlock(oc, (void*)p, 1 << ri->r_length);
    
    290
    +    checkProddableBlock(&oc->proddables, (void*)p, 1 << ri->r_length);
    
    291 291
     
    
    292 292
         switch(ri->r_type) {
    
    293 293
             case ARM64_RELOC_UNSIGNED: {
    
    ... ... @@ -364,7 +364,7 @@ encodeAddend(ObjectCode * oc, Section * section,
    364 364
                  MachORelocationInfo * ri, int64_t addend) {
    
    365 365
         uint32_t * p = (uint32_t*)((uint8_t*)section->start + ri->r_address);
    
    366 366
     
    
    367
    -    checkProddableBlock(oc, (void*)p, 1 << ri->r_length);
    
    367
    +    checkProddableBlock(&oc->proddables, (void*)p, 1 << ri->r_length);
    
    368 368
     
    
    369 369
         switch (ri->r_type) {
    
    370 370
             case ARM64_RELOC_UNSIGNED: {
    
    ... ... @@ -788,7 +788,7 @@ relocateSection(ObjectCode* oc, int curSection)
    788 788
                 default:
    
    789 789
                     barf("Unknown size.");
    
    790 790
             }
    
    791
    -        checkProddableBlock(oc,thingPtr,relocLenBytes);
    
    791
    +        checkProddableBlock(&oc->proddables,thingPtr,relocLenBytes);
    
    792 792
     
    
    793 793
             /*
    
    794 794
              * With SIGNED_N the relocation is not at the end of the
    
    ... ... @@ -1034,9 +1034,9 @@ relocateSection(ObjectCode* oc, int curSection)
    1034 1034
              */
    
    1035 1035
             if (0 == reloc->r_extern) {
    
    1036 1036
                 if (reloc->r_pcrel) {
    
    1037
    -                checkProddableBlock(oc, (void *)((char *)thing + baseValue), 1);
    
    1037
    +                checkProddableBlock(&oc->proddables, (void *)((char *)thing + baseValue), 1);
    
    1038 1038
                 } else {
    
    1039
    -                checkProddableBlock(oc, (void *)thing, 1);
    
    1039
    +                checkProddableBlock(&oc->proddables, (void *)thing, 1);
    
    1040 1040
                 }
    
    1041 1041
             }
    
    1042 1042
     
    
    ... ... @@ -1343,7 +1343,7 @@ ocGetNames_MachO(ObjectCode* oc)
    1343 1343
                     secArray[sec_idx].info->stub_size = 0;
    
    1344 1344
                     secArray[sec_idx].info->stubs = NULL;
    
    1345 1345
     #endif
    
    1346
    -                addProddableBlock(oc, start, section->size);
    
    1346
    +                addProddableBlock(&oc->proddables, start, section->size);
    
    1347 1347
                 }
    
    1348 1348
     
    
    1349 1349
                 curMem = (char*) secMem + section->size;
    

  • rts/linker/PEi386.c
    ... ... @@ -378,7 +378,7 @@ static size_t makeSymbolExtra_PEi386(
    378 378
     #endif
    
    379 379
     
    
    380 380
     static void addDLLHandle(
    
    381
    -    pathchar* dll_name,
    
    381
    +    const pathchar* dll_name,
    
    382 382
         HINSTANCE instance);
    
    383 383
     
    
    384 384
     static bool verifyCOFFHeader(
    
    ... ... @@ -427,8 +427,52 @@ const int default_alignment = 8;
    427 427
        the pointer as a redirect.  Essentially it's a DATA DLL reference.  */
    
    428 428
     const void* __rts_iob_func = (void*)&__acrt_iob_func;
    
    429 429
     
    
    430
    +/*
    
    431
    + * Note [Avoiding repeated DLL loading]
    
    432
    + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    433
    + * As LoadLibraryEx tends to be expensive and addDLL_PEi386 is called on every
    
    434
    + * DLL-imported symbol, we use a hash-map to keep track of which DLLs have
    
    435
    + * already been loaded. This hash-map is keyed on the dll_name passed to
    
    436
    + * addDLL_PEi386 and is mapped to its HINSTANCE. This serves as a quick check
    
    437
    + * to avoid repeated calls to LoadLibraryEx for the identical DLL. See #26009.
    
    438
    + */
    
    439
    +
    
    440
    +typedef struct {
    
    441
    +    HashTable *hash;
    
    442
    +} LoadedDllCache;
    
    443
    +
    
    444
    +LoadedDllCache loaded_dll_cache;
    
    445
    +
    
    446
    +static void initLoadedDllCache(LoadedDllCache *cache) {
    
    447
    +    cache->hash = allocHashTable();
    
    448
    +}
    
    449
    +
    
    450
    +static int hash_path(const HashTable *table, StgWord w)
    
    451
    +{
    
    452
    +    const pathchar *key = (pathchar*) w;
    
    453
    +    return hashBuffer(table, key, sizeof(pathchar) * wcslen(key));
    
    454
    +}
    
    455
    +
    
    456
    +static int compare_path(StgWord key1, StgWord key2)
    
    457
    +{
    
    458
    +    return wcscmp((pathchar*) key1, (pathchar*) key2) == 0;
    
    459
    +}
    
    460
    +
    
    461
    +static void addLoadedDll(LoadedDllCache *cache, const pathchar *dll_name, HINSTANCE instance)
    
    462
    +{
    
    463
    +    insertHashTable_(cache->hash, (StgWord) dll_name, instance, hash_path);
    
    464
    +}
    
    465
    +
    
    466
    +static HINSTANCE isDllLoaded(const LoadedDllCache *cache, const pathchar *dll_name)
    
    467
    +{
    
    468
    +    void *result = lookupHashTable_(cache->hash, (StgWord) dll_name, hash_path, compare_path);
    
    469
    +    return (HINSTANCE) result;
    
    470
    +}
    
    471
    +
    
    430 472
     void initLinker_PEi386(void)
    
    431 473
     {
    
    474
    +    initLoadedDllCache(&loaded_dll_cache);
    
    475
    +
    
    432 476
         if (!ghciInsertSymbolTable(WSTR("(GHCi/Ld special symbols)"),
    
    433 477
                                    symhash, "__image_base__",
    
    434 478
                                    GetModuleHandleW (NULL), HS_BOOL_TRUE,
    
    ... ... @@ -440,10 +484,11 @@ void initLinker_PEi386(void)
    440 484
         addDLLHandle(WSTR("*.exe"), GetModuleHandle(NULL));
    
    441 485
     #endif
    
    442 486
     
    
    443
    -  /* Register the cleanup routine as an exit handler,  this gives other exit handlers
    
    444
    -     a chance to run which may need linker information.  Exit handlers are ran in
    
    445
    -     reverse registration order so this needs to be before the linker loads anything.  */
    
    446
    -  atexit (exitLinker_PEi386);
    
    487
    +    /* Register the cleanup routine as an exit handler,  this gives other exit handlers
    
    488
    +     * a chance to run which may need linker information.  Exit handlers are ran in
    
    489
    +     * reverse registration order so this needs to be before the linker loads anything.
    
    490
    +     */
    
    491
    +    atexit (exitLinker_PEi386);
    
    447 492
     }
    
    448 493
     
    
    449 494
     void exitLinker_PEi386(void)
    
    ... ... @@ -454,7 +499,7 @@ void exitLinker_PEi386(void)
    454 499
     static OpenedDLL* opened_dlls = NULL;
    
    455 500
     
    
    456 501
     /* Adds a DLL instance to the list of DLLs in which to search for symbols. */
    
    457
    -static void addDLLHandle(pathchar* dll_name, HINSTANCE instance) {
    
    502
    +static void addDLLHandle(const pathchar* dll_name, HINSTANCE instance) {
    
    458 503
     
    
    459 504
         IF_DEBUG(linker, debugBelch("addDLLHandle(%" PATH_FMT ")...\n", dll_name));
    
    460 505
         /* At this point, we actually know what was loaded.
    
    ... ... @@ -796,14 +841,19 @@ uint8_t* getSymShortName ( COFF_HEADER_INFO *info, COFF_symbol* sym )
    796 841
     }
    
    797 842
     
    
    798 843
     const char *
    
    799
    -addDLL_PEi386( pathchar *dll_name, HINSTANCE *loaded )
    
    844
    +addDLL_PEi386( const pathchar *dll_name, HINSTANCE *loaded )
    
    800 845
     {
    
    801
    -   /* ------------------- Win32 DLL loader ------------------- */
    
    802
    -
    
    803
    -   pathchar*  buf;
    
    804
    -   HINSTANCE  instance;
    
    805
    -
    
    806
    -   IF_DEBUG(linker, debugBelch("addDLL; dll_name = `%" PATH_FMT "'\n", dll_name));
    
    846
    +    /* ------------------- Win32 DLL loader ------------------- */
    
    847
    +    IF_DEBUG(linker, debugBelch("addDLL; dll_name = `%" PATH_FMT "'\n", dll_name));
    
    848
    +
    
    849
    +    // See Note [Avoiding repeated DLL loading]
    
    850
    +    HINSTANCE instance = isDllLoaded(&loaded_dll_cache, dll_name);
    
    851
    +    if (instance) {
    
    852
    +        if (loaded) {
    
    853
    +            *loaded = instance;
    
    854
    +        }
    
    855
    +        return NULL;
    
    856
    +    }
    
    807 857
     
    
    808 858
         /* The file name has no suffix (yet) so that we can try
    
    809 859
            both foo.dll and foo.drv
    
    ... ... @@ -816,45 +866,32 @@ addDLL_PEi386( pathchar *dll_name, HINSTANCE *loaded )
    816 866
             extension. */
    
    817 867
     
    
    818 868
         size_t bufsize = pathlen(dll_name) + 10;
    
    819
    -    buf = stgMallocBytes(bufsize * sizeof(wchar_t), "addDLL");
    
    869
    +    pathchar *buf = stgMallocBytes(bufsize * sizeof(wchar_t), "addDLL");
    
    820 870
     
    
    821 871
         /* These are ordered by probability of success and order we'd like them.  */
    
    822 872
         const wchar_t *formats[] = { L"%ls.DLL", L"%ls.DRV", L"lib%ls.DLL", L"%ls" };
    
    823 873
         const DWORD flags[] = { LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS, 0 };
    
    824 874
     
    
    825
    -    int cFormat, cFlag;
    
    826
    -    int flags_start = 1; /* Assume we don't support the new API.  */
    
    827
    -
    
    828
    -    /* Detect if newer API are available, if not, skip the first flags entry.  */
    
    829
    -    if (GetProcAddress((HMODULE)LoadLibraryW(L"Kernel32.DLL"), "AddDllDirectory")) {
    
    830
    -        flags_start = 0;
    
    831
    -    }
    
    832
    -
    
    833 875
         /* Iterate through the possible flags and formats.  */
    
    834
    -    for (cFlag = flags_start; cFlag < 2; cFlag++)
    
    835
    -    {
    
    836
    -        for (cFormat = 0; cFormat < 4; cFormat++)
    
    837
    -        {
    
    876
    +    for (int cFlag = 0; cFlag < 2; cFlag++) {
    
    877
    +        for (int cFormat = 0; cFormat < 4; cFormat++) {
    
    838 878
                 snwprintf(buf, bufsize, formats[cFormat], dll_name);
    
    839 879
                 instance = LoadLibraryExW(buf, NULL, flags[cFlag]);
    
    840 880
                 if (instance == NULL) {
    
    841
    -                if (GetLastError() != ERROR_MOD_NOT_FOUND)
    
    842
    -                {
    
    881
    +                if (GetLastError() != ERROR_MOD_NOT_FOUND) {
    
    843 882
                         goto error;
    
    844 883
                     }
    
    845
    -            }
    
    846
    -            else
    
    847
    -            {
    
    848
    -                break; /* We're done. DLL has been loaded.  */
    
    884
    +            } else {
    
    885
    +                goto loaded; /* We're done. DLL has been loaded.  */
    
    849 886
                 }
    
    850 887
             }
    
    851 888
         }
    
    852 889
     
    
    853
    -    /* Check if we managed to load the DLL.  */
    
    854
    -    if (instance == NULL) {
    
    855
    -        goto error;
    
    856
    -    }
    
    890
    +    // We failed to load
    
    891
    +    goto error;
    
    857 892
     
    
    893
    +loaded:
    
    894
    +    addLoadedDll(&loaded_dll_cache, dll_name, instance);
    
    858 895
         addDLLHandle(buf, instance);
    
    859 896
         if (loaded) {
    
    860 897
             *loaded = instance;
    
    ... ... @@ -1658,7 +1695,7 @@ ocGetNames_PEi386 ( ObjectCode* oc )
    1658 1695
           }
    
    1659 1696
     
    
    1660 1697
           addSection(section, kind, SECTION_NOMEM, start, sz, 0, 0, 0);
    
    1661
    -      addProddableBlock(oc, oc->sections[i].start, sz);
    
    1698
    +      addProddableBlock(&oc->proddables, oc->sections[i].start, sz);
    
    1662 1699
        }
    
    1663 1700
     
    
    1664 1701
        /* Copy exported symbols into the ObjectCode. */
    
    ... ... @@ -1690,7 +1727,7 @@ ocGetNames_PEi386 ( ObjectCode* oc )
    1690 1727
                       SECTIONKIND_RWDATA, SECTION_MALLOC,
    
    1691 1728
                       bss, globalBssSize, 0, 0, 0);
    
    1692 1729
            IF_DEBUG(linker_verbose, debugBelch("bss @ %p %" FMT_Word "\n", bss, globalBssSize));
    
    1693
    -       addProddableBlock(oc, bss, globalBssSize);
    
    1730
    +       addProddableBlock(&oc->proddables, bss, globalBssSize);
    
    1694 1731
        } else {
    
    1695 1732
            addSection(&oc->sections[oc->n_sections-1],
    
    1696 1733
                       SECTIONKIND_OTHER, SECTION_NOMEM, NULL, 0, 0, 0, 0);
    
    ... ... @@ -2067,13 +2104,13 @@ ocResolve_PEi386 ( ObjectCode* oc )
    2067 2104
              IF_DEBUG(linker_verbose, debugBelch("S=%zx\n", S));
    
    2068 2105
     
    
    2069 2106
              /* All supported relocations write at least 4 bytes */
    
    2070
    -         checkProddableBlock(oc, pP, 4);
    
    2107
    +         checkProddableBlock(&oc->proddables, pP, 4);
    
    2071 2108
              switch (reloc->Type) {
    
    2072 2109
     #if defined(x86_64_HOST_ARCH)
    
    2073 2110
                 case 1: /* R_X86_64_64 (ELF constant 1) - IMAGE_REL_AMD64_ADDR64 (PE constant 1) */
    
    2074 2111
                    {
    
    2075 2112
                        uint64_t A;
    
    2076
    -                   checkProddableBlock(oc, pP, 8);
    
    2113
    +                   checkProddableBlock(&oc->proddables, pP, 8);
    
    2077 2114
                        A = *(uint64_t*)pP;
    
    2078 2115
                        *(uint64_t *)pP = S + A;
    
    2079 2116
                        break;
    
    ... ... @@ -2114,7 +2151,7 @@ ocResolve_PEi386 ( ObjectCode* oc )
    2114 2151
                    {
    
    2115 2152
                        /* mingw will emit this for a pc-rel 64 relocation */
    
    2116 2153
                        uint64_t A;
    
    2117
    -                   checkProddableBlock(oc, pP, 8);
    
    2154
    +                   checkProddableBlock(&oc->proddables, pP, 8);
    
    2118 2155
                        A = *(uint64_t*)pP;
    
    2119 2156
                        *(uint64_t *)pP = S + A - (intptr_t)pP;
    
    2120 2157
                        break;
    

  • rts/linker/PEi386.h
    ... ... @@ -45,7 +45,7 @@ typedef struct _COFF_HEADER_INFO {
    45 45
     
    
    46 46
     void initLinker_PEi386( void );
    
    47 47
     void exitLinker_PEi386( void );
    
    48
    -const char * addDLL_PEi386( pathchar *dll_name, HINSTANCE *instance  );
    
    48
    +const char * addDLL_PEi386( const pathchar *dll_name, HINSTANCE *instance  );
    
    49 49
     void freePreloadObjectFile_PEi386( ObjectCode *oc );
    
    50 50
     
    
    51 51
     bool checkAndLoadImportLibrary( pathchar* arch_name, char* member_name, FILE* f);
    

  • rts/linker/ProddableBlocks.c
    1
    +/* -----------------------------------------------------------------------------
    
    2
    + *
    
    3
    + * (c) The GHC Team, 2025
    
    4
    + *
    
    5
    + * RTS Object Linker
    
    6
    + *
    
    7
    + * ---------------------------------------------------------------------------*/
    
    8
    +
    
    9
    +
    
    10
    +/*
    
    11
    + * Note [Proddable blocks]
    
    12
    + * ~~~~~~~~~~~~~~~~~~~~~~~
    
    13
    + * For each ObjectCode, we maintain a ProddableBlockSet representing the set of
    
    14
    + * address ranges containing data belonging to the object. This set is
    
    15
    + * represented here as an array of intervals sorted by start address. This
    
    16
    + * allows us to efficiently query and insert via binary search. Array resizing
    
    17
    + * is done according to an exponential growth schedule.
    
    18
    + *
    
    19
    + * While performing relocations we check against this set and and abort if we
    
    20
    + * try and write outside any of these.
    
    21
    + */
    
    22
    +
    
    23
    +#include "Rts.h"
    
    24
    +#include "RtsUtils.h"
    
    25
    +#include "linker/ProddableBlocks.h"
    
    26
    +
    
    27
    +#include <stdlib.h>
    
    28
    +#include <string.h>
    
    29
    +
    
    30
    +typedef struct _ProddableBlock {
    
    31
    +    uintptr_t start;  // inclusive
    
    32
    +    uintptr_t end;    // inclusive
    
    33
    +} ProddableBlock;
    
    34
    +
    
    35
    +void
    
    36
    +initProddableBlockSet ( ProddableBlockSet* set )
    
    37
    +{
    
    38
    +    set->data = NULL;
    
    39
    +    set->capacity = 0;
    
    40
    +    set->size = 0;
    
    41
    +}
    
    42
    +
    
    43
    +void
    
    44
    +freeProddableBlocks (ProddableBlockSet *set)
    
    45
    +{
    
    46
    +    stgFree(set->data);
    
    47
    +    set->data = NULL;
    
    48
    +    set->size = 0;
    
    49
    +    set->capacity = 0;
    
    50
    +}
    
    51
    +
    
    52
    +// Binary search for the first interval with start >= value. Returns index or
    
    53
    +// size if none.
    
    54
    +static size_t
    
    55
    +findLower(const ProddableBlockSet *set, uintptr_t value)
    
    56
    +{
    
    57
    +    size_t l = 0;
    
    58
    +    size_t r = set->size;
    
    59
    +    while (l < r) {
    
    60
    +        size_t mid = l + (r - l) / 2;
    
    61
    +        if (set->data[mid].start < value) {
    
    62
    +            l = mid + 1;
    
    63
    +        } else {
    
    64
    +            r = mid;
    
    65
    +        }
    
    66
    +    }
    
    67
    +    return l;
    
    68
    +}
    
    69
    +
    
    70
    +// Check whether a given value is a member of the set.
    
    71
    +bool
    
    72
    +containsSpan ( const ProddableBlockSet *set, uintptr_t start, uintptr_t end )
    
    73
    +{
    
    74
    +    size_t i = findLower(set, start+1);
    
    75
    +    return i > 0
    
    76
    +      && set->data[i-1].start <= start
    
    77
    +      && end <= set->data[i-1].end;
    
    78
    +}
    
    79
    +
    
    80
    +void
    
    81
    +checkProddableBlock (const ProddableBlockSet *set, void *addr, size_t size )
    
    82
    +{
    
    83
    +    if (! containsSpan(set, (uintptr_t) addr, (uintptr_t) addr+size)) {
    
    84
    +        barf("checkProddableBlock: invalid fixup in runtime linker: %p", addr);
    
    85
    +    }
    
    86
    +}
    
    87
    +
    
    88
    +// Ensure capacity for at least new_capacity intervals
    
    89
    +static void
    
    90
    +ensureCapacity(ProddableBlockSet *set, size_t new_capacity) {
    
    91
    +    if (new_capacity > set->capacity) {
    
    92
    +        size_t cap = set->capacity ? set->capacity * 2 : 4;
    
    93
    +        if (cap < new_capacity) {
    
    94
    +            cap = new_capacity;
    
    95
    +        }
    
    96
    +        ProddableBlock *tmp = stgReallocBytes(set->data, cap * sizeof(ProddableBlock), "addProddableBlock");
    
    97
    +        set->data = tmp;
    
    98
    +        set->capacity = cap;
    
    99
    +    }
    
    100
    +}
    
    101
    +
    
    102
    +void
    
    103
    +addProddableBlock ( ProddableBlockSet* set, void* start_ptr, size_t size )
    
    104
    +{
    
    105
    +    const uintptr_t start = (uintptr_t) start_ptr;
    
    106
    +    const uintptr_t end = (uintptr_t) start + size;
    
    107
    +    size_t i = findLower(set, start);
    
    108
    +
    
    109
    +    // check previous interval if it is overlapping or adjacent
    
    110
    +    if (i > 0 && start <= set->data[i-1].end + 1) {
    
    111
    +        // merge with left interval
    
    112
    +        i--;
    
    113
    +        if (end > set->data[i].end) {
    
    114
    +            set->data[i].end = end;
    
    115
    +        }
    
    116
    +    } else {
    
    117
    +        // insert new interval
    
    118
    +        ensureCapacity(set, set->size + 1);
    
    119
    +        memmove(&set->data[i+1], &set->data[i], sizeof(ProddableBlock) * (set->size - i));
    
    120
    +        set->data[i].start = start;
    
    121
    +        set->data[i].end = end;
    
    122
    +        set->size++;
    
    123
    +    }
    
    124
    +
    
    125
    +    // coalesce overlaps on right
    
    126
    +    size_t j = i;
    
    127
    +    while (j < set->size && set->data[j].start <= set->data[i].end + 1) {
    
    128
    +        set->data[i].end = set->data[j].end;
    
    129
    +        j++;
    
    130
    +    }
    
    131
    +
    
    132
    +    if (j != i) {
    
    133
    +        memmove(&set->data[i+1], &set->data[j], sizeof(ProddableBlock) * (set->size - j));
    
    134
    +        set->size -= j - i - 1;
    
    135
    +    }
    
    136
    +}
    
    137
    +

  • rts/linker/ProddableBlocks.h
    1
    +/* -----------------------------------------------------------------------------
    
    2
    + *
    
    3
    + * (c) The GHC Team, 2025
    
    4
    + *
    
    5
    + * RTS Object Linker
    
    6
    + *
    
    7
    + * ---------------------------------------------------------------------------*/
    
    8
    +
    
    9
    +#pragma once
    
    10
    +
    
    11
    +#include <stdbool.h>
    
    12
    +#include <stddef.h>
    
    13
    +#include <stdint.h>
    
    14
    +
    
    15
    +// An interval set on uintptr_t.
    
    16
    +struct _ProddableBlock;
    
    17
    +
    
    18
    +typedef struct {
    
    19
    +    size_t size;
    
    20
    +    size_t capacity;
    
    21
    +    // sorted list of disjoint (start,end) pairs
    
    22
    +    struct _ProddableBlock *data;
    
    23
    +} ProddableBlockSet;
    
    24
    +
    
    25
    +void initProddableBlockSet ( ProddableBlockSet* set );
    
    26
    +
    
    27
    +// Insert an interval.
    
    28
    +void addProddableBlock ( ProddableBlockSet* set, void* start, size_t size );
    
    29
    +
    
    30
    +// Check that an address belongs to the set.
    
    31
    +void checkProddableBlock (const ProddableBlockSet *set, void *addr, size_t size );
    
    32
    +
    
    33
    +
    
    34
    +// Free a set.
    
    35
    +void freeProddableBlocks (ProddableBlockSet *set);
    
    36
    +
    
    37
    +// For testing.
    
    38
    +bool containsSpan ( const ProddableBlockSet *set, uintptr_t start, uintptr_t end );

  • rts/rts.cabal
    ... ... @@ -491,6 +491,7 @@ library
    491 491
                      linker/MachO.c
    
    492 492
                      linker/macho/plt.c
    
    493 493
                      linker/macho/plt_aarch64.c
    
    494
    +                 linker/ProddableBlocks.c
    
    494 495
                      linker/PEi386.c
    
    495 496
                      linker/SymbolExtras.c
    
    496 497
                      linker/elf_got.c
    

  • testsuite/tests/rts/TestProddableBlockSet.c
    1
    +#include <assert.h>
    
    2
    +#include <stdbool.h>
    
    3
    +#include <stdint.h>
    
    4
    +#include <stddef.h>
    
    5
    +
    
    6
    +// Excerpted from ProddableBlocks.h
    
    7
    +typedef struct {
    
    8
    +    size_t size;
    
    9
    +    size_t capacity;
    
    10
    +    // sorted list of disjoint (start,end) pairs
    
    11
    +    struct _ProddableBlock *data;
    
    12
    +} ProddableBlockSet;
    
    13
    +
    
    14
    +void initProddableBlockSet ( ProddableBlockSet* set );
    
    15
    +void addProddableBlock ( ProddableBlockSet* set, void* start, size_t size );
    
    16
    +bool containsSpan ( const ProddableBlockSet *set, uintptr_t start, uintptr_t end );
    
    17
    +
    
    18
    +int main () {
    
    19
    +  ProddableBlockSet set;
    
    20
    +  initProddableBlockSet(&set);
    
    21
    +  addProddableBlock(&set, (void*) 0x20, 0x10);
    
    22
    +  addProddableBlock(&set, (void*) 0x30, 0x10);
    
    23
    +  addProddableBlock(&set, (void*) 0x100, 0x10);
    
    24
    +
    
    25
    +  assert( containsSpan(&set, 0x20, 0x30));
    
    26
    +  assert( containsSpan(&set, 0x30, 0x29));
    
    27
    +  assert(!containsSpan(&set, 0x30, 0x49));
    
    28
    +  assert(!containsSpan(&set, 0x60, 0x70));
    
    29
    +  assert(!containsSpan(&set, 0x90, 0x110));
    
    30
    +  assert( containsSpan(&set, 0x100, 0x101));
    
    31
    +  return 0;
    
    32
    +}
    
    33
    +

  • testsuite/tests/rts/all.T
    ... ... @@ -641,3 +641,5 @@ test('T25280', [unless(opsys('linux'),skip),req_process,js_skip], compile_and_ru
    641 641
     # N.B. This will likely issue a warning on stderr but we merely care that the
    
    642 642
     # program doesn't crash.
    
    643 643
     test('T25560', [req_c_rts, ignore_stderr], compile_and_run, [''])
    
    644
    +
    
    645
    +test('TestProddableBlockSet', [req_c_rts], multimod_compile_and_run, ['TestProddableBlockSet.c', '-no-hs-main'])