Home | History | Annotate | Line # | Download | only in sections
      1 // PE/COFF-specific support for sections.
      2 // Copyright (C) 2021-2022 Free Software Foundation, Inc.
      3 
      4 // GCC is free software; you can redistribute it and/or modify it under
      5 // the terms of the GNU General Public License as published by the Free
      6 // Software Foundation; either version 3, or (at your option) any later
      7 // version.
      8 
      9 // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
     10 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
     11 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     12 // for more details.
     13 
     14 // Under Section 7 of GPL version 3, you are granted additional
     15 // permissions described in the GCC Runtime Library Exception, version
     16 // 3.1, as published by the Free Software Foundation.
     17 
     18 // You should have received a copy of the GNU General Public License and
     19 // a copy of the GCC Runtime Library Exception along with this program;
     20 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     21 // <http://www.gnu.org/licenses/>.
     22 
     23 module gcc.sections.pecoff;
     24 
     25 version (Windows):
     26 
     27 import core.memory;
     28 import core.stdc.stdlib;
     29 import core.sys.windows.winbase;
     30 import core.sys.windows.windef;
     31 import core.sys.windows.winnt;
     32 import rt.minfo;
     33 import core.internal.container.array;
     34 import core.internal.container.hashtab;
     35 import gcc.sections.common;
     36 
     37 version (GNU_EMUTLS)
     38     import gcc.emutls;
     39 
     40 alias DSO SectionGroup;
     41 struct DSO
     42 {
     43     static int opApply(scope int delegate(ref DSO) dg)
     44     {
     45         foreach (dso; _loadedDSOs)
     46         {
     47             if (auto res = dg(*dso))
     48                 return res;
     49         }
     50         return 0;
     51     }
     52 
     53     static int opApplyReverse(scope int delegate(ref DSO) dg)
     54     {
     55         foreach_reverse (dso; _loadedDSOs)
     56         {
     57             if (auto res = dg(*dso))
     58                 return res;
     59         }
     60         return 0;
     61     }
     62 
     63     @property immutable(ModuleInfo*)[] modules() const nothrow @nogc
     64     {
     65         return _moduleGroup.modules;
     66     }
     67 
     68     @property ref inout(ModuleGroup) moduleGroup() inout return nothrow @nogc
     69     {
     70         return _moduleGroup;
     71     }
     72 
     73     @property inout(void[])[] gcRanges() inout nothrow @nogc
     74     {
     75         return _gcRanges[];
     76     }
     77 
     78 private:
     79 
     80     invariant()
     81     {
     82         safeAssert(_moduleGroup.modules.length > 0, "No modules for DSO.");
     83     }
     84 
     85     void** _slot;
     86     ModuleGroup _moduleGroup;
     87     Array!(void[]) _gcRanges;
     88 
     89     version (Shared)
     90     {
     91         Array!(void[]) _codeSegments; // array of code segments
     92         Array!(DSO*) _deps; // D libraries needed by this DSO
     93         void* _handle; // corresponding handle
     94     }
     95 }
     96 
     97 /****
     98  * Boolean flag set to true while the runtime is initialized.
     99  */
    100 __gshared bool _isRuntimeInitialized;
    101 
    102 /****
    103  * Gets called on program startup just before GC is initialized.
    104  */
    105 void initSections() nothrow @nogc
    106 {
    107     _isRuntimeInitialized = true;
    108 }
    109 
    110 /***
    111  * Gets called on program shutdown just after GC is terminated.
    112  */
    113 void finiSections() nothrow @nogc
    114 {
    115     _isRuntimeInitialized = false;
    116 }
    117 
    118 alias ScanDG = void delegate(void* pbeg, void* pend) nothrow;
    119 
    120 version (Shared)
    121 {
    122     import gcc.sections : pinLoadedLibraries, unpinLoadedLibraries,
    123            inheritLoadedLibraries, cleanupLoadedLibraries;
    124 
    125     /***
    126      * Called once per thread; returns array of thread local storage ranges
    127      */
    128     Array!(ThreadDSO)* initTLSRanges() @nogc nothrow
    129     {
    130         return &_loadedDSOs();
    131     }
    132 
    133     void finiTLSRanges(Array!(ThreadDSO)* tdsos) @nogc nothrow
    134     {
    135         // Nothing to do here. tdsos used to point to the _loadedDSOs instance
    136         // in the dying thread's TLS segment and as such is not valid anymore.
    137         // The memory for the array contents was already reclaimed in
    138         // cleanupLoadedLibraries().
    139     }
    140 
    141     void scanTLSRanges(Array!(ThreadDSO)* tdsos, scope ScanDG dg) nothrow
    142     {
    143         version (GNU_EMUTLS)
    144             _d_emutls_scan(dg);
    145         else
    146             static assert(0, "Native TLS unimplemented");
    147     }
    148 
    149     // interface for core.thread to inherit loaded libraries
    150     pragma(mangle, gcc.sections.pinLoadedLibraries.mangleof)
    151     void* pinLoadedLibraries() nothrow @nogc
    152     {
    153         auto res = cast(Array!(ThreadDSO)*)calloc(1, Array!(ThreadDSO).sizeof);
    154         res.length = _loadedDSOs.length;
    155         foreach (i, ref tdso; _loadedDSOs)
    156         {
    157             (*res)[i] = tdso;
    158             if (tdso._addCnt)
    159             {
    160                 // Increment the DLL ref for explicitly loaded libraries to pin them.
    161                 char[MAX_PATH] buf;
    162                 char[] buffer = buf[];
    163                 const success = .LoadLibraryA(nameForDSO(tdso._pdso, buffer)) !is null;
    164                 safeAssert(success, "Failed to increment DLL ref.");
    165                 (*res)[i]._addCnt = 1; // new array takes over the additional ref count
    166             }
    167         }
    168         return res;
    169     }
    170 
    171     pragma(mangle, gcc.sections.unpinLoadedLibraries.mangleof)
    172     void unpinLoadedLibraries(void* p) nothrow @nogc
    173     {
    174         auto pary = cast(Array!(ThreadDSO)*)p;
    175         // In case something failed we need to undo the pinning.
    176         foreach (ref tdso; *pary)
    177         {
    178             if (tdso._addCnt)
    179             {
    180                 auto handle = tdso._pdso._handle;
    181                 safeAssert(handle !is null, "Invalid library handle.");
    182                 .FreeLibrary(handle);
    183             }
    184         }
    185         pary.reset();
    186         .free(pary);
    187     }
    188 
    189     // Called before TLS ctors are ran, copy over the loaded libraries
    190     // of the parent thread.
    191     pragma(mangle, gcc.sections.inheritLoadedLibraries.mangleof)
    192     void inheritLoadedLibraries(void* p) nothrow @nogc
    193     {
    194         safeAssert(_loadedDSOs.empty, "DSOs have already been registered for this thread.");
    195         _loadedDSOs.swap(*cast(Array!(ThreadDSO)*)p);
    196         .free(p);
    197     }
    198 
    199     // Called after all TLS dtors ran, decrements all remaining DLL refs.
    200     pragma(mangle, gcc.sections.cleanupLoadedLibraries.mangleof)
    201     void cleanupLoadedLibraries() nothrow @nogc
    202     {
    203         foreach (ref tdso; _loadedDSOs)
    204         {
    205             if (tdso._addCnt == 0) continue;
    206 
    207             auto handle = tdso._pdso._handle;
    208             safeAssert(handle !is null, "Invalid DSO handle.");
    209             for (; tdso._addCnt > 0; --tdso._addCnt)
    210                 .FreeLibrary(handle);
    211         }
    212 
    213         // Free the memory for the array contents.
    214         _loadedDSOs.reset();
    215     }
    216 }
    217 else
    218 {
    219     /***
    220      * Called once per thread; returns array of thread local storage ranges
    221      */
    222     Array!(void[])* initTLSRanges() nothrow @nogc
    223     {
    224         return null;
    225     }
    226 
    227     void finiTLSRanges(Array!(void[])* rngs) nothrow @nogc
    228     {
    229     }
    230 
    231     void scanTLSRanges(Array!(void[])* rngs, scope ScanDG dg) nothrow
    232     {
    233         version (GNU_EMUTLS)
    234             _d_emutls_scan(dg);
    235         else
    236             static assert(0, "Native TLS unimplemented");
    237     }
    238 }
    239 
    240 private:
    241 
    242 version (Shared)
    243 {
    244     /*
    245      * Array of thread local DSO metadata for all libraries loaded and
    246      * initialized in this thread.
    247      *
    248      * Note:
    249      *     A newly spawned thread will inherit these libraries.
    250      * Note:
    251      *     We use an array here to preserve the order of
    252      *     initialization.  If that became a performance issue, we
    253      *     could use a hash table and enumerate the DSOs during
    254      *     loading so that the hash table values could be sorted when
    255      *     necessary.
    256      */
    257     struct ThreadDSO
    258     {
    259         DSO* _pdso;
    260         static if (_pdso.sizeof == 8) uint _refCnt, _addCnt;
    261         else static if (_pdso.sizeof == 4) ushort _refCnt, _addCnt;
    262         else static assert(0, "unimplemented");
    263         alias _pdso this;
    264     }
    265 
    266     @property ref Array!(ThreadDSO) _loadedDSOs() @nogc nothrow
    267     {
    268         static Array!(ThreadDSO) x;
    269         return x;
    270     }
    271 
    272     /*
    273      * Set to true during rt_loadLibrary/rt_unloadLibrary calls.
    274      */
    275     bool _rtLoading;
    276 
    277     /*
    278      * Hash table to map the native handle (as returned by dlopen)
    279      * to the corresponding DSO*, protected by a mutex.
    280      */
    281     __gshared CRITICAL_SECTION _handleToDSOMutex;
    282     @property ref HashTab!(void*, DSO*) _handleToDSO() @nogc nothrow
    283     {
    284         __gshared HashTab!(void*, DSO*) x;
    285         return x;
    286     }
    287 }
    288 else
    289 {
    290     /*
    291      * Static DSOs loaded by the runtime linker. This includes the
    292      * executable. These can't be unloaded.
    293      */
    294     @property ref Array!(DSO*) _loadedDSOs() @nogc nothrow
    295     {
    296         __gshared Array!(DSO*) x;
    297         return x;
    298     }
    299 
    300     enum _rtLoading = false;
    301 }
    302 
    303 ///////////////////////////////////////////////////////////////////////////////
    304 // Compiler to runtime interface.
    305 ///////////////////////////////////////////////////////////////////////////////
    306 
    307 /****
    308  * This data structure is generated by the compiler, and then passed to
    309  * _d_dso_registry().
    310  */
    311 struct CompilerDSOData
    312 {
    313     size_t _version;                                       // currently 1
    314     void** _slot;                                          // can be used to store runtime data
    315     immutable(object.ModuleInfo*)* _minfo_beg, _minfo_end; // array of modules in this object file
    316 }
    317 
    318 T[] toRange(T)(T* beg, T* end) { return beg[0 .. end - beg]; }
    319 
    320 /* For each shared library and executable, the compiler generates code that
    321  * sets up CompilerDSOData and calls _d_dso_registry().
    322  * A pointer to that code is inserted into both the .ctors and .dtors
    323  * segment so it gets called by the loader on startup and shutdown.
    324  */
    325 extern(C) void _d_dso_registry(CompilerDSOData* data)
    326 {
    327     // only one supported currently
    328     safeAssert(data._version >= 1, "Incompatible compiler-generated DSO data version.");
    329 
    330     // no backlink => register
    331     if (*data._slot is null)
    332     {
    333         immutable firstDSO = _loadedDSOs.empty;
    334         if (firstDSO) initLocks();
    335 
    336         DSO* pdso = cast(DSO*).calloc(1, DSO.sizeof);
    337         assert(typeid(DSO).initializer().ptr is null);
    338         pdso._slot = data._slot;
    339         *data._slot = pdso; // store backlink in library record
    340 
    341         pdso._moduleGroup = ModuleGroup(toRange(data._minfo_beg, data._minfo_end));
    342 
    343         HMODULE handle = void;
    344         const moduleFound = findModuleHandleForAddr(data._slot, handle);
    345         safeAssert(moduleFound, "Failed to find image header.");
    346 
    347         scanSegments(handle, pdso);
    348 
    349         version (Shared)
    350         {
    351             getDependencies(handle, pdso._deps);
    352             pdso._handle = handle;
    353             setDSOForHandle(pdso, pdso._handle);
    354 
    355             if (!_rtLoading)
    356             {
    357                 /* This DSO was not loaded by rt_loadLibrary which
    358                  * happens for all dependencies of an executable or
    359                  * the first dlopen call from a C program.
    360                  * In this case we add the DSO to the _loadedDSOs of this
    361                  * thread with a refCnt of 1 and call the TlsCtors.
    362                  */
    363                 immutable ushort refCnt = 1, addCnt = 0;
    364                 _loadedDSOs.insertBack(ThreadDSO(pdso, refCnt, addCnt));
    365             }
    366         }
    367         else
    368         {
    369             foreach (p; _loadedDSOs)
    370                 safeAssert(p !is pdso, "DSO already registered.");
    371             _loadedDSOs.insertBack(pdso);
    372         }
    373 
    374         // don't initialize modules before rt_init was called
    375         if (_isRuntimeInitialized)
    376         {
    377             registerGCRanges(pdso);
    378             // rt_loadLibrary will run tls ctors, so do this only for dlopen
    379             immutable runTlsCtors = !_rtLoading;
    380             runModuleConstructors(pdso, runTlsCtors);
    381         }
    382     }
    383     // has backlink => unregister
    384     else
    385     {
    386         DSO* pdso = cast(DSO*)*data._slot;
    387         *data._slot = null;
    388 
    389         // don't finalizes modules after rt_term was called (see Bugzilla 11378)
    390         if (_isRuntimeInitialized)
    391         {
    392             // rt_unloadLibrary already ran tls dtors, so do this only for dlclose
    393             immutable runTlsDtors = !_rtLoading;
    394             runModuleDestructors(pdso, runTlsDtors);
    395             unregisterGCRanges(pdso);
    396             // run finalizers after module dtors (same order as in rt_term)
    397             version (Shared) runFinalizers(pdso);
    398         }
    399 
    400         version (Shared)
    401         {
    402             if (!_rtLoading)
    403             {
    404                 /* This DSO was not unloaded by rt_unloadLibrary so we
    405                  * have to remove it from _loadedDSOs here.
    406                  */
    407                 foreach (i, ref tdso; _loadedDSOs)
    408                 {
    409                     if (tdso._pdso == pdso)
    410                     {
    411                         _loadedDSOs.remove(i);
    412                         break;
    413                     }
    414                 }
    415             }
    416 
    417             unsetDSOForHandle(pdso, pdso._handle);
    418         }
    419         else
    420         {
    421             // static DSOs are unloaded in reverse order
    422             safeAssert(pdso == _loadedDSOs.back, "DSO being unregistered isn't current last one.");
    423             _loadedDSOs.popBack();
    424         }
    425 
    426         freeDSO(pdso);
    427 
    428         // last DSO being unloaded => shutdown registry
    429         if (_loadedDSOs.empty)
    430         {
    431             version (GNU_EMUTLS)
    432                 _d_emutls_destroy();
    433             version (Shared)
    434             {
    435                 safeAssert(_handleToDSO.empty, "_handleToDSO not in sync with _loadedDSOs.");
    436                 _handleToDSO.reset();
    437             }
    438             finiLocks();
    439         }
    440     }
    441 }
    442 
    443 ///////////////////////////////////////////////////////////////////////////////
    444 // dynamic loading
    445 ///////////////////////////////////////////////////////////////////////////////
    446 
    447 // Shared D libraries are only supported when linking against a shared druntime library.
    448 
    449 version (Shared)
    450 {
    451     ThreadDSO* findThreadDSO(DSO* pdso) nothrow @nogc
    452     {
    453         foreach (ref tdata; _loadedDSOs)
    454             if (tdata._pdso == pdso) return &tdata;
    455         return null;
    456     }
    457 
    458     void incThreadRef(DSO* pdso, bool incAdd)
    459     {
    460         if (auto tdata = findThreadDSO(pdso)) // already initialized
    461         {
    462             if (incAdd && ++tdata._addCnt > 1) return;
    463             ++tdata._refCnt;
    464         }
    465         else
    466         {
    467             foreach (dep; pdso._deps)
    468                 incThreadRef(dep, false);
    469             immutable ushort refCnt = 1, addCnt = incAdd ? 1 : 0;
    470             _loadedDSOs.insertBack(ThreadDSO(pdso, refCnt, addCnt));
    471             pdso._moduleGroup.runTlsCtors();
    472         }
    473     }
    474 
    475     void decThreadRef(DSO* pdso, bool decAdd)
    476     {
    477         auto tdata = findThreadDSO(pdso);
    478         safeAssert(tdata !is null, "Failed to find thread DSO.");
    479         safeAssert(!decAdd || tdata._addCnt > 0, "Mismatching rt_unloadLibrary call.");
    480 
    481         if (decAdd && --tdata._addCnt > 0) return;
    482         if (--tdata._refCnt > 0) return;
    483 
    484         pdso._moduleGroup.runTlsDtors();
    485         foreach (i, ref td; _loadedDSOs)
    486             if (td._pdso == pdso) _loadedDSOs.remove(i);
    487         foreach (dep; pdso._deps)
    488             decThreadRef(dep, false);
    489     }
    490 }
    491 
    492 /***********************************
    493  * These are a temporary means of providing a GC hook for DLL use.  They may be
    494  * replaced with some other similar functionality later.
    495  */
    496 extern (C)
    497 {
    498     void* gc_getProxy();
    499     void  gc_setProxy(void* p);
    500     void  gc_clrProxy();
    501 
    502     alias void  function(void*) gcSetFn;
    503     alias void  function()      gcClrFn;
    504 }
    505 
    506 /*******************************************
    507  * Loads a DLL written in D with the name 'name'.
    508  * Returns:
    509  *      opaque handle to the DLL if successfully loaded
    510  *      null if failure
    511  */
    512 extern(C) void* rt_loadLibrary(const char* name)
    513 {
    514     version (Shared)
    515     {
    516         immutable save = _rtLoading;
    517         _rtLoading = true;
    518         scope (exit) _rtLoading = save;
    519     }
    520     return initLibrary(.LoadLibraryA(name));
    521 }
    522 
    523 extern (C) void* rt_loadLibraryW(const wchar_t* name)
    524 {
    525     version (Shared)
    526     {
    527         immutable save = _rtLoading;
    528         _rtLoading = true;
    529         scope (exit) _rtLoading = save;
    530     }
    531     return initLibrary(.LoadLibraryW(name));
    532 }
    533 
    534 void* initLibrary(void* handle)
    535 {
    536     if (handle is null)
    537         return null;
    538 
    539     version (Shared)
    540     {
    541         // if it's a D library
    542         if (auto pdso = dsoForHandle(handle))
    543             incThreadRef(pdso, true);
    544     }
    545     gcSetFn gcSet = cast(gcSetFn) GetProcAddress(handle, "gc_setProxy");
    546     if (gcSet !is null)
    547     {
    548         // BUG: Set proxy, but too late
    549         gcSet(gc_getProxy());
    550     }
    551     return handle;
    552 }
    553 
    554 /*************************************
    555  * Unloads DLL that was previously loaded by rt_loadLibrary().
    556  * Input:
    557  *      handle  the handle returned by rt_loadLibrary()
    558  * Returns:
    559  *      1   succeeded
    560  *      0   some failure happened
    561  */
    562 extern(C) int rt_unloadLibrary(void* handle)
    563 {
    564     if (handle is null)
    565         return false;
    566 
    567     version (Shared)
    568     {
    569         immutable save = _rtLoading;
    570         _rtLoading = true;
    571         scope (exit) _rtLoading = save;
    572 
    573         // if it's a D library
    574         if (auto pdso = dsoForHandle(handle))
    575             decThreadRef(pdso, true);
    576     }
    577     gcClrFn gcClr  = cast(gcClrFn) GetProcAddress(handle, "gc_clrProxy");
    578     if (gcClr !is null)
    579         gcClr();
    580     return .FreeLibrary(handle) != 0;
    581 }
    582 
    583 ///////////////////////////////////////////////////////////////////////////////
    584 // helper functions
    585 ///////////////////////////////////////////////////////////////////////////////
    586 
    587 void initLocks() nothrow @nogc
    588 {
    589     version (Shared)
    590         InitializeCriticalSection(&_handleToDSOMutex);
    591 }
    592 
    593 void finiLocks() nothrow @nogc
    594 {
    595     version (Shared)
    596         DeleteCriticalSection(&_handleToDSOMutex);
    597 }
    598 
    599 void runModuleConstructors(DSO* pdso, bool runTlsCtors)
    600 {
    601     pdso._moduleGroup.sortCtors();
    602     pdso._moduleGroup.runCtors();
    603     if (runTlsCtors) pdso._moduleGroup.runTlsCtors();
    604 }
    605 
    606 void runModuleDestructors(DSO* pdso, bool runTlsDtors)
    607 {
    608     if (runTlsDtors) pdso._moduleGroup.runTlsDtors();
    609     pdso._moduleGroup.runDtors();
    610 }
    611 
    612 void registerGCRanges(DSO* pdso) nothrow @nogc
    613 {
    614     foreach (rng; pdso._gcRanges)
    615         GC.addRange(rng.ptr, rng.length);
    616 }
    617 
    618 void unregisterGCRanges(DSO* pdso) nothrow @nogc
    619 {
    620     foreach (rng; pdso._gcRanges)
    621         GC.removeRange(rng.ptr);
    622 }
    623 
    624 version (Shared) void runFinalizers(DSO* pdso)
    625 {
    626     foreach (seg; pdso._codeSegments)
    627         GC.runFinalizers(seg);
    628 }
    629 
    630 void freeDSO(DSO* pdso) nothrow @nogc
    631 {
    632     pdso._gcRanges.reset();
    633     version (Shared)
    634     {
    635         pdso._codeSegments.reset();
    636         pdso._deps.reset();
    637         pdso._handle = null;
    638     }
    639     .free(pdso);
    640 }
    641 
    642 version (Shared)
    643 {
    644 @nogc nothrow:
    645     const(char)* nameForDSO(DSO* pdso, ref char[] buffer)
    646     {
    647         const success = GetModuleFileNameA(pdso._handle, buffer.ptr, cast(DWORD)buffer.length) != 0;
    648         safeAssert(success, "Failed to get DLL name.");
    649         return buffer.ptr;
    650     }
    651 
    652     DSO* dsoForHandle(in void* handle)
    653     {
    654         DSO* pdso;
    655         .EnterCriticalSection(&_handleToDSOMutex);
    656         if (auto ppdso = handle in _handleToDSO)
    657             pdso = *ppdso;
    658         .LeaveCriticalSection(&_handleToDSOMutex);
    659         return pdso;
    660     }
    661 
    662     void setDSOForHandle(DSO* pdso, void* handle)
    663     {
    664         .EnterCriticalSection(&_handleToDSOMutex);
    665         safeAssert(handle !in _handleToDSO, "DSO already registered.");
    666         _handleToDSO[handle] = pdso;
    667         .LeaveCriticalSection(&_handleToDSOMutex);
    668     }
    669 
    670     void unsetDSOForHandle(DSO* pdso, void* handle)
    671     {
    672         .EnterCriticalSection(&_handleToDSOMutex);
    673         safeAssert(_handleToDSO[handle] == pdso, "Handle doesn't match registered DSO.");
    674         _handleToDSO.remove(handle);
    675         .LeaveCriticalSection(&_handleToDSOMutex);
    676     }
    677 
    678     void getDependencies(in HMODULE handle, ref Array!(DSO*) deps)
    679     {
    680         auto nthdr = getNTHeader(handle);
    681         auto import_entry = nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
    682         auto addr = import_entry.VirtualAddress;
    683         auto datasize = import_entry.Size;
    684 
    685         if (addr == 0 && datasize == 0)
    686         {
    687             // Maybe the optional header isn't there, look for the section.
    688             foreach (section; getSectionHeader(handle))
    689             {
    690                 if (!compareSectionName(section, ".idata"))
    691                     continue;
    692                 addr = section.VirtualAddress;
    693                 datasize = section.Misc.VirtualSize;
    694                 break;
    695             }
    696             if (datasize == 0)
    697                 return;
    698         }
    699         else
    700         {
    701             bool foundSection = false;
    702             foreach (section; getSectionHeader(handle))
    703             {
    704                 if (!compareSectionName(section, ".idata"))
    705                     continue;
    706                 // Section containing import table has no contents.
    707                 if (section.Misc.VirtualSize == 0)
    708                     return;
    709                 foundSection = true;
    710                 break;
    711             }
    712             // There is an import table, but the section containing it could not be found
    713             if (!foundSection)
    714                 return;
    715         }
    716 
    717         // Get the names of each DLL
    718         for (uint i = 0; i + IMAGE_IMPORT_DESCRIPTOR.sizeof <= datasize;
    719              i += IMAGE_IMPORT_DESCRIPTOR.sizeof)
    720         {
    721             const data = cast(PIMAGE_IMPORT_DESCRIPTOR)(handle + addr + i);
    722             if (data.Name == 0)
    723                 break;
    724 
    725             // dll name of dependency
    726             auto name = cast(char*)(handle + data.Name);
    727             // get handle without loading the library
    728             auto libhandle = handleForName(name);
    729             // the runtime linker has already loaded all dependencies
    730             safeAssert(handle !is null, "Failed to get library handle.");
    731             // if it's a D library
    732             if (auto pdso = dsoForHandle(handle))
    733                 deps.insertBack(pdso); // append it to the dependencies
    734         }
    735     }
    736 
    737     void* handleForName(const char* name)
    738     {
    739         return GetModuleHandleA(name);
    740     }
    741 }
    742 
    743 ///////////////////////////////////////////////////////////////////////////////
    744 // PE/COFF program header iteration
    745 ///////////////////////////////////////////////////////////////////////////////
    746 
    747 bool compareSectionName(ref IMAGE_SECTION_HEADER section, string name) nothrow @nogc
    748 {
    749     if (name[] != cast(char[])section.Name[0 .. name.length])
    750         return false;
    751     return name.length == 8 || section.Name[name.length] == 0;
    752 }
    753 
    754 /************
    755  * Scan segments in the image header and store
    756  * the writeable data segments in *pdso.
    757  */
    758 
    759 void scanSegments(in HMODULE handle, DSO* pdso) nothrow @nogc
    760 {
    761     foreach (section; getSectionHeader(handle))
    762     {
    763         // the ".data" image section includes both object file sections ".data" and ".bss"
    764         if (compareSectionName(section, ".data"))
    765         {
    766             auto data = cast(void*)handle + section.VirtualAddress;
    767             pdso._gcRanges.insertBack(data[0 .. section.Misc.VirtualSize]);
    768             continue;
    769         }
    770 
    771         version (Shared)
    772         {
    773             if (compareSectionName(section, ".text"))
    774             {
    775                 auto text = cast(void*)handle + section.VirtualAddress;
    776                 pdso._codeSegments.insertBack(text[0 .. section.Misc.VirtualSize]);
    777                 continue;
    778             }
    779         }
    780     }
    781 }
    782 
    783 /**************************
    784  * Input:
    785  *      handle  where the output is to be written
    786  * Returns:
    787  *      true if found, and *handle is filled in
    788  */
    789 
    790 bool findModuleHandleForAddr(in void* addr, out HMODULE handle) nothrow @nogc
    791 {
    792     if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
    793                            cast(const(wchar)*) addr, &handle))
    794         return true;
    795 
    796     return false;
    797 }
    798 
    799 /**
    800  * Returns the image NT header for the HMODULE handle passed,
    801  * or null if not found.
    802  */
    803 PIMAGE_NT_HEADERS getNTHeader(in HMODULE handle) nothrow @nogc
    804 {
    805     auto doshdr = cast(PIMAGE_DOS_HEADER)handle;
    806     if (doshdr.e_magic != IMAGE_DOS_SIGNATURE)
    807         return null;
    808 
    809     return cast(typeof(return))(cast(void*)doshdr + doshdr.e_lfanew);
    810 }
    811 
    812 /**
    813  * Returns the image section header for the HMODULE handle passed,
    814  * or null if not found.
    815  */
    816 IMAGE_SECTION_HEADER[] getSectionHeader(in HMODULE handle) nothrow @nogc
    817 {
    818     if (auto nthdr = getNTHeader(handle))
    819     {
    820         const void* opthdr = &nthdr.OptionalHeader;
    821         const offset = nthdr.FileHeader.SizeOfOptionalHeader;
    822         const length = nthdr.FileHeader.NumberOfSections;
    823         return (cast(PIMAGE_SECTION_HEADER)(opthdr + offset))[0 .. length];
    824     }
    825     return null;
    826 }
    827