Ben Gamari pushed to branch wip/T26009 at Glasgow Haskell Compiler / GHC

Commits:

13 changed files:

Changes:

  • libffi-tarballs
    1
    -Subproject commit ac7fa3132d382056837cad297ab4c66418febb69
    1
    +Subproject commit cb280851187d7b509d341be7b50c9a239810feb0

  • 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/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
    ... ... @@ -427,8 +427,53 @@ 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-set to keep track of which DLLs have
    
    435
    + * already been loaded. This hash-set is keyed on the dll_name passed to
    
    436
    + * addDLL_PEi386 and serves as a quick check to avoid repeated calls to
    
    437
    + * LoadLibraryEx for the identical DLL. See #26009.
    
    438
    + */
    
    439
    +
    
    440
    +typedef struct {
    
    441
    +    HashTable *hash;
    
    442
    +} LoadedDllSet;
    
    443
    +
    
    444
    +LoadedDllSet loaded_dll_set;
    
    445
    +
    
    446
    +void initLoadedDllSet(LoadedDllSet *set) {
    
    447
    +    set->hash = allocHashTable();
    
    448
    +}
    
    449
    +
    
    450
    +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
    +int compare_path(StgWord key1, StgWord key2)
    
    457
    +{
    
    458
    +    return wscmp((pathchar*) key1, (pathchar*) key2);
    
    459
    +}
    
    460
    +
    
    461
    +void addLoadedDll(LoadedDllSet *set, pathchar *dll_name)
    
    462
    +{
    
    463
    +    insertHashTable_(set->hash, (StgWord) dll_name, (void*) 1, hash_path);
    
    464
    +}
    
    465
    +
    
    466
    +bool isDllLoaded(LoadedDllSet *set, pathchar *dll_name)
    
    467
    +{
    
    468
    +    void * result = lookupHashTable_(set->hash, (StgWord) dll_name, hash_path, compare_path);
    
    469
    +    return result != NULL;
    
    470
    +}
    
    471
    +
    
    472
    +
    
    430 473
     void initLinker_PEi386(void)
    
    431 474
     {
    
    475
    +    initLoadedDllSet(&loaded_dll_set);
    
    476
    +
    
    432 477
         if (!ghciInsertSymbolTable(WSTR("(GHCi/Ld special symbols)"),
    
    433 478
                                    symhash, "__image_base__",
    
    434 479
                                    GetModuleHandleW (NULL), HS_BOOL_TRUE,
    
    ... ... @@ -440,10 +485,11 @@ void initLinker_PEi386(void)
    440 485
         addDLLHandle(WSTR("*.exe"), GetModuleHandle(NULL));
    
    441 486
     #endif
    
    442 487
     
    
    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);
    
    488
    +    /* Register the cleanup routine as an exit handler,  this gives other exit handlers
    
    489
    +     * a chance to run which may need linker information.  Exit handlers are ran in
    
    490
    +     * reverse registration order so this needs to be before the linker loads anything.
    
    491
    +     */
    
    492
    +    atexit (exitLinker_PEi386);
    
    447 493
     }
    
    448 494
     
    
    449 495
     void exitLinker_PEi386(void)
    
    ... ... @@ -798,12 +844,12 @@ uint8_t* getSymShortName ( COFF_HEADER_INFO *info, COFF_symbol* sym )
    798 844
     const char *
    
    799 845
     addDLL_PEi386( pathchar *dll_name, HINSTANCE *loaded )
    
    800 846
     {
    
    801
    -   /* ------------------- Win32 DLL loader ------------------- */
    
    802
    -
    
    803
    -   pathchar*  buf;
    
    804
    -   HINSTANCE  instance;
    
    847
    +    /* ------------------- Win32 DLL loader ------------------- */
    
    848
    +    IF_DEBUG(linker, debugBelch("addDLL; dll_name = `%" PATH_FMT "'\n", dll_name));
    
    805 849
     
    
    806
    -   IF_DEBUG(linker, debugBelch("addDLL; dll_name = `%" PATH_FMT "'\n", dll_name));
    
    850
    +    if (isDllLoaded(&loaded_dll_set, dll_name)) {
    
    851
    +        return NULL;
    
    852
    +    }
    
    807 853
     
    
    808 854
         /* The file name has no suffix (yet) so that we can try
    
    809 855
            both foo.dll and foo.drv
    
    ... ... @@ -816,35 +862,23 @@ addDLL_PEi386( pathchar *dll_name, HINSTANCE *loaded )
    816 862
             extension. */
    
    817 863
     
    
    818 864
         size_t bufsize = pathlen(dll_name) + 10;
    
    819
    -    buf = stgMallocBytes(bufsize * sizeof(wchar_t), "addDLL");
    
    865
    +    pathchar *buf = stgMallocBytes(bufsize * sizeof(wchar_t), "addDLL");
    
    820 866
     
    
    821 867
         /* These are ordered by probability of success and order we'd like them.  */
    
    822 868
         const wchar_t *formats[] = { L"%ls.DLL", L"%ls.DRV", L"lib%ls.DLL", L"%ls" };
    
    823 869
         const DWORD flags[] = { LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS, 0 };
    
    824 870
     
    
    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 871
         /* Iterate through the possible flags and formats.  */
    
    834
    -    for (cFlag = flags_start; cFlag < 2; cFlag++)
    
    835
    -    {
    
    836
    -        for (cFormat = 0; cFormat < 4; cFormat++)
    
    837
    -        {
    
    872
    +    HINSTANCE instance;
    
    873
    +    for (int cFlag = 0; cFlag < 2; cFlag++) {
    
    874
    +        for (int cFormat = 0; cFormat < 4; cFormat++) {
    
    838 875
                 snwprintf(buf, bufsize, formats[cFormat], dll_name);
    
    839 876
                 instance = LoadLibraryExW(buf, NULL, flags[cFlag]);
    
    840 877
                 if (instance == NULL) {
    
    841
    -                if (GetLastError() != ERROR_MOD_NOT_FOUND)
    
    842
    -                {
    
    878
    +                if (GetLastError() != ERROR_MOD_NOT_FOUND) {
    
    843 879
                         goto error;
    
    844 880
                     }
    
    845
    -            }
    
    846
    -            else
    
    847
    -            {
    
    881
    +            } else {
    
    848 882
                     break; /* We're done. DLL has been loaded.  */
    
    849 883
                 }
    
    850 884
             }
    
    ... ... @@ -855,6 +889,7 @@ addDLL_PEi386( pathchar *dll_name, HINSTANCE *loaded )
    855 889
             goto error;
    
    856 890
         }
    
    857 891
     
    
    892
    +    addLoadedDll(&loaded_dll_set, dll_name);
    
    858 893
         addDLLHandle(buf, instance);
    
    859 894
         if (loaded) {
    
    860 895
             *loaded = instance;
    
    ... ... @@ -1658,7 +1693,7 @@ ocGetNames_PEi386 ( ObjectCode* oc )
    1658 1693
           }
    
    1659 1694
     
    
    1660 1695
           addSection(section, kind, SECTION_NOMEM, start, sz, 0, 0, 0);
    
    1661
    -      addProddableBlock(oc, oc->sections[i].start, sz);
    
    1696
    +      addProddableBlock(&oc->proddables, oc->sections[i].start, sz);
    
    1662 1697
        }
    
    1663 1698
     
    
    1664 1699
        /* Copy exported symbols into the ObjectCode. */
    
    ... ... @@ -1690,7 +1725,7 @@ ocGetNames_PEi386 ( ObjectCode* oc )
    1690 1725
                       SECTIONKIND_RWDATA, SECTION_MALLOC,
    
    1691 1726
                       bss, globalBssSize, 0, 0, 0);
    
    1692 1727
            IF_DEBUG(linker_verbose, debugBelch("bss @ %p %" FMT_Word "\n", bss, globalBssSize));
    
    1693
    -       addProddableBlock(oc, bss, globalBssSize);
    
    1728
    +       addProddableBlock(&oc->proddables, bss, globalBssSize);
    
    1694 1729
        } else {
    
    1695 1730
            addSection(&oc->sections[oc->n_sections-1],
    
    1696 1731
                       SECTIONKIND_OTHER, SECTION_NOMEM, NULL, 0, 0, 0, 0);
    
    ... ... @@ -2067,13 +2102,13 @@ ocResolve_PEi386 ( ObjectCode* oc )
    2067 2102
              IF_DEBUG(linker_verbose, debugBelch("S=%zx\n", S));
    
    2068 2103
     
    
    2069 2104
              /* All supported relocations write at least 4 bytes */
    
    2070
    -         checkProddableBlock(oc, pP, 4);
    
    2105
    +         checkProddableBlock(&oc->proddables, pP, 4);
    
    2071 2106
              switch (reloc->Type) {
    
    2072 2107
     #if defined(x86_64_HOST_ARCH)
    
    2073 2108
                 case 1: /* R_X86_64_64 (ELF constant 1) - IMAGE_REL_AMD64_ADDR64 (PE constant 1) */
    
    2074 2109
                    {
    
    2075 2110
                        uint64_t A;
    
    2076
    -                   checkProddableBlock(oc, pP, 8);
    
    2111
    +                   checkProddableBlock(&oc->proddables, pP, 8);
    
    2077 2112
                        A = *(uint64_t*)pP;
    
    2078 2113
                        *(uint64_t *)pP = S + A;
    
    2079 2114
                        break;
    
    ... ... @@ -2114,7 +2149,7 @@ ocResolve_PEi386 ( ObjectCode* oc )
    2114 2149
                    {
    
    2115 2150
                        /* mingw will emit this for a pc-rel 64 relocation */
    
    2116 2151
                        uint64_t A;
    
    2117
    -                   checkProddableBlock(oc, pP, 8);
    
    2152
    +                   checkProddableBlock(&oc->proddables, pP, 8);
    
    2118 2153
                        A = *(uint64_t*)pP;
    
    2119 2154
                        *(uint64_t *)pP = S + A - (intptr_t)pP;
    
    2120 2155
                        break;
    

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

  • 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'])