aboutsummaryrefslogtreecommitdiff
path: root/libphobos
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2021-04-08 16:11:16 +0200
committerIain Buclaw <ibuclaw@gdcproject.org>2021-04-10 15:02:07 +0200
commit32703b80f66f7ca504eb79bee7e745f22cf096a8 (patch)
tree1954456b1d2e6a84ccc6a9846f2211f4fb60d596 /libphobos
parent385ee099eeae53bff5dd5adf673ad4f4b8d22981 (diff)
downloadgcc-32703b80f66f7ca504eb79bee7e745f22cf096a8.zip
gcc-32703b80f66f7ca504eb79bee7e745f22cf096a8.tar.gz
gcc-32703b80f66f7ca504eb79bee7e745f22cf096a8.tar.bz2
libphobos: Add section support code for MACHO and PE/COFF
This replaces the original and untested support for Windows and OSX, and is the 90% of the work needed to support libphobos on those targets. The core.thread interface has been updated to accomodate for the same function might be implemented by any of the platform-dependent modules. libphobos/ChangeLog: * libdruntime/Makefile.am (DRUNTIME_DSOURCES): Removed gcc/sections/android.d, elf_shared.d, osx.d, win32.d, and win64.d. Added gcc/sections/common.d, elf.d macho.d, and pecoff.d. * libdruntime/Makefile.in: Regenerate. * libdruntime/core/thread/osthread.d: Update externDFunc FQDN names to use platform independant section function names. * libdruntime/gcc/sections/elf_shared.d: Renamed to... * libdruntime/gcc/sections/elf.d: ...this. Mangle functions for core.thread interface as if they come from the gcc.sections module. * libdruntime/gcc/sections/package.d: Update public imports, declare functions for core.thread interface. * libdruntime/gcc/sections/android.d: Removed. * libdruntime/gcc/sections/osx.d: Removed. * libdruntime/gcc/sections/win32.d: Removed. * libdruntime/gcc/sections/win64.d: Removed. * libdruntime/gcc/sections/common.d: New file. * libdruntime/gcc/sections/macho.d: New file. * libdruntime/gcc/sections/pecoff.d: New file.
Diffstat (limited to 'libphobos')
-rw-r--r--libphobos/libdruntime/Makefile.am23
-rw-r--r--libphobos/libdruntime/Makefile.in39
-rw-r--r--libphobos/libdruntime/core/thread/osthread.d10
-rw-r--r--libphobos/libdruntime/gcc/sections/android.d184
-rw-r--r--libphobos/libdruntime/gcc/sections/common.d39
-rw-r--r--libphobos/libdruntime/gcc/sections/elf.d (renamed from libphobos/libdruntime/gcc/sections/elf_shared.d)71
-rw-r--r--libphobos/libdruntime/gcc/sections/macho.d738
-rw-r--r--libphobos/libdruntime/gcc/sections/osx.d284
-rw-r--r--libphobos/libdruntime/gcc/sections/package.d47
-rw-r--r--libphobos/libdruntime/gcc/sections/pecoff.d826
-rw-r--r--libphobos/libdruntime/gcc/sections/win32.d183
-rw-r--r--libphobos/libdruntime/gcc/sections/win64.d321
12 files changed, 1673 insertions, 1092 deletions
diff --git a/libphobos/libdruntime/Makefile.am b/libphobos/libdruntime/Makefile.am
index 5137f85..74a0f00 100644
--- a/libphobos/libdruntime/Makefile.am
+++ b/libphobos/libdruntime/Makefile.am
@@ -186,18 +186,17 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \
gc/gcinterface.d gc/impl/conservative/gc.d gc/impl/manual/gc.d gc/os.d \
gc/pooltable.d gc/proxy.d gcc/attribute.d gcc/attributes.d \
gcc/backtrace.d gcc/builtins.d gcc/deh.d gcc/emutls.d gcc/gthread.d \
- gcc/sections/android.d gcc/sections/elf_shared.d gcc/sections/osx.d \
- gcc/sections/package.d gcc/sections/win32.d gcc/sections/win64.d \
- gcc/unwind/arm.d gcc/unwind/arm_common.d gcc/unwind/c6x.d \
- gcc/unwind/generic.d gcc/unwind/package.d gcc/unwind/pe.d object.d \
- rt/aApply.d rt/aApplyR.d rt/aaA.d rt/adi.d rt/arrayassign.d \
- rt/arraycast.d rt/arraycat.d rt/cast_.d rt/config.d rt/critical_.d \
- rt/deh.d rt/dmain2.d rt/invariant.d rt/lifetime.d rt/memory.d \
- rt/minfo.d rt/monitor_.d rt/obj.d rt/qsort.d rt/sections.d \
- rt/switch_.d rt/tlsgc.d rt/util/array.d rt/util/container/array.d \
- rt/util/container/common.d rt/util/container/hashtab.d \
- rt/util/container/treap.d rt/util/random.d rt/util/typeinfo.d \
- rt/util/utf.d
+ gcc/sections/common.d gcc/sections/elf.d gcc/sections/macho.d \
+ gcc/sections/package.d gcc/sections/pecoff.d gcc/unwind/arm.d \
+ gcc/unwind/arm_common.d gcc/unwind/c6x.d gcc/unwind/generic.d \
+ gcc/unwind/package.d gcc/unwind/pe.d object.d rt/aApply.d rt/aApplyR.d \
+ rt/aaA.d rt/adi.d rt/arrayassign.d rt/arraycast.d rt/arraycat.d \
+ rt/cast_.d rt/config.d rt/critical_.d rt/deh.d rt/dmain2.d \
+ rt/invariant.d rt/lifetime.d rt/memory.d rt/minfo.d rt/monitor_.d \
+ rt/obj.d rt/qsort.d rt/sections.d rt/switch_.d rt/tlsgc.d \
+ rt/util/array.d rt/util/container/array.d rt/util/container/common.d \
+ rt/util/container/hashtab.d rt/util/container/treap.d rt/util/random.d \
+ rt/util/typeinfo.d rt/util/utf.d
DRUNTIME_DSOURCES_STDCXX = core/stdcpp/exception.d \
core/stdcpp/typeinfo.d
diff --git a/libphobos/libdruntime/Makefile.in b/libphobos/libdruntime/Makefile.in
index 4a93b49..63b2133 100644
--- a/libphobos/libdruntime/Makefile.in
+++ b/libphobos/libdruntime/Makefile.in
@@ -211,10 +211,9 @@ am__objects_1 = core/atomic.lo core/attribute.lo core/bitop.lo \
gc/impl/conservative/gc.lo gc/impl/manual/gc.lo gc/os.lo \
gc/pooltable.lo gc/proxy.lo gcc/attribute.lo gcc/attributes.lo \
gcc/backtrace.lo gcc/builtins.lo gcc/deh.lo gcc/emutls.lo \
- gcc/gthread.lo gcc/sections/android.lo \
- gcc/sections/elf_shared.lo gcc/sections/osx.lo \
- gcc/sections/package.lo gcc/sections/win32.lo \
- gcc/sections/win64.lo gcc/unwind/arm.lo \
+ gcc/gthread.lo gcc/sections/common.lo gcc/sections/elf.lo \
+ gcc/sections/macho.lo gcc/sections/package.lo \
+ gcc/sections/pecoff.lo gcc/unwind/arm.lo \
gcc/unwind/arm_common.lo gcc/unwind/c6x.lo \
gcc/unwind/generic.lo gcc/unwind/package.lo gcc/unwind/pe.lo \
object.lo rt/aApply.lo rt/aApplyR.lo rt/aaA.lo rt/adi.lo \
@@ -819,18 +818,17 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \
gc/gcinterface.d gc/impl/conservative/gc.d gc/impl/manual/gc.d gc/os.d \
gc/pooltable.d gc/proxy.d gcc/attribute.d gcc/attributes.d \
gcc/backtrace.d gcc/builtins.d gcc/deh.d gcc/emutls.d gcc/gthread.d \
- gcc/sections/android.d gcc/sections/elf_shared.d gcc/sections/osx.d \
- gcc/sections/package.d gcc/sections/win32.d gcc/sections/win64.d \
- gcc/unwind/arm.d gcc/unwind/arm_common.d gcc/unwind/c6x.d \
- gcc/unwind/generic.d gcc/unwind/package.d gcc/unwind/pe.d object.d \
- rt/aApply.d rt/aApplyR.d rt/aaA.d rt/adi.d rt/arrayassign.d \
- rt/arraycast.d rt/arraycat.d rt/cast_.d rt/config.d rt/critical_.d \
- rt/deh.d rt/dmain2.d rt/invariant.d rt/lifetime.d rt/memory.d \
- rt/minfo.d rt/monitor_.d rt/obj.d rt/qsort.d rt/sections.d \
- rt/switch_.d rt/tlsgc.d rt/util/array.d rt/util/container/array.d \
- rt/util/container/common.d rt/util/container/hashtab.d \
- rt/util/container/treap.d rt/util/random.d rt/util/typeinfo.d \
- rt/util/utf.d
+ gcc/sections/common.d gcc/sections/elf.d gcc/sections/macho.d \
+ gcc/sections/package.d gcc/sections/pecoff.d gcc/unwind/arm.d \
+ gcc/unwind/arm_common.d gcc/unwind/c6x.d gcc/unwind/generic.d \
+ gcc/unwind/package.d gcc/unwind/pe.d object.d rt/aApply.d rt/aApplyR.d \
+ rt/aaA.d rt/adi.d rt/arrayassign.d rt/arraycast.d rt/arraycat.d \
+ rt/cast_.d rt/config.d rt/critical_.d rt/deh.d rt/dmain2.d \
+ rt/invariant.d rt/lifetime.d rt/memory.d rt/minfo.d rt/monitor_.d \
+ rt/obj.d rt/qsort.d rt/sections.d rt/switch_.d rt/tlsgc.d \
+ rt/util/array.d rt/util/container/array.d rt/util/container/common.d \
+ rt/util/container/hashtab.d rt/util/container/treap.d rt/util/random.d \
+ rt/util/typeinfo.d rt/util/utf.d
DRUNTIME_DSOURCES_STDCXX = core/stdcpp/exception.d \
core/stdcpp/typeinfo.d
@@ -1219,12 +1217,11 @@ gcc/gthread.lo: gcc/$(am__dirstamp)
gcc/sections/$(am__dirstamp):
@$(MKDIR_P) gcc/sections
@: > gcc/sections/$(am__dirstamp)
-gcc/sections/android.lo: gcc/sections/$(am__dirstamp)
-gcc/sections/elf_shared.lo: gcc/sections/$(am__dirstamp)
-gcc/sections/osx.lo: gcc/sections/$(am__dirstamp)
+gcc/sections/common.lo: gcc/sections/$(am__dirstamp)
+gcc/sections/elf.lo: gcc/sections/$(am__dirstamp)
+gcc/sections/macho.lo: gcc/sections/$(am__dirstamp)
gcc/sections/package.lo: gcc/sections/$(am__dirstamp)
-gcc/sections/win32.lo: gcc/sections/$(am__dirstamp)
-gcc/sections/win64.lo: gcc/sections/$(am__dirstamp)
+gcc/sections/pecoff.lo: gcc/sections/$(am__dirstamp)
gcc/unwind/$(am__dirstamp):
@$(MKDIR_P) gcc/unwind
@: > gcc/unwind/$(am__dirstamp)
diff --git a/libphobos/libdruntime/core/thread/osthread.d b/libphobos/libdruntime/core/thread/osthread.d
index defdc95..880836e 100644
--- a/libphobos/libdruntime/core/thread/osthread.d
+++ b/libphobos/libdruntime/core/thread/osthread.d
@@ -510,7 +510,7 @@ class Thread : ThreadBase
{
version (GNU)
{
- auto libs = externDFunc!("gcc.sections.elf_shared.pinLoadedLibraries",
+ auto libs = externDFunc!("gcc.sections.pinLoadedLibraries",
void* function() @nogc nothrow)();
}
else
@@ -527,7 +527,7 @@ class Thread : ThreadBase
{
version (GNU)
{
- externDFunc!("gcc.sections.elf_shared.unpinLoadedLibraries",
+ externDFunc!("gcc.sections.unpinLoadedLibraries",
void function(void*) @nogc nothrow)(libs);
}
else
@@ -2196,7 +2196,7 @@ else version (Posix)
// before initilizing GC for TLS (rt_tlsgc_init)
version (GNUShared)
{
- externDFunc!("gcc.sections.elf_shared.inheritLoadedLibraries",
+ externDFunc!("gcc.sections.inheritLoadedLibraries",
void function(void*) @nogc nothrow)(loadedLibraries);
}
else version (Shared)
@@ -2287,7 +2287,7 @@ else version (Posix)
rt_moduleTlsDtor();
version (GNUShared)
{
- externDFunc!("gcc.sections.elf_shared.cleanupLoadedLibraries",
+ externDFunc!("gcc.sections.cleanupLoadedLibraries",
void function() @nogc nothrow)();
}
else version (Shared)
@@ -2786,7 +2786,7 @@ private size_t adjustStackSize(size_t sz) nothrow @nogc
// On glibc, TLS uses the top of the stack, so add its size to the requested size
version (GNU)
{
- sz += externDFunc!("gcc.sections.elf_shared.sizeOfTLS",
+ sz += externDFunc!("gcc.sections.elf.sizeOfTLS",
size_t function() @nogc nothrow)();
}
else
diff --git a/libphobos/libdruntime/gcc/sections/android.d b/libphobos/libdruntime/gcc/sections/android.d
deleted file mode 100644
index 4af26b4..0000000
--- a/libphobos/libdruntime/gcc/sections/android.d
+++ /dev/null
@@ -1,184 +0,0 @@
-// Bionic-specific support for sections.
-// Copyright (C) 2019-2021 Free Software Foundation, Inc.
-
-// GCC is free software; you can redistribute it and/or modify it under
-// the terms of the GNU General Public License as published by the Free
-// Software Foundation; either version 3, or (at your option) any later
-// version.
-
-// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-// WARRANTY; without even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-// for more details.
-
-// Under Section 7 of GPL version 3, you are granted additional
-// permissions described in the GCC Runtime Library Exception, version
-// 3.1, as published by the Free Software Foundation.
-
-// You should have received a copy of the GNU General Public License and
-// a copy of the GCC Runtime Library Exception along with this program;
-// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
-// <http://www.gnu.org/licenses/>.
-
-module gcc.sections.android;
-
-version (CRuntime_Bionic):
-
-// debug = PRINTF;
-debug(PRINTF) import core.stdc.stdio;
-import core.stdc.stdlib : malloc, free;
-import rt.deh, rt.minfo;
-import core.sys.posix.pthread;
-import core.stdc.stdlib : calloc;
-import core.stdc.string : memcpy;
-
-struct SectionGroup
-{
- static int opApply(scope int delegate(ref SectionGroup) dg)
- {
- return dg(_sections);
- }
-
- static int opApplyReverse(scope int delegate(ref SectionGroup) dg)
- {
- return dg(_sections);
- }
-
- @property immutable(ModuleInfo*)[] modules() const nothrow @nogc
- {
- return _moduleGroup.modules;
- }
-
- @property ref inout(ModuleGroup) moduleGroup() inout nothrow @nogc
- {
- return _moduleGroup;
- }
-
- @property immutable(FuncTable)[] ehTables() const nothrow @nogc
- {
- auto pbeg = cast(immutable(FuncTable)*)&__start_deh;
- auto pend = cast(immutable(FuncTable)*)&__stop_deh;
- return pbeg[0 .. pend - pbeg];
- }
-
- @property inout(void[])[] gcRanges() inout nothrow @nogc
- {
- return _gcRanges[];
- }
-
-private:
- ModuleGroup _moduleGroup;
- void[][1] _gcRanges;
-}
-
-void initSections() nothrow @nogc
-{
- pthread_key_create(&_tlsKey, null);
-
- auto mbeg = cast(immutable ModuleInfo**)&__start_minfo;
- auto mend = cast(immutable ModuleInfo**)&__stop_minfo;
- _sections.moduleGroup = ModuleGroup(mbeg[0 .. mend - mbeg]);
-
- auto pbeg = cast(void*)&_tlsend;
- auto pend = cast(void*)&__bss_end__;
- // _tlsend is a 32-bit int and may not be 64-bit void*-aligned, so align pbeg.
- version (D_LP64) pbeg = cast(void*)(cast(size_t)(pbeg + 7) & ~cast(size_t)7);
- _sections._gcRanges[0] = pbeg[0 .. pend - pbeg];
-}
-
-void finiSections() nothrow @nogc
-{
- pthread_key_delete(_tlsKey);
-}
-
-void[]* initTLSRanges() nothrow @nogc
-{
- return &getTLSBlock();
-}
-
-void finiTLSRanges(void[]* rng) nothrow @nogc
-{
- .free(rng.ptr);
- .free(rng);
-}
-
-void scanTLSRanges(void[]* rng, scope void delegate(void* pbeg, void* pend) nothrow dg) nothrow
-{
- dg(rng.ptr, rng.ptr + rng.length);
-}
-
-/* NOTE: The Bionic C library ignores thread-local data stored in the normal
- * .tbss/.tdata ELF sections, which are marked with the SHF_TLS/STT_TLS
- * flags. So instead we roll our own by keeping TLS data in the
- * .tdata/.tbss sections but removing the SHF_TLS/STT_TLS flags, and
- * access the TLS data using this function and the _tlsstart/_tlsend
- * symbols as delimiters.
- *
- * This function is called by the code emitted by the compiler. It
- * is expected to translate an address in the TLS static data to
- * the corresponding address in the TLS dynamic per-thread data.
- */
-
-extern(C) void* __tls_get_addr( void* p ) nothrow @nogc
-{
- debug(PRINTF) printf(" __tls_get_addr input - %p\n", p);
- immutable offset = cast(size_t)(p - cast(void*)&_tlsstart);
- auto tls = getTLSBlockAlloc();
- assert(offset < tls.length);
- return tls.ptr + offset;
-}
-
-private:
-
-__gshared pthread_key_t _tlsKey;
-
-ref void[] getTLSBlock() nothrow @nogc
-{
- auto pary = cast(void[]*)pthread_getspecific(_tlsKey);
- if (pary is null)
- {
- pary = cast(void[]*).calloc(1, (void[]).sizeof);
- if (pthread_setspecific(_tlsKey, pary) != 0)
- {
- import core.stdc.stdio;
- perror("pthread_setspecific failed with");
- assert(0);
- }
- }
- return *pary;
-}
-
-ref void[] getTLSBlockAlloc() nothrow @nogc
-{
- auto pary = &getTLSBlock();
- if (!pary.length)
- {
- auto pbeg = cast(void*)&_tlsstart;
- auto pend = cast(void*)&_tlsend;
- auto p = .malloc(pend - pbeg);
- memcpy(p, pbeg, pend - pbeg);
- *pary = p[0 .. pend - pbeg];
- }
- return *pary;
-}
-
-__gshared SectionGroup _sections;
-
-extern(C)
-{
- /* Symbols created by the compiler/linker and inserted into the
- * object file that 'bracket' sections.
- */
- extern __gshared
- {
- void* __start_deh;
- void* __stop_deh;
- void* __start_minfo;
- void* __stop_minfo;
-
- size_t __bss_end__;
-
- int _tlsstart;
- int _tlsend;
- }
-}
diff --git a/libphobos/libdruntime/gcc/sections/common.d b/libphobos/libdruntime/gcc/sections/common.d
new file mode 100644
index 0000000..85fdc0e
--- /dev/null
+++ b/libphobos/libdruntime/gcc/sections/common.d
@@ -0,0 +1,39 @@
+// Contains various utility functions used by the runtime implementation.
+// Copyright (C) 2019-2021 Free Software Foundation, Inc.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+module gcc.sections.common;
+
+/**
+ * Asserts that the given condition is `true`.
+ *
+ * The assertion is independent from -release, by abort()ing. Regular assertions
+ * throw an AssertError and thus require an initialized GC, which might not be
+ * the case (yet or anymore) for the startup/shutdown code in this package
+ * (called by CRT ctors/dtors etc.).
+ */
+package(gcc) void safeAssert(
+ bool condition, scope string msg, scope string file = __FILE__, size_t line = __LINE__
+) nothrow @nogc @safe
+{
+ import core.internal.abort;
+ condition || abort(msg, file, line);
+}
diff --git a/libphobos/libdruntime/gcc/sections/elf_shared.d b/libphobos/libdruntime/gcc/sections/elf.d
index 5b0fad9..8450aec 100644
--- a/libphobos/libdruntime/gcc/sections/elf_shared.d
+++ b/libphobos/libdruntime/gcc/sections/elf.d
@@ -20,7 +20,7 @@
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
// <http://www.gnu.org/licenses/>.
-module gcc.sections.elf_shared;
+module gcc.sections.elf;
version (MIPS32) version = MIPS_Any;
version (MIPS64) version = MIPS_Any;
@@ -39,7 +39,6 @@ else version (Solaris) enum SharedELF = true;
else enum SharedELF = false;
static if (SharedELF):
-// debug = PRINTF;
import core.memory;
import core.stdc.config;
import core.stdc.stdio;
@@ -81,25 +80,14 @@ else
static assert(0, "unimplemented");
}
import core.sys.posix.pthread;
-import gcc.builtins;
-import gcc.config;
import rt.deh;
import rt.dmain2;
import rt.minfo;
import rt.util.container.array;
import rt.util.container.hashtab;
-
-/****
- * Asserts the specified condition, independent from -release, by abort()ing.
- * Regular assertions throw an AssertError and thus require an initialized
- * GC, which isn't the case (yet or anymore) for the startup/shutdown code in
- * this module (called by CRT ctors/dtors etc.).
- */
-private void safeAssert(bool condition, scope string msg, size_t line = __LINE__) @nogc nothrow @safe
-{
- import core.internal.abort;
- condition || abort(msg, __FILE__, line);
-}
+import gcc.builtins;
+import gcc.config;
+import gcc.sections.common;
alias DSO SectionGroup;
struct DSO
@@ -134,11 +122,6 @@ struct DSO
return _moduleGroup;
}
- @property immutable(FuncTable)[] ehTables() const nothrow @nogc
- {
- return null;
- }
-
@property inout(void[])[] gcRanges() inout nothrow @nogc
{
return _gcRanges[];
@@ -177,22 +160,12 @@ private:
__gshared bool _isRuntimeInitialized;
-version (FreeBSD) private __gshared void* dummy_ref;
-version (DragonFlyBSD) private __gshared void* dummy_ref;
-version (NetBSD) private __gshared void* dummy_ref;
-version (Solaris) private __gshared void* dummy_ref;
-
/****
* Gets called on program startup just before GC is initialized.
*/
void initSections() nothrow @nogc
{
_isRuntimeInitialized = true;
- // reference symbol to support weak linkage
- version (FreeBSD) dummy_ref = &_d_dso_registry;
- version (DragonFlyBSD) dummy_ref = &_d_dso_registry;
- version (NetBSD) dummy_ref = &_d_dso_registry;
- version (Solaris) dummy_ref = &_d_dso_registry;
}
@@ -208,6 +181,9 @@ alias ScanDG = void delegate(void* pbeg, void* pend) nothrow;
version (Shared)
{
+ import gcc.sections : pinLoadedLibraries, unpinLoadedLibraries,
+ inheritLoadedLibraries, cleanupLoadedLibraries;
+
/***
* Called once per thread; returns array of thread local storage ranges
*/
@@ -248,6 +224,7 @@ version (Shared)
}
// interface for core.thread to inherit loaded libraries
+ pragma(mangle, gcc.sections.pinLoadedLibraries.mangleof)
void* pinLoadedLibraries() nothrow @nogc
{
auto res = cast(Array!(ThreadDSO)*)calloc(1, Array!(ThreadDSO).sizeof);
@@ -266,6 +243,7 @@ version (Shared)
return res;
}
+ pragma(mangle, gcc.sections.unpinLoadedLibraries.mangleof)
void unpinLoadedLibraries(void* p) nothrow @nogc
{
auto pary = cast(Array!(ThreadDSO)*)p;
@@ -285,6 +263,7 @@ version (Shared)
// Called before TLS ctors are ran, copy over the loaded libraries
// of the parent thread.
+ pragma(mangle, gcc.sections.inheritLoadedLibraries.mangleof)
void inheritLoadedLibraries(void* p) nothrow @nogc
{
safeAssert(_loadedDSOs.empty, "DSOs have already been registered for this thread.");
@@ -298,6 +277,7 @@ version (Shared)
}
// Called after all TLS dtors ran, decrements all remaining dlopen refs.
+ pragma(mangle, gcc.sections.cleanupLoadedLibraries.mangleof)
void cleanupLoadedLibraries() nothrow @nogc
{
foreach (ref tdso; _loadedDSOs)
@@ -403,12 +383,6 @@ version (Shared)
*/
__gshared pthread_mutex_t _handleToDSOMutex;
@property ref HashTab!(void*, DSO*) _handleToDSO() @nogc nothrow { __gshared HashTab!(void*, DSO*) x; return x; }
-
- /*
- * Section in executable that contains copy relocations.
- * Might be null when druntime is dynamically loaded by a C host.
- */
- __gshared const(void)[] _copyRelocSection;
}
else
{
@@ -976,29 +950,6 @@ bool findSegmentForAddr(in ref dl_phdr_info info, in void* addr, ElfW!"Phdr"* re
return false;
}
-version (linux) import core.sys.linux.errno : program_invocation_name;
-// should be in core.sys.freebsd.stdlib
-version (FreeBSD) extern(C) const(char)* getprogname() nothrow @nogc;
-version (DragonFlyBSD) extern(C) const(char)* getprogname() nothrow @nogc;
-version (NetBSD) extern(C) const(char)* getprogname() nothrow @nogc;
-version (Solaris) extern(C) const(char)* getprogname() nothrow @nogc;
-
-@property const(char)* progname() nothrow @nogc
-{
- version (linux) return program_invocation_name;
- version (FreeBSD) return getprogname();
- version (DragonFlyBSD) return getprogname();
- version (NetBSD) return getprogname();
- version (Solaris) return getprogname();
-}
-
-const(char)[] dsoName(const char* dlpi_name) nothrow @nogc
-{
- // the main executable doesn't have a name in its dlpi_name field
- const char* p = dlpi_name[0] != 0 ? dlpi_name : progname;
- return p[0 .. strlen(p)];
-}
-
/**************************
* Input:
* addr an internal address of a DSO
diff --git a/libphobos/libdruntime/gcc/sections/macho.d b/libphobos/libdruntime/gcc/sections/macho.d
new file mode 100644
index 0000000..3ce58a53
--- /dev/null
+++ b/libphobos/libdruntime/gcc/sections/macho.d
@@ -0,0 +1,738 @@
+// MACHO-specific support for sections.
+// Copyright (C) 2021 Free Software Foundation, Inc.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+module gcc.sections.macho;
+
+version (OSX):
+
+import core.memory;
+import core.stdc.stdlib;
+import core.sys.darwin.dlfcn;
+import core.sys.darwin.mach.dyld;
+import core.sys.darwin.mach.getsect;
+import core.sys.posix.pthread;
+import rt.minfo;
+import rt.util.container.array;
+import rt.util.container.hashtab;
+import gcc.sections.common;
+
+version (GNU_EMUTLS)
+ import gcc.emutls;
+
+alias DSO SectionGroup;
+struct DSO
+{
+ static int opApply(scope int delegate(ref DSO) dg)
+ {
+ foreach (dso; _loadedDSOs)
+ {
+ if (auto res = dg(*dso))
+ return res;
+ }
+ return 0;
+ }
+
+ static int opApplyReverse(scope int delegate(ref DSO) dg)
+ {
+ foreach_reverse (dso; _loadedDSOs)
+ {
+ if (auto res = dg(*dso))
+ return res;
+ }
+ return 0;
+ }
+
+ @property immutable(ModuleInfo*)[] modules() const nothrow @nogc
+ {
+ return _moduleGroup.modules;
+ }
+
+ @property ref inout(ModuleGroup) moduleGroup() inout nothrow @nogc
+ {
+ return _moduleGroup;
+ }
+
+ @property inout(void[])[] gcRanges() inout nothrow @nogc
+ {
+ return _gcRanges[];
+ }
+
+private:
+
+ invariant()
+ {
+ safeAssert(_moduleGroup.modules.length > 0, "No modules for DSO.");
+ }
+
+ void** _slot;
+ ModuleGroup _moduleGroup;
+ Array!(void[]) _gcRanges;
+
+ version (Shared)
+ {
+ Array!(void[]) _codeSegments; // array of code segments
+ Array!(DSO*) _deps; // D libraries needed by this DSO
+ void* _handle; // corresponding handle
+ }
+}
+
+/****
+ * Boolean flag set to true while the runtime is initialized.
+ */
+__gshared bool _isRuntimeInitialized;
+
+/****
+ * Gets called on program startup just before GC is initialized.
+ */
+void initSections() nothrow @nogc
+{
+ _isRuntimeInitialized = true;
+}
+
+/***
+ * Gets called on program shutdown just after GC is terminated.
+ */
+void finiSections() nothrow @nogc
+{
+ _isRuntimeInitialized = false;
+}
+
+alias ScanDG = void delegate(void* pbeg, void* pend) nothrow;
+
+version (Shared)
+{
+ import gcc.sections : pinLoadedLibraries, unpinLoadedLibraries,
+ inheritLoadedLibraries, cleanupLoadedLibraries;
+
+ /***
+ * Called once per thread; returns array of thread local storage ranges
+ */
+ Array!(ThreadDSO)* initTLSRanges() @nogc nothrow
+ {
+ return &_loadedDSOs();
+ }
+
+ void finiTLSRanges(Array!(ThreadDSO)* tdsos) @nogc nothrow
+ {
+ // Nothing to do here. tdsos used to point to the _loadedDSOs instance
+ // in the dying thread's TLS segment and as such is not valid anymore.
+ // The memory for the array contents was already reclaimed in
+ // cleanupLoadedLibraries().
+ }
+
+ void scanTLSRanges(Array!(ThreadDSO)* tdsos, scope ScanDG dg) nothrow
+ {
+ version (GNU_EMUTLS)
+ _d_emutls_scan(dg);
+ else
+ static assert(0, "Native TLS unimplemented");
+ }
+
+ // interface for core.thread to inherit loaded libraries
+ pragma(mangle, gcc.sections.pinLoadedLibraries.mangleof)
+ void* pinLoadedLibraries() nothrow @nogc
+ {
+ auto res = cast(Array!(ThreadDSO)*)calloc(1, Array!(ThreadDSO).sizeof);
+ res.length = _loadedDSOs.length;
+ foreach (i, ref tdso; _loadedDSOs)
+ {
+ (*res)[i] = tdso;
+ if (tdso._addCnt)
+ {
+ // Increment the dlopen ref for explicitly loaded libraries to pin them.
+ const success = .dlopen(nameForDSO(tdso._pdso), RTLD_LAZY) !is null;
+ safeAssert(success, "Failed to increment dlopen ref.");
+ (*res)[i]._addCnt = 1; // new array takes over the additional ref count
+ }
+ }
+ return res;
+ }
+
+ pragma(mangle, gcc.sections.unpinLoadedLibraries.mangleof)
+ void unpinLoadedLibraries(void* p) nothrow @nogc
+ {
+ auto pary = cast(Array!(ThreadDSO)*)p;
+ // In case something failed we need to undo the pinning.
+ foreach (ref tdso; *pary)
+ {
+ if (tdso._addCnt)
+ {
+ auto handle = tdso._pdso._handle;
+ safeAssert(handle !is null, "Invalid library handle.");
+ .dlclose(handle);
+ }
+ }
+ pary.reset();
+ .free(pary);
+ }
+
+ // Called before TLS ctors are ran, copy over the loaded libraries
+ // of the parent thread.
+ pragma(mangle, gcc.sections.inheritLoadedLibraries.mangleof)
+ void inheritLoadedLibraries(void* p) nothrow @nogc
+ {
+ safeAssert(_loadedDSOs.empty, "DSOs have already been registered for this thread.");
+ _loadedDSOs.swap(*cast(Array!(ThreadDSO)*)p);
+ .free(p);
+ }
+
+ // Called after all TLS dtors ran, decrements all remaining dlopen refs.
+ pragma(mangle, gcc.sections.cleanupLoadedLibraries.mangleof)
+ void cleanupLoadedLibraries() nothrow @nogc
+ {
+ foreach (ref tdso; _loadedDSOs)
+ {
+ if (tdso._addCnt == 0) continue;
+
+ auto handle = tdso._pdso._handle;
+ safeAssert(handle !is null, "Invalid DSO handle.");
+ for (; tdso._addCnt > 0; --tdso._addCnt)
+ .dlclose(handle);
+ }
+
+ // Free the memory for the array contents.
+ _loadedDSOs.reset();
+ }
+}
+else
+{
+ /***
+ * Called once per thread; returns array of thread local storage ranges
+ */
+ Array!(void[])* initTLSRanges() nothrow @nogc
+ {
+ return null;
+ }
+
+ void finiTLSRanges(Array!(void[])* rngs) nothrow @nogc
+ {
+ }
+
+ void scanTLSRanges(Array!(void[])* rngs, scope ScanDG dg) nothrow
+ {
+ version (GNU_EMUTLS)
+ _d_emutls_scan(dg);
+ else
+ static assert(0, "Native TLS unimplemented");
+ }
+}
+
+private:
+
+version (Shared)
+{
+ /*
+ * Array of thread local DSO metadata for all libraries loaded and
+ * initialized in this thread.
+ *
+ * Note:
+ * A newly spawned thread will inherit these libraries.
+ * Note:
+ * We use an array here to preserve the order of
+ * initialization. If that became a performance issue, we
+ * could use a hash table and enumerate the DSOs during
+ * loading so that the hash table values could be sorted when
+ * necessary.
+ */
+ struct ThreadDSO
+ {
+ DSO* _pdso;
+ static if (_pdso.sizeof == 8) uint _refCnt, _addCnt;
+ else static if (_pdso.sizeof == 4) ushort _refCnt, _addCnt;
+ else static assert(0, "unimplemented");
+ alias _pdso this;
+ }
+
+ @property ref Array!(ThreadDSO) _loadedDSOs() @nogc nothrow
+ {
+ static Array!(ThreadDSO) x;
+ return x;
+ }
+
+ /*
+ * Set to true during rt_loadLibrary/rt_unloadLibrary calls.
+ */
+ bool _rtLoading;
+
+ /*
+ * Hash table to map the native handle (as returned by dlopen)
+ * to the corresponding DSO*, protected by a mutex.
+ */
+ __gshared pthread_mutex_t _handleToDSOMutex;
+ @property ref HashTab!(void*, DSO*) _handleToDSO() @nogc nothrow
+ {
+ __gshared HashTab!(void*, DSO*) x;
+ return x;
+ }
+}
+else
+{
+ /*
+ * Static DSOs loaded by the runtime linker. This includes the
+ * executable. These can't be unloaded.
+ */
+ @property ref Array!(DSO*) _loadedDSOs() @nogc nothrow
+ {
+ __gshared Array!(DSO*) x;
+ return x;
+ }
+
+ enum _rtLoading = false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Compiler to runtime interface.
+///////////////////////////////////////////////////////////////////////////////
+
+struct MachHeader
+{
+ const(mach_header)* header; // the mach header of the image
+ intptr_t slide; // virtural memory address slide amount
+}
+
+/****
+ * This data structure is generated by the compiler, and then passed to
+ * _d_dso_registry().
+ */
+struct CompilerDSOData
+{
+ size_t _version; // currently 1
+ void** _slot; // can be used to store runtime data
+ immutable(object.ModuleInfo*)* _minfo_beg, _minfo_end; // array of modules in this object file
+}
+
+T[] toRange(T)(T* beg, T* end) { return beg[0 .. end - beg]; }
+
+/* For each shared library and executable, the compiler generates code that
+ * sets up CompilerDSOData and calls _d_dso_registry().
+ * A pointer to that code is inserted into both the .ctors and .dtors
+ * segment so it gets called by the loader on startup and shutdown.
+ */
+extern(C) void _d_dso_registry(CompilerDSOData* data)
+{
+ // only one supported currently
+ safeAssert(data._version >= 1, "Incompatible compiler-generated DSO data version.");
+
+ // no backlink => register
+ if (*data._slot is null)
+ {
+ immutable firstDSO = _loadedDSOs.empty;
+ if (firstDSO) initLocks();
+
+ DSO* pdso = cast(DSO*).calloc(1, DSO.sizeof);
+ assert(typeid(DSO).initializer().ptr is null);
+ pdso._slot = data._slot;
+ *data._slot = pdso; // store backlink in library record
+
+ pdso._moduleGroup = ModuleGroup(toRange(data._minfo_beg, data._minfo_end));
+
+ MachHeader header = void;
+ const headerFound = findImageHeaderForAddr(data._slot, header);
+ safeAssert(headerFound, "Failed to find image header.");
+
+ scanSegments(header, pdso);
+
+ version (Shared)
+ {
+ auto handle = handleForAddr(data._slot);
+
+ getDependencies(header, pdso._deps);
+ pdso._handle = handle;
+ setDSOForHandle(pdso, pdso._handle);
+
+ if (!_rtLoading)
+ {
+ /* This DSO was not loaded by rt_loadLibrary which
+ * happens for all dependencies of an executable or
+ * the first dlopen call from a C program.
+ * In this case we add the DSO to the _loadedDSOs of this
+ * thread with a refCnt of 1 and call the TlsCtors.
+ */
+ immutable ushort refCnt = 1, addCnt = 0;
+ _loadedDSOs.insertBack(ThreadDSO(pdso, refCnt, addCnt));
+ }
+ }
+ else
+ {
+ foreach (p; _loadedDSOs)
+ safeAssert(p !is pdso, "DSO already registered.");
+ _loadedDSOs.insertBack(pdso);
+ }
+
+ // don't initialize modules before rt_init was called
+ if (_isRuntimeInitialized)
+ {
+ registerGCRanges(pdso);
+ // rt_loadLibrary will run tls ctors, so do this only for dlopen
+ immutable runTlsCtors = !_rtLoading;
+ runModuleConstructors(pdso, runTlsCtors);
+ }
+ }
+ // has backlink => unregister
+ else
+ {
+ DSO* pdso = cast(DSO*)*data._slot;
+ *data._slot = null;
+
+ // don't finalizes modules after rt_term was called (see Bugzilla 11378)
+ if (_isRuntimeInitialized)
+ {
+ // rt_unloadLibrary already ran tls dtors, so do this only for dlclose
+ immutable runTlsDtors = !_rtLoading;
+ runModuleDestructors(pdso, runTlsDtors);
+ unregisterGCRanges(pdso);
+ // run finalizers after module dtors (same order as in rt_term)
+ version (Shared) runFinalizers(pdso);
+ }
+
+ version (Shared)
+ {
+ if (!_rtLoading)
+ {
+ /* This DSO was not unloaded by rt_unloadLibrary so we
+ * have to remove it from _loadedDSOs here.
+ */
+ foreach (i, ref tdso; _loadedDSOs)
+ {
+ if (tdso._pdso == pdso)
+ {
+ _loadedDSOs.remove(i);
+ break;
+ }
+ }
+ }
+
+ unsetDSOForHandle(pdso, pdso._handle);
+ }
+ else
+ {
+ // static DSOs are unloaded in reverse order
+ safeAssert(pdso == _loadedDSOs.back, "DSO being unregistered isn't current last one.");
+ _loadedDSOs.popBack();
+ }
+
+ freeDSO(pdso);
+
+ // last DSO being unloaded => shutdown registry
+ if (_loadedDSOs.empty)
+ {
+ version (GNU_EMUTLS)
+ _d_emutls_destroy();
+ version (Shared)
+ {
+ safeAssert(_handleToDSO.empty, "_handleToDSO not in sync with _loadedDSOs.");
+ _handleToDSO.reset();
+ }
+ finiLocks();
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// dynamic loading
+///////////////////////////////////////////////////////////////////////////////
+
+// Shared D libraries are only supported when linking against a shared druntime library.
+
+version (Shared)
+{
+ ThreadDSO* findThreadDSO(DSO* pdso) nothrow @nogc
+ {
+ foreach (ref tdata; _loadedDSOs)
+ if (tdata._pdso == pdso) return &tdata;
+ return null;
+ }
+
+ void incThreadRef(DSO* pdso, bool incAdd)
+ {
+ if (auto tdata = findThreadDSO(pdso)) // already initialized
+ {
+ if (incAdd && ++tdata._addCnt > 1) return;
+ ++tdata._refCnt;
+ }
+ else
+ {
+ foreach (dep; pdso._deps)
+ incThreadRef(dep, false);
+ immutable ushort refCnt = 1, addCnt = incAdd ? 1 : 0;
+ _loadedDSOs.insertBack(ThreadDSO(pdso, refCnt, addCnt));
+ pdso._moduleGroup.runTlsCtors();
+ }
+ }
+
+ void decThreadRef(DSO* pdso, bool decAdd)
+ {
+ auto tdata = findThreadDSO(pdso);
+ safeAssert(tdata !is null, "Failed to find thread DSO.");
+ safeAssert(!decAdd || tdata._addCnt > 0, "Mismatching rt_unloadLibrary call.");
+
+ if (decAdd && --tdata._addCnt > 0) return;
+ if (--tdata._refCnt > 0) return;
+
+ pdso._moduleGroup.runTlsDtors();
+ foreach (i, ref td; _loadedDSOs)
+ if (td._pdso == pdso) _loadedDSOs.remove(i);
+ foreach (dep; pdso._deps)
+ decThreadRef(dep, false);
+ }
+
+ extern(C) void* rt_loadLibrary(const char* name)
+ {
+ immutable save = _rtLoading;
+ _rtLoading = true;
+ scope (exit) _rtLoading = save;
+
+ auto handle = .dlopen(name, RTLD_LAZY);
+ if (handle is null) return null;
+
+ // if it's a D library
+ if (auto pdso = dsoForHandle(handle))
+ incThreadRef(pdso, true);
+ return handle;
+ }
+
+ extern(C) int rt_unloadLibrary(void* handle)
+ {
+ if (handle is null) return false;
+
+ immutable save = _rtLoading;
+ _rtLoading = true;
+ scope (exit) _rtLoading = save;
+
+ // if it's a D library
+ if (auto pdso = dsoForHandle(handle))
+ decThreadRef(pdso, true);
+ return .dlclose(handle) == 0;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// helper functions
+///////////////////////////////////////////////////////////////////////////////
+
+void initLocks() nothrow @nogc
+{
+ version (Shared)
+ !pthread_mutex_init(&_handleToDSOMutex, null) || assert(0);
+}
+
+void finiLocks() nothrow @nogc
+{
+ version (Shared)
+ !pthread_mutex_destroy(&_handleToDSOMutex) || assert(0);
+}
+
+void runModuleConstructors(DSO* pdso, bool runTlsCtors)
+{
+ pdso._moduleGroup.sortCtors();
+ pdso._moduleGroup.runCtors();
+ if (runTlsCtors) pdso._moduleGroup.runTlsCtors();
+}
+
+void runModuleDestructors(DSO* pdso, bool runTlsDtors)
+{
+ if (runTlsDtors) pdso._moduleGroup.runTlsDtors();
+ pdso._moduleGroup.runDtors();
+}
+
+void registerGCRanges(DSO* pdso) nothrow @nogc
+{
+ foreach (rng; pdso._gcRanges)
+ GC.addRange(rng.ptr, rng.length);
+}
+
+void unregisterGCRanges(DSO* pdso) nothrow @nogc
+{
+ foreach (rng; pdso._gcRanges)
+ GC.removeRange(rng.ptr);
+}
+
+version (Shared) void runFinalizers(DSO* pdso)
+{
+ foreach (seg; pdso._codeSegments)
+ GC.runFinalizers(seg);
+}
+
+void freeDSO(DSO* pdso) nothrow @nogc
+{
+ pdso._gcRanges.reset();
+ version (Shared)
+ {
+ pdso._codeSegments.reset();
+ pdso._deps.reset();
+ pdso._handle = null;
+ }
+ .free(pdso);
+}
+
+version (Shared)
+{
+@nogc nothrow:
+ const(char)* nameForDSO(in DSO* pdso)
+ {
+ Dl_info info = void;
+ const success = dladdr(pdso._slot, &info) != 0;
+ safeAssert(success, "Failed to get DSO info.");
+ return info.dli_fname;
+ }
+
+ DSO* dsoForHandle(void* handle)
+ {
+ DSO* pdso;
+ !pthread_mutex_lock(&_handleToDSOMutex) || assert(0);
+ if (auto ppdso = handle in _handleToDSO)
+ pdso = *ppdso;
+ !pthread_mutex_unlock(&_handleToDSOMutex) || assert(0);
+ return pdso;
+ }
+
+ void setDSOForHandle(DSO* pdso, void* handle)
+ {
+ !pthread_mutex_lock(&_handleToDSOMutex) || assert(0);
+ safeAssert(handle !in _handleToDSO, "DSO already registered.");
+ _handleToDSO[handle] = pdso;
+ !pthread_mutex_unlock(&_handleToDSOMutex) || assert(0);
+ }
+
+ void unsetDSOForHandle(DSO* pdso, void* handle)
+ {
+ !pthread_mutex_lock(&_handleToDSOMutex) || assert(0);
+ safeAssert(_handleToDSO[handle] == pdso, "Handle doesn't match registered DSO.");
+ _handleToDSO.remove(handle);
+ !pthread_mutex_unlock(&_handleToDSOMutex) || assert(0);
+ }
+
+ void getDependencies(in MachHeader info, ref Array!(DSO*) deps)
+ {
+ // FIXME: Not implemented yet.
+ }
+
+ void* handleForName(const char* name)
+ {
+ auto handle = .dlopen(name, RTLD_NOLOAD | RTLD_LAZY);
+ if (handle !is null) .dlclose(handle); // drop reference count
+ return handle;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Mach-O program header iteration
+///////////////////////////////////////////////////////////////////////////////
+
+/************
+ * Scan segments in the image header and store
+ * the writeable data segments in *pdso.
+ */
+
+void scanSegments(in MachHeader info, DSO* pdso)
+{
+ foreach (e; dataSegs)
+ {
+ auto sect = getSection(info.header, info.slide, e.seg.ptr, e.sect.ptr);
+ if (sect != null)
+ pdso._gcRanges.insertBack((cast(void*)sect.ptr)[0 .. sect.length]);
+ }
+
+ version (Shared)
+ {
+ void[] text = getSection(info.header, info.slide, "__TEXT", "__text");
+ if (!text)
+ assert(0, "Failed to get text section.");
+ pdso._codeSegments.insertBack(text);
+ }
+}
+
+/**************************
+ * Input:
+ * result where the output is to be written
+ * Returns:
+ * true if found, and *result is filled in
+ */
+
+bool findImageHeaderForAddr(in void* addr, out MachHeader result)
+{
+ Dl_info info;
+ if (dladdr(addr, &info) == 0)
+ return false;
+
+ foreach (i; 0 .. _dyld_image_count())
+ {
+ if (info.dli_fbase == _dyld_get_image_header(i))
+ {
+ result.header = cast(const(mach_header)*)info.dli_fbase;
+ result.slide = _dyld_get_image_vmaddr_slide(i);
+ return true;
+ }
+ }
+ return false;
+}
+
+/**************************
+ * Input:
+ * addr an internal address of a DSO
+ * Returns:
+ * the dlopen handle for that DSO or null if addr is not within a loaded DSO
+ */
+version (Shared) void* handleForAddr(void* addr) nothrow @nogc
+{
+ Dl_info info = void;
+ if (dladdr(addr, &info) != 0)
+ return handleForName(info.dli_fname);
+ return null;
+}
+
+struct SegRef
+{
+ string seg;
+ string sect;
+}
+
+static immutable SegRef[] dataSegs = [{SEG_DATA, SECT_DATA},
+ {SEG_DATA, SECT_BSS},
+ {SEG_DATA, SECT_COMMON}];
+
+/**
+ * Returns the section for the named section in the named segment
+ * for the mach_header pointer passed, or null if not found.
+ */
+ubyte[] getSection(in mach_header* header, intptr_t slide,
+ in char* segmentName, in char* sectionName)
+{
+ version (D_LP64)
+ {
+ assert(header.magic == MH_MAGIC_64);
+ auto sect = getsectbynamefromheader_64(cast(mach_header_64*)header,
+ segmentName,
+ sectionName);
+ }
+ else
+ {
+ assert(header.magic == MH_MAGIC);
+ auto sect = getsectbynamefromheader(header,
+ segmentName,
+ sectionName);
+ }
+
+ if (sect !is null && sect.size > 0)
+ return (cast(ubyte*)sect.addr + slide)[0 .. cast(size_t)sect.size];
+ return null;
+}
diff --git a/libphobos/libdruntime/gcc/sections/osx.d b/libphobos/libdruntime/gcc/sections/osx.d
deleted file mode 100644
index 3e3db70..0000000
--- a/libphobos/libdruntime/gcc/sections/osx.d
+++ /dev/null
@@ -1,284 +0,0 @@
-// OSX-specific support for sections.
-// Copyright (C) 2019-2021 Free Software Foundation, Inc.
-
-// GCC is free software; you can redistribute it and/or modify it under
-// the terms of the GNU General Public License as published by the Free
-// Software Foundation; either version 3, or (at your option) any later
-// version.
-
-// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-// WARRANTY; without even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-// for more details.
-
-// Under Section 7 of GPL version 3, you are granted additional
-// permissions described in the GCC Runtime Library Exception, version
-// 3.1, as published by the Free Software Foundation.
-
-// You should have received a copy of the GNU General Public License and
-// a copy of the GCC Runtime Library Exception along with this program;
-// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
-// <http://www.gnu.org/licenses/>.
-
-module gcc.sections.osx;
-
-version (OSX):
-
-// debug = PRINTF;
-import core.stdc.stdio;
-import core.stdc.string, core.stdc.stdlib;
-import core.sys.posix.pthread;
-import core.sys.darwin.mach.dyld;
-import core.sys.darwin.mach.getsect;
-import rt.deh, rt.minfo;
-import rt.util.container.array;
-
-struct SectionGroup
-{
- static int opApply(scope int delegate(ref SectionGroup) dg)
- {
- return dg(_sections);
- }
-
- static int opApplyReverse(scope int delegate(ref SectionGroup) dg)
- {
- return dg(_sections);
- }
-
- @property immutable(ModuleInfo*)[] modules() const nothrow @nogc
- {
- return _moduleGroup.modules;
- }
-
- @property ref inout(ModuleGroup) moduleGroup() inout nothrow @nogc
- {
- return _moduleGroup;
- }
-
- @property inout(void[])[] gcRanges() inout nothrow @nogc
- {
- return _gcRanges[];
- }
-
- @property immutable(FuncTable)[] ehTables() const nothrow @nogc
- {
- return _ehTables[];
- }
-
-private:
- immutable(FuncTable)[] _ehTables;
- ModuleGroup _moduleGroup;
- Array!(void[]) _gcRanges;
- immutable(void)[][2] _tlsImage;
-}
-
-/****
- * Boolean flag set to true while the runtime is initialized.
- */
-__gshared bool _isRuntimeInitialized;
-
-/****
- * Gets called on program startup just before GC is initialized.
- */
-void initSections() nothrow @nogc
-{
- pthread_key_create(&_tlsKey, null);
- _dyld_register_func_for_add_image(&sections_osx_onAddImage);
- _isRuntimeInitialized = true;
-}
-
-/***
- * Gets called on program shutdown just after GC is terminated.
- */
-void finiSections() nothrow @nogc
-{
- _sections._gcRanges.reset();
- pthread_key_delete(_tlsKey);
- _isRuntimeInitialized = false;
-}
-
-void[]* initTLSRanges() nothrow @nogc
-{
- return &getTLSBlock();
-}
-
-void finiTLSRanges(void[]* rng) nothrow @nogc
-{
- .free(rng.ptr);
- .free(rng);
-}
-
-void scanTLSRanges(void[]* rng, scope void delegate(void* pbeg, void* pend) nothrow dg) nothrow
-{
- dg(rng.ptr, rng.ptr + rng.length);
-}
-
-// NOTE: The Mach-O object file format does not allow for thread local
-// storage declarations. So instead we roll our own by putting tls
-// into the __tls_data and the __tlscoal_nt sections.
-//
-// This function is called by the code emitted by the compiler. It
-// is expected to translate an address into the TLS static data to
-// the corresponding address in the TLS dynamic per-thread data.
-
-// NB: the compiler mangles this function as '___tls_get_addr' even though it is extern(D)
-extern(D) void* ___tls_get_addr( void* p )
-{
- immutable off = tlsOffset(p);
- auto tls = getTLSBlockAlloc();
- assert(off < tls.length);
- return tls.ptr + off;
-}
-
-private:
-
-__gshared pthread_key_t _tlsKey;
-
-size_t tlsOffset(void* p)
-in
-{
- assert(_sections._tlsImage[0].ptr !is null ||
- _sections._tlsImage[1].ptr !is null);
-}
-body
-{
- // NOTE: p is an address in the TLS static data emitted by the
- // compiler. If it isn't, something is disastrously wrong.
- immutable off0 = cast(size_t)(p - _sections._tlsImage[0].ptr);
- if (off0 < _sections._tlsImage[0].length)
- {
- return off0;
- }
- immutable off1 = cast(size_t)(p - _sections._tlsImage[1].ptr);
- if (off1 < _sections._tlsImage[1].length)
- {
- size_t sz = (_sections._tlsImage[0].length + 15) & ~cast(size_t)15;
- return sz + off1;
- }
- assert(0);
-}
-
-ref void[] getTLSBlock() nothrow @nogc
-{
- auto pary = cast(void[]*)pthread_getspecific(_tlsKey);
- if (pary is null)
- {
- pary = cast(void[]*).calloc(1, (void[]).sizeof);
- if (pthread_setspecific(_tlsKey, pary) != 0)
- {
- import core.stdc.stdio;
- perror("pthread_setspecific failed with");
- assert(0);
- }
- }
- return *pary;
-}
-
-ref void[] getTLSBlockAlloc()
-{
- auto pary = &getTLSBlock();
- if (!pary.length)
- {
- auto imgs = _sections._tlsImage;
- immutable sz0 = (imgs[0].length + 15) & ~cast(size_t)15;
- immutable sz2 = sz0 + imgs[1].length;
- auto p = .malloc(sz2);
- memcpy(p, imgs[0].ptr, imgs[0].length);
- memcpy(p + sz0, imgs[1].ptr, imgs[1].length);
- *pary = p[0 .. sz2];
- }
- return *pary;
-}
-
-__gshared SectionGroup _sections;
-
-extern (C) void sections_osx_onAddImage(in mach_header* h, intptr_t slide)
-{
- foreach (e; dataSegs)
- {
- auto sect = getSection(h, slide, e.seg.ptr, e.sect.ptr);
- if (sect != null)
- _sections._gcRanges.insertBack((cast(void*)sect.ptr)[0 .. sect.length]);
- }
-
- auto minfosect = getSection(h, slide, "__DATA", "__minfodata");
- if (minfosect != null)
- {
- // no support for multiple images yet
- // take the sections from the last static image which is the executable
- if (_isRuntimeInitialized)
- {
- fprintf(stderr, "Loading shared libraries isn't yet supported on OSX.\n");
- return;
- }
- else if (_sections.modules.ptr !is null)
- {
- fprintf(stderr, "Shared libraries are not yet supported on OSX.\n");
- }
-
- debug(PRINTF) printf(" minfodata\n");
- auto p = cast(immutable(ModuleInfo*)*)minfosect.ptr;
- immutable len = minfosect.length / (*p).sizeof;
-
- _sections._moduleGroup = ModuleGroup(p[0 .. len]);
- }
-
- auto ehsect = getSection(h, slide, "__DATA", "__deh_eh");
- if (ehsect != null)
- {
- debug(PRINTF) printf(" deh_eh\n");
- auto p = cast(immutable(FuncTable)*)ehsect.ptr;
- immutable len = ehsect.length / (*p).sizeof;
-
- _sections._ehTables = p[0 .. len];
- }
-
- auto tlssect = getSection(h, slide, "__DATA", "__tls_data");
- if (tlssect != null)
- {
- debug(PRINTF) printf(" tls_data %p %p\n", tlssect.ptr, tlssect.ptr + tlssect.length);
- _sections._tlsImage[0] = (cast(immutable(void)*)tlssect.ptr)[0 .. tlssect.length];
- }
-
- auto tlssect2 = getSection(h, slide, "__DATA", "__tlscoal_nt");
- if (tlssect2 != null)
- {
- debug(PRINTF) printf(" tlscoal_nt %p %p\n", tlssect2.ptr, tlssect2.ptr + tlssect2.length);
- _sections._tlsImage[1] = (cast(immutable(void)*)tlssect2.ptr)[0 .. tlssect2.length];
- }
-}
-
-struct SegRef
-{
- string seg;
- string sect;
-}
-
-static immutable SegRef[] dataSegs = [{SEG_DATA, SECT_DATA},
- {SEG_DATA, SECT_BSS},
- {SEG_DATA, SECT_COMMON}];
-
-ubyte[] getSection(in mach_header* header, intptr_t slide,
- in char* segmentName, in char* sectionName)
-{
- version (X86)
- {
- assert(header.magic == MH_MAGIC);
- auto sect = getsectbynamefromheader(header,
- segmentName,
- sectionName);
- }
- else version (X86_64)
- {
- assert(header.magic == MH_MAGIC_64);
- auto sect = getsectbynamefromheader_64(cast(mach_header_64*)header,
- segmentName,
- sectionName);
- }
- else
- static assert(0, "unimplemented");
-
- if (sect !is null && sect.size > 0)
- return (cast(ubyte*)sect.addr + slide)[0 .. cast(size_t)sect.size];
- return null;
-}
diff --git a/libphobos/libdruntime/gcc/sections/package.d b/libphobos/libdruntime/gcc/sections/package.d
index fdaf039..4c2b542 100644
--- a/libphobos/libdruntime/gcc/sections/package.d
+++ b/libphobos/libdruntime/gcc/sections/package.d
@@ -22,27 +22,30 @@
module gcc.sections;
-version (CRuntime_Glibc)
- public import gcc.sections.elf_shared;
-else version (CRuntime_Musl)
- public import gcc.sections.elf_shared;
-else version (CRuntime_UClibc)
- public import gcc.sections.elf_shared;
-else version (FreeBSD)
- public import gcc.sections.elf_shared;
-else version (NetBSD)
- public import gcc.sections.elf_shared;
-else version (DragonFlyBSD)
- public import gcc.sections.elf_shared;
-else version (Solaris)
- public import gcc.sections.elf_shared;
-else version (OSX)
- public import gcc.sections.osx;
-else version (CRuntime_DigitalMars)
- public import gcc.sections.win32;
-else version (CRuntime_Microsoft)
- public import gcc.sections.win64;
-else version (CRuntime_Bionic)
- public import gcc.sections.android;
+version (CRuntime_Glibc) version = SectionsElf;
+version (CRuntime_Musl) version = SectionsElf;
+version (CRuntime_UClibc) version = SectionsElf;
+version (FreeBSD) version = SectionsElf;
+version (NetBSD) version = SectionsElf;
+version (DragonFlyBSD) version = SectionsElf;
+version (Solaris) version = SectionsElf;
+version (OSX) version = SectionsMacho;
+version (Windows) version = SectionsPeCoff;
+
+version (SectionsElf)
+ public import gcc.sections.elf;
+else version (SectionsMacho)
+ public import gcc.sections.macho;
+else version (SectionsPeCoff)
+ public import gcc.sections.pecoff;
else
static assert(0, "unimplemented");
+
+version (Shared)
+{
+ // interface for core.thread to inherit loaded libraries
+ void* pinLoadedLibraries() nothrow @nogc;
+ void unpinLoadedLibraries(void* p) nothrow @nogc;
+ void inheritLoadedLibraries(void* p) nothrow @nogc;
+ void cleanupLoadedLibraries() nothrow @nogc;
+}
diff --git a/libphobos/libdruntime/gcc/sections/pecoff.d b/libphobos/libdruntime/gcc/sections/pecoff.d
new file mode 100644
index 0000000..ed0340e
--- /dev/null
+++ b/libphobos/libdruntime/gcc/sections/pecoff.d
@@ -0,0 +1,826 @@
+// PE/COFF-specific support for sections.
+// Copyright (C) 2021 Free Software Foundation, Inc.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+module gcc.sections.pecoff;
+
+version (Windows):
+
+import core.memory;
+import core.stdc.stdlib;
+import core.sys.windows.winbase;
+import core.sys.windows.windef;
+import core.sys.windows.winnt;
+import rt.minfo;
+import rt.util.container.array;
+import rt.util.container.hashtab;
+import gcc.sections.common;
+
+version (GNU_EMUTLS)
+ import gcc.emutls;
+
+alias DSO SectionGroup;
+struct DSO
+{
+ static int opApply(scope int delegate(ref DSO) dg)
+ {
+ foreach (dso; _loadedDSOs)
+ {
+ if (auto res = dg(*dso))
+ return res;
+ }
+ return 0;
+ }
+
+ static int opApplyReverse(scope int delegate(ref DSO) dg)
+ {
+ foreach_reverse (dso; _loadedDSOs)
+ {
+ if (auto res = dg(*dso))
+ return res;
+ }
+ return 0;
+ }
+
+ @property immutable(ModuleInfo*)[] modules() const nothrow @nogc
+ {
+ return _moduleGroup.modules;
+ }
+
+ @property ref inout(ModuleGroup) moduleGroup() inout nothrow @nogc
+ {
+ return _moduleGroup;
+ }
+
+ @property inout(void[])[] gcRanges() inout nothrow @nogc
+ {
+ return _gcRanges[];
+ }
+
+private:
+
+ invariant()
+ {
+ safeAssert(_moduleGroup.modules.length > 0, "No modules for DSO.");
+ }
+
+ void** _slot;
+ ModuleGroup _moduleGroup;
+ Array!(void[]) _gcRanges;
+
+ version (Shared)
+ {
+ Array!(void[]) _codeSegments; // array of code segments
+ Array!(DSO*) _deps; // D libraries needed by this DSO
+ void* _handle; // corresponding handle
+ }
+}
+
+/****
+ * Boolean flag set to true while the runtime is initialized.
+ */
+__gshared bool _isRuntimeInitialized;
+
+/****
+ * Gets called on program startup just before GC is initialized.
+ */
+void initSections() nothrow @nogc
+{
+ _isRuntimeInitialized = true;
+}
+
+/***
+ * Gets called on program shutdown just after GC is terminated.
+ */
+void finiSections() nothrow @nogc
+{
+ _isRuntimeInitialized = false;
+}
+
+alias ScanDG = void delegate(void* pbeg, void* pend) nothrow;
+
+version (Shared)
+{
+ import gcc.sections : pinLoadedLibraries, unpinLoadedLibraries,
+ inheritLoadedLibraries, cleanupLoadedLibraries;
+
+ /***
+ * Called once per thread; returns array of thread local storage ranges
+ */
+ Array!(ThreadDSO)* initTLSRanges() @nogc nothrow
+ {
+ return &_loadedDSOs();
+ }
+
+ void finiTLSRanges(Array!(ThreadDSO)* tdsos) @nogc nothrow
+ {
+ // Nothing to do here. tdsos used to point to the _loadedDSOs instance
+ // in the dying thread's TLS segment and as such is not valid anymore.
+ // The memory for the array contents was already reclaimed in
+ // cleanupLoadedLibraries().
+ }
+
+ void scanTLSRanges(Array!(ThreadDSO)* tdsos, scope ScanDG dg) nothrow
+ {
+ version (GNU_EMUTLS)
+ _d_emutls_scan(dg);
+ else
+ static assert(0, "Native TLS unimplemented");
+ }
+
+ // interface for core.thread to inherit loaded libraries
+ pragma(mangle, gcc.sections.pinLoadedLibraries.mangleof)
+ void* pinLoadedLibraries() nothrow @nogc
+ {
+ auto res = cast(Array!(ThreadDSO)*)calloc(1, Array!(ThreadDSO).sizeof);
+ res.length = _loadedDSOs.length;
+ foreach (i, ref tdso; _loadedDSOs)
+ {
+ (*res)[i] = tdso;
+ if (tdso._addCnt)
+ {
+ // Increment the DLL ref for explicitly loaded libraries to pin them.
+ char[MAX_PATH] buf;
+ char[] buffer = buf[];
+ const success = .LoadLibraryA(nameForDSO(tdso._pdso, buffer)) !is null;
+ safeAssert(success, "Failed to increment DLL ref.");
+ (*res)[i]._addCnt = 1; // new array takes over the additional ref count
+ }
+ }
+ return res;
+ }
+
+ pragma(mangle, gcc.sections.unpinLoadedLibraries.mangleof)
+ void unpinLoadedLibraries(void* p) nothrow @nogc
+ {
+ auto pary = cast(Array!(ThreadDSO)*)p;
+ // In case something failed we need to undo the pinning.
+ foreach (ref tdso; *pary)
+ {
+ if (tdso._addCnt)
+ {
+ auto handle = tdso._pdso._handle;
+ safeAssert(handle !is null, "Invalid library handle.");
+ .FreeLibrary(handle);
+ }
+ }
+ pary.reset();
+ .free(pary);
+ }
+
+ // Called before TLS ctors are ran, copy over the loaded libraries
+ // of the parent thread.
+ pragma(mangle, gcc.sections.inheritLoadedLibraries.mangleof)
+ void inheritLoadedLibraries(void* p) nothrow @nogc
+ {
+ safeAssert(_loadedDSOs.empty, "DSOs have already been registered for this thread.");
+ _loadedDSOs.swap(*cast(Array!(ThreadDSO)*)p);
+ .free(p);
+ }
+
+ // Called after all TLS dtors ran, decrements all remaining DLL refs.
+ pragma(mangle, gcc.sections.cleanupLoadedLibraries.mangleof)
+ void cleanupLoadedLibraries() nothrow @nogc
+ {
+ foreach (ref tdso; _loadedDSOs)
+ {
+ if (tdso._addCnt == 0) continue;
+
+ auto handle = tdso._pdso._handle;
+ safeAssert(handle !is null, "Invalid DSO handle.");
+ for (; tdso._addCnt > 0; --tdso._addCnt)
+ .FreeLibrary(handle);
+ }
+
+ // Free the memory for the array contents.
+ _loadedDSOs.reset();
+ }
+}
+else
+{
+ /***
+ * Called once per thread; returns array of thread local storage ranges
+ */
+ Array!(void[])* initTLSRanges() nothrow @nogc
+ {
+ return null;
+ }
+
+ void finiTLSRanges(Array!(void[])* rngs) nothrow @nogc
+ {
+ }
+
+ void scanTLSRanges(Array!(void[])* rngs, scope ScanDG dg) nothrow
+ {
+ version (GNU_EMUTLS)
+ _d_emutls_scan(dg);
+ else
+ static assert(0, "Native TLS unimplemented");
+ }
+}
+
+private:
+
+version (Shared)
+{
+ /*
+ * Array of thread local DSO metadata for all libraries loaded and
+ * initialized in this thread.
+ *
+ * Note:
+ * A newly spawned thread will inherit these libraries.
+ * Note:
+ * We use an array here to preserve the order of
+ * initialization. If that became a performance issue, we
+ * could use a hash table and enumerate the DSOs during
+ * loading so that the hash table values could be sorted when
+ * necessary.
+ */
+ struct ThreadDSO
+ {
+ DSO* _pdso;
+ static if (_pdso.sizeof == 8) uint _refCnt, _addCnt;
+ else static if (_pdso.sizeof == 4) ushort _refCnt, _addCnt;
+ else static assert(0, "unimplemented");
+ alias _pdso this;
+ }
+
+ @property ref Array!(ThreadDSO) _loadedDSOs() @nogc nothrow
+ {
+ static Array!(ThreadDSO) x;
+ return x;
+ }
+
+ /*
+ * Set to true during rt_loadLibrary/rt_unloadLibrary calls.
+ */
+ bool _rtLoading;
+
+ /*
+ * Hash table to map the native handle (as returned by dlopen)
+ * to the corresponding DSO*, protected by a mutex.
+ */
+ __gshared CRITICAL_SECTION _handleToDSOMutex;
+ @property ref HashTab!(void*, DSO*) _handleToDSO() @nogc nothrow
+ {
+ __gshared HashTab!(void*, DSO*) x;
+ return x;
+ }
+}
+else
+{
+ /*
+ * Static DSOs loaded by the runtime linker. This includes the
+ * executable. These can't be unloaded.
+ */
+ @property ref Array!(DSO*) _loadedDSOs() @nogc nothrow
+ {
+ __gshared Array!(DSO*) x;
+ return x;
+ }
+
+ enum _rtLoading = false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Compiler to runtime interface.
+///////////////////////////////////////////////////////////////////////////////
+
+/****
+ * This data structure is generated by the compiler, and then passed to
+ * _d_dso_registry().
+ */
+struct CompilerDSOData
+{
+ size_t _version; // currently 1
+ void** _slot; // can be used to store runtime data
+ immutable(object.ModuleInfo*)* _minfo_beg, _minfo_end; // array of modules in this object file
+}
+
+T[] toRange(T)(T* beg, T* end) { return beg[0 .. end - beg]; }
+
+/* For each shared library and executable, the compiler generates code that
+ * sets up CompilerDSOData and calls _d_dso_registry().
+ * A pointer to that code is inserted into both the .ctors and .dtors
+ * segment so it gets called by the loader on startup and shutdown.
+ */
+extern(C) void _d_dso_registry(CompilerDSOData* data)
+{
+ // only one supported currently
+ safeAssert(data._version >= 1, "Incompatible compiler-generated DSO data version.");
+
+ // no backlink => register
+ if (*data._slot is null)
+ {
+ immutable firstDSO = _loadedDSOs.empty;
+ if (firstDSO) initLocks();
+
+ DSO* pdso = cast(DSO*).calloc(1, DSO.sizeof);
+ assert(typeid(DSO).initializer().ptr is null);
+ pdso._slot = data._slot;
+ *data._slot = pdso; // store backlink in library record
+
+ pdso._moduleGroup = ModuleGroup(toRange(data._minfo_beg, data._minfo_end));
+
+ HMODULE handle = void;
+ const moduleFound = findModuleHandleForAddr(data._slot, handle);
+ safeAssert(moduleFound, "Failed to find image header.");
+
+ scanSegments(handle, pdso);
+
+ version (Shared)
+ {
+ getDependencies(handle, pdso._deps);
+ pdso._handle = handle;
+ setDSOForHandle(pdso, pdso._handle);
+
+ if (!_rtLoading)
+ {
+ /* This DSO was not loaded by rt_loadLibrary which
+ * happens for all dependencies of an executable or
+ * the first dlopen call from a C program.
+ * In this case we add the DSO to the _loadedDSOs of this
+ * thread with a refCnt of 1 and call the TlsCtors.
+ */
+ immutable ushort refCnt = 1, addCnt = 0;
+ _loadedDSOs.insertBack(ThreadDSO(pdso, refCnt, addCnt));
+ }
+ }
+ else
+ {
+ foreach (p; _loadedDSOs)
+ safeAssert(p !is pdso, "DSO already registered.");
+ _loadedDSOs.insertBack(pdso);
+ }
+
+ // don't initialize modules before rt_init was called
+ if (_isRuntimeInitialized)
+ {
+ registerGCRanges(pdso);
+ // rt_loadLibrary will run tls ctors, so do this only for dlopen
+ immutable runTlsCtors = !_rtLoading;
+ runModuleConstructors(pdso, runTlsCtors);
+ }
+ }
+ // has backlink => unregister
+ else
+ {
+ DSO* pdso = cast(DSO*)*data._slot;
+ *data._slot = null;
+
+ // don't finalizes modules after rt_term was called (see Bugzilla 11378)
+ if (_isRuntimeInitialized)
+ {
+ // rt_unloadLibrary already ran tls dtors, so do this only for dlclose
+ immutable runTlsDtors = !_rtLoading;
+ runModuleDestructors(pdso, runTlsDtors);
+ unregisterGCRanges(pdso);
+ // run finalizers after module dtors (same order as in rt_term)
+ version (Shared) runFinalizers(pdso);
+ }
+
+ version (Shared)
+ {
+ if (!_rtLoading)
+ {
+ /* This DSO was not unloaded by rt_unloadLibrary so we
+ * have to remove it from _loadedDSOs here.
+ */
+ foreach (i, ref tdso; _loadedDSOs)
+ {
+ if (tdso._pdso == pdso)
+ {
+ _loadedDSOs.remove(i);
+ break;
+ }
+ }
+ }
+
+ unsetDSOForHandle(pdso, pdso._handle);
+ }
+ else
+ {
+ // static DSOs are unloaded in reverse order
+ safeAssert(pdso == _loadedDSOs.back, "DSO being unregistered isn't current last one.");
+ _loadedDSOs.popBack();
+ }
+
+ freeDSO(pdso);
+
+ // last DSO being unloaded => shutdown registry
+ if (_loadedDSOs.empty)
+ {
+ version (GNU_EMUTLS)
+ _d_emutls_destroy();
+ version (Shared)
+ {
+ safeAssert(_handleToDSO.empty, "_handleToDSO not in sync with _loadedDSOs.");
+ _handleToDSO.reset();
+ }
+ finiLocks();
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// dynamic loading
+///////////////////////////////////////////////////////////////////////////////
+
+// Shared D libraries are only supported when linking against a shared druntime library.
+
+version (Shared)
+{
+ ThreadDSO* findThreadDSO(DSO* pdso) nothrow @nogc
+ {
+ foreach (ref tdata; _loadedDSOs)
+ if (tdata._pdso == pdso) return &tdata;
+ return null;
+ }
+
+ void incThreadRef(DSO* pdso, bool incAdd)
+ {
+ if (auto tdata = findThreadDSO(pdso)) // already initialized
+ {
+ if (incAdd && ++tdata._addCnt > 1) return;
+ ++tdata._refCnt;
+ }
+ else
+ {
+ foreach (dep; pdso._deps)
+ incThreadRef(dep, false);
+ immutable ushort refCnt = 1, addCnt = incAdd ? 1 : 0;
+ _loadedDSOs.insertBack(ThreadDSO(pdso, refCnt, addCnt));
+ pdso._moduleGroup.runTlsCtors();
+ }
+ }
+
+ void decThreadRef(DSO* pdso, bool decAdd)
+ {
+ auto tdata = findThreadDSO(pdso);
+ safeAssert(tdata !is null, "Failed to find thread DSO.");
+ safeAssert(!decAdd || tdata._addCnt > 0, "Mismatching rt_unloadLibrary call.");
+
+ if (decAdd && --tdata._addCnt > 0) return;
+ if (--tdata._refCnt > 0) return;
+
+ pdso._moduleGroup.runTlsDtors();
+ foreach (i, ref td; _loadedDSOs)
+ if (td._pdso == pdso) _loadedDSOs.remove(i);
+ foreach (dep; pdso._deps)
+ decThreadRef(dep, false);
+ }
+}
+
+/***********************************
+ * These are a temporary means of providing a GC hook for DLL use. They may be
+ * replaced with some other similar functionality later.
+ */
+extern (C)
+{
+ void* gc_getProxy();
+ void gc_setProxy(void* p);
+ void gc_clrProxy();
+
+ alias void function(void*) gcSetFn;
+ alias void function() gcClrFn;
+}
+
+/*******************************************
+ * Loads a DLL written in D with the name 'name'.
+ * Returns:
+ * opaque handle to the DLL if successfully loaded
+ * null if failure
+ */
+extern(C) void* rt_loadLibrary(const char* name)
+{
+ version (Shared)
+ {
+ immutable save = _rtLoading;
+ _rtLoading = true;
+ scope (exit) _rtLoading = save;
+ }
+ return initLibrary(.LoadLibraryA(name));
+}
+
+extern (C) void* rt_loadLibraryW(const wchar_t* name)
+{
+ version (Shared)
+ {
+ immutable save = _rtLoading;
+ _rtLoading = true;
+ scope (exit) _rtLoading = save;
+ }
+ return initLibrary(.LoadLibraryW(name));
+}
+
+void* initLibrary(void* handle)
+{
+ if (handle is null)
+ return null;
+
+ version (Shared)
+ {
+ // if it's a D library
+ if (auto pdso = dsoForHandle(handle))
+ incThreadRef(pdso, true);
+ }
+ gcSetFn gcSet = cast(gcSetFn) GetProcAddress(handle, "gc_setProxy");
+ if (gcSet !is null)
+ {
+ // BUG: Set proxy, but too late
+ gcSet(gc_getProxy());
+ }
+ return handle;
+}
+
+/*************************************
+ * Unloads DLL that was previously loaded by rt_loadLibrary().
+ * Input:
+ * handle the handle returned by rt_loadLibrary()
+ * Returns:
+ * 1 succeeded
+ * 0 some failure happened
+ */
+extern(C) int rt_unloadLibrary(void* handle)
+{
+ if (handle is null)
+ return false;
+
+ version (Shared)
+ {
+ immutable save = _rtLoading;
+ _rtLoading = true;
+ scope (exit) _rtLoading = save;
+
+ // if it's a D library
+ if (auto pdso = dsoForHandle(handle))
+ decThreadRef(pdso, true);
+ }
+ gcClrFn gcClr = cast(gcClrFn) GetProcAddress(handle, "gc_clrProxy");
+ if (gcClr !is null)
+ gcClr();
+ return .FreeLibrary(handle) != 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// helper functions
+///////////////////////////////////////////////////////////////////////////////
+
+void initLocks() nothrow @nogc
+{
+ version (Shared)
+ InitializeCriticalSection(&_handleToDSOMutex);
+}
+
+void finiLocks() nothrow @nogc
+{
+ version (Shared)
+ DeleteCriticalSection(&_handleToDSOMutex);
+}
+
+void runModuleConstructors(DSO* pdso, bool runTlsCtors)
+{
+ pdso._moduleGroup.sortCtors();
+ pdso._moduleGroup.runCtors();
+ if (runTlsCtors) pdso._moduleGroup.runTlsCtors();
+}
+
+void runModuleDestructors(DSO* pdso, bool runTlsDtors)
+{
+ if (runTlsDtors) pdso._moduleGroup.runTlsDtors();
+ pdso._moduleGroup.runDtors();
+}
+
+void registerGCRanges(DSO* pdso) nothrow @nogc
+{
+ foreach (rng; pdso._gcRanges)
+ GC.addRange(rng.ptr, rng.length);
+}
+
+void unregisterGCRanges(DSO* pdso) nothrow @nogc
+{
+ foreach (rng; pdso._gcRanges)
+ GC.removeRange(rng.ptr);
+}
+
+version (Shared) void runFinalizers(DSO* pdso)
+{
+ foreach (seg; pdso._codeSegments)
+ GC.runFinalizers(seg);
+}
+
+void freeDSO(DSO* pdso) nothrow @nogc
+{
+ pdso._gcRanges.reset();
+ version (Shared)
+ {
+ pdso._codeSegments.reset();
+ pdso._deps.reset();
+ pdso._handle = null;
+ }
+ .free(pdso);
+}
+
+version (Shared)
+{
+@nogc nothrow:
+ const(char)* nameForDSO(DSO* pdso, ref char[] buffer)
+ {
+ const success = GetModuleFileNameA(pdso._handle, buffer.ptr, cast(DWORD)buffer.length) != 0;
+ safeAssert(success, "Failed to get DLL name.");
+ return buffer.ptr;
+ }
+
+ DSO* dsoForHandle(in void* handle)
+ {
+ DSO* pdso;
+ .EnterCriticalSection(&_handleToDSOMutex);
+ if (auto ppdso = handle in _handleToDSO)
+ pdso = *ppdso;
+ .LeaveCriticalSection(&_handleToDSOMutex);
+ return pdso;
+ }
+
+ void setDSOForHandle(DSO* pdso, void* handle)
+ {
+ .EnterCriticalSection(&_handleToDSOMutex);
+ safeAssert(handle !in _handleToDSO, "DSO already registered.");
+ _handleToDSO[handle] = pdso;
+ .LeaveCriticalSection(&_handleToDSOMutex);
+ }
+
+ void unsetDSOForHandle(DSO* pdso, void* handle)
+ {
+ .EnterCriticalSection(&_handleToDSOMutex);
+ safeAssert(_handleToDSO[handle] == pdso, "Handle doesn't match registered DSO.");
+ _handleToDSO.remove(handle);
+ .LeaveCriticalSection(&_handleToDSOMutex);
+ }
+
+ void getDependencies(in HMODULE handle, ref Array!(DSO*) deps)
+ {
+ auto nthdr = getNTHeader(handle);
+ auto import_entry = nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
+ auto addr = import_entry.VirtualAddress;
+ auto datasize = import_entry.Size;
+
+ if (addr == 0 && datasize == 0)
+ {
+ // Maybe the optional header isn't there, look for the section.
+ foreach (section; getSectionHeader(handle))
+ {
+ if (!compareSectionName(section, ".idata"))
+ continue;
+ addr = section.VirtualAddress;
+ datasize = section.Misc.VirtualSize;
+ break;
+ }
+ if (datasize == 0)
+ return;
+ }
+ else
+ {
+ bool foundSection = false;
+ foreach (section; getSectionHeader(handle))
+ {
+ if (!compareSectionName(section, ".idata"))
+ continue;
+ // Section containing import table has no contents.
+ if (section.Misc.VirtualSize == 0)
+ return;
+ foundSection = true;
+ break;
+ }
+ // There is an import table, but the section containing it could not be found
+ if (!foundSection)
+ return;
+ }
+
+ // Get the names of each DLL
+ for (uint i = 0; i + IMAGE_IMPORT_DESCRIPTOR.sizeof <= datasize;
+ i += IMAGE_IMPORT_DESCRIPTOR.sizeof)
+ {
+ const data = cast(PIMAGE_IMPORT_DESCRIPTOR)(handle + addr + i);
+ if (data.Name == 0)
+ break;
+
+ // dll name of dependency
+ auto name = cast(char*)(handle + data.Name);
+ // get handle without loading the library
+ auto libhandle = handleForName(name);
+ // the runtime linker has already loaded all dependencies
+ safeAssert(handle !is null, "Failed to get library handle.");
+ // if it's a D library
+ if (auto pdso = dsoForHandle(handle))
+ deps.insertBack(pdso); // append it to the dependencies
+ }
+ }
+
+ void* handleForName(const char* name)
+ {
+ return GetModuleHandleA(name);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// PE/COFF program header iteration
+///////////////////////////////////////////////////////////////////////////////
+
+bool compareSectionName(ref IMAGE_SECTION_HEADER section, string name) nothrow @nogc
+{
+ if (name[] != cast(char[])section.Name[0 .. name.length])
+ return false;
+ return name.length == 8 || section.Name[name.length] == 0;
+}
+
+/************
+ * Scan segments in the image header and store
+ * the writeable data segments in *pdso.
+ */
+
+void scanSegments(in HMODULE handle, DSO* pdso) nothrow @nogc
+{
+ foreach (section; getSectionHeader(handle))
+ {
+ // the ".data" image section includes both object file sections ".data" and ".bss"
+ if (compareSectionName(section, ".data"))
+ {
+ auto data = cast(void*)handle + section.VirtualAddress;
+ pdso._gcRanges.insertBack(data[0 .. section.Misc.VirtualSize]);
+ continue;
+ }
+
+ version (Shared)
+ {
+ if (compareSectionName(section, ".text"))
+ {
+ auto text = cast(void*)handle + section.VirtualAddress;
+ pdso._codeSegments.insertBack(text[0 .. section.Misc.VirtualSize]);
+ continue;
+ }
+ }
+ }
+}
+
+/**************************
+ * Input:
+ * handle where the output is to be written
+ * Returns:
+ * true if found, and *handle is filled in
+ */
+
+bool findModuleHandleForAddr(in void* addr, out HMODULE handle) nothrow @nogc
+{
+ if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+ cast(const(wchar)*) addr, &handle))
+ return true;
+
+ return false;
+}
+
+/**
+ * Returns the image NT header for the HMODULE handle passed,
+ * or null if not found.
+ */
+PIMAGE_NT_HEADERS getNTHeader(in HMODULE handle) nothrow @nogc
+{
+ auto doshdr = cast(PIMAGE_DOS_HEADER)handle;
+ if (doshdr.e_magic != IMAGE_DOS_SIGNATURE)
+ return null;
+
+ return cast(typeof(return))(cast(void*)doshdr + doshdr.e_lfanew);
+}
+
+/**
+ * Returns the image section header for the HMODULE handle passed,
+ * or null if not found.
+ */
+IMAGE_SECTION_HEADER[] getSectionHeader(in HMODULE handle) nothrow @nogc
+{
+ if (auto nthdr = getNTHeader(handle))
+ {
+ const void* opthdr = &nthdr.OptionalHeader;
+ const offset = nthdr.FileHeader.SizeOfOptionalHeader;
+ const length = nthdr.FileHeader.NumberOfSections;
+ return (cast(PIMAGE_SECTION_HEADER)(opthdr + offset))[0 .. length];
+ }
+ return null;
+}
diff --git a/libphobos/libdruntime/gcc/sections/win32.d b/libphobos/libdruntime/gcc/sections/win32.d
deleted file mode 100644
index b355dfc..0000000
--- a/libphobos/libdruntime/gcc/sections/win32.d
+++ /dev/null
@@ -1,183 +0,0 @@
-// Win32-specific support for sections.
-// Copyright (C) 2019-2021 Free Software Foundation, Inc.
-
-// GCC is free software; you can redistribute it and/or modify it under
-// the terms of the GNU General Public License as published by the Free
-// Software Foundation; either version 3, or (at your option) any later
-// version.
-
-// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-// WARRANTY; without even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-// for more details.
-
-// Under Section 7 of GPL version 3, you are granted additional
-// permissions described in the GCC Runtime Library Exception, version
-// 3.1, as published by the Free Software Foundation.
-
-// You should have received a copy of the GNU General Public License and
-// a copy of the GCC Runtime Library Exception along with this program;
-// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
-// <http://www.gnu.org/licenses/>.
-
-module gcc.sections.win32;
-
-version (CRuntime_DigitalMars):
-
-// debug = PRINTF;
-debug(PRINTF) import core.stdc.stdio;
-import rt.minfo;
-import core.stdc.stdlib : malloc, free;
-
-struct SectionGroup
-{
- static int opApply(scope int delegate(ref SectionGroup) dg)
- {
- return dg(_sections);
- }
-
- static int opApplyReverse(scope int delegate(ref SectionGroup) dg)
- {
- return dg(_sections);
- }
-
- @property immutable(ModuleInfo*)[] modules() const nothrow @nogc
- {
- return _moduleGroup.modules;
- }
-
- @property ref inout(ModuleGroup) moduleGroup() inout nothrow @nogc
- {
- return _moduleGroup;
- }
-
- @property inout(void[])[] gcRanges() inout nothrow @nogc
- {
- return _gcRanges[];
- }
-
-private:
- ModuleGroup _moduleGroup;
- void[][] _gcRanges;
-}
-
-shared(bool) conservative;
-
-void initSections() nothrow @nogc
-{
- _sections._moduleGroup = ModuleGroup(getModuleInfos());
-
- import rt.sections;
- conservative = !scanDataSegPrecisely();
-
- if (conservative)
- {
- _sections._gcRanges = (cast(void[]*) malloc(2 * (void[]).sizeof))[0..2];
-
- auto databeg = cast(void*)&_xi_a;
- auto dataend = cast(void*)_moduleinfo_array.ptr;
- _sections._gcRanges[0] = databeg[0 .. dataend - databeg];
-
- // skip module info and CONST segment
- auto bssbeg = cast(void*)&_edata;
- auto bssend = cast(void*)&_end;
- _sections._gcRanges[1] = bssbeg[0 .. bssend - bssbeg];
- }
- else
- {
- size_t count = &_DPend - &_DPbegin;
- auto ranges = cast(void[]*) malloc(count * (void[]).sizeof);
- size_t r = 0;
- void* prev = null;
- for (size_t i = 0; i < count; i++)
- {
- void* addr = (&_DPbegin)[i];
- if (prev + (void*).sizeof == addr)
- ranges[r-1] = ranges[r-1].ptr[0 .. ranges[r-1].length + (void*).sizeof];
- else
- ranges[r++] = (cast(void**)addr)[0..1];
- prev = addr;
- }
- _sections._gcRanges = ranges[0..r];
- }
-}
-
-void finiSections() nothrow @nogc
-{
- free(_sections._gcRanges.ptr);
-}
-
-void[] initTLSRanges() nothrow @nogc
-{
- auto pbeg = cast(void*)&_tlsstart;
- auto pend = cast(void*)&_tlsend;
- return pbeg[0 .. pend - pbeg];
-}
-
-void finiTLSRanges(void[] rng) nothrow @nogc
-{
-}
-
-void scanTLSRanges(void[] rng, scope void delegate(void* pbeg, void* pend) nothrow dg) nothrow
-{
- if (conservative)
- {
- dg(rng.ptr, rng.ptr + rng.length);
- }
- else
- {
- for (auto p = &_TPbegin; p < &_TPend; )
- {
- uint beg = *p++;
- uint end = beg + cast(uint)((void*).sizeof);
- while (p < &_TPend && *p == end)
- {
- end += (void*).sizeof;
- p++;
- }
- dg(rng.ptr + beg, rng.ptr + end);
- }
- }
-}
-
-private:
-
-__gshared SectionGroup _sections;
-
-// Windows: this gets initialized by minit.asm
-extern(C) __gshared immutable(ModuleInfo*)[] _moduleinfo_array;
-extern(C) void _minit() nothrow @nogc;
-
-immutable(ModuleInfo*)[] getModuleInfos() nothrow @nogc
-out (result)
-{
- foreach (m; result)
- assert(m !is null);
-}
-body
-{
- // _minit directly alters the global _moduleinfo_array
- _minit();
- return _moduleinfo_array;
-}
-
-extern(C)
-{
- extern __gshared
- {
- int _xi_a; // &_xi_a just happens to be start of data segment
- int _edata; // &_edata is start of BSS segment
- int _end; // &_end is past end of BSS
-
- void* _DPbegin; // first entry in the array of pointers addresses
- void* _DPend; // &_DPend points after last entry of array
- uint _TPbegin; // first entry in the array of TLS offsets of pointers
- uint _TPend; // &_DPend points after last entry of array
- }
-
- extern
- {
- int _tlsstart;
- int _tlsend;
- }
-}
diff --git a/libphobos/libdruntime/gcc/sections/win64.d b/libphobos/libdruntime/gcc/sections/win64.d
deleted file mode 100644
index 357940b..0000000
--- a/libphobos/libdruntime/gcc/sections/win64.d
+++ /dev/null
@@ -1,321 +0,0 @@
-// Win64-specific support for sections.
-// Copyright (C) 2019-2021 Free Software Foundation, Inc.
-
-// GCC is free software; you can redistribute it and/or modify it under
-// the terms of the GNU General Public License as published by the Free
-// Software Foundation; either version 3, or (at your option) any later
-// version.
-
-// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-// WARRANTY; without even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-// for more details.
-
-// Under Section 7 of GPL version 3, you are granted additional
-// permissions described in the GCC Runtime Library Exception, version
-// 3.1, as published by the Free Software Foundation.
-
-// You should have received a copy of the GNU General Public License and
-// a copy of the GCC Runtime Library Exception along with this program;
-// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
-// <http://www.gnu.org/licenses/>.
-
-module gcc.sections.win64;
-
-version (CRuntime_Microsoft):
-
-// debug = PRINTF;
-debug(PRINTF) import core.stdc.stdio;
-import core.stdc.stdlib : malloc, free;
-import rt.deh, rt.minfo;
-
-struct SectionGroup
-{
- static int opApply(scope int delegate(ref SectionGroup) dg)
- {
- return dg(_sections);
- }
-
- static int opApplyReverse(scope int delegate(ref SectionGroup) dg)
- {
- return dg(_sections);
- }
-
- @property immutable(ModuleInfo*)[] modules() const nothrow @nogc
- {
- return _moduleGroup.modules;
- }
-
- @property ref inout(ModuleGroup) moduleGroup() inout nothrow @nogc
- {
- return _moduleGroup;
- }
-
- version (Win64)
- @property immutable(FuncTable)[] ehTables() const nothrow @nogc
- {
- auto pbeg = cast(immutable(FuncTable)*)&_deh_beg;
- auto pend = cast(immutable(FuncTable)*)&_deh_end;
- return pbeg[0 .. pend - pbeg];
- }
-
- @property inout(void[])[] gcRanges() inout nothrow @nogc
- {
- return _gcRanges[];
- }
-
-private:
- ModuleGroup _moduleGroup;
- void[][] _gcRanges;
-}
-
-shared(bool) conservative;
-
-void initSections() nothrow @nogc
-{
- _sections._moduleGroup = ModuleGroup(getModuleInfos());
-
- // the ".data" image section includes both object file sections ".data" and ".bss"
- void[] dataSection = findImageSection(".data");
- debug(PRINTF) printf("found .data section: [%p,+%llx]\n", dataSection.ptr,
- cast(ulong)dataSection.length);
-
- import rt.sections;
- conservative = !scanDataSegPrecisely();
-
- if (conservative)
- {
- _sections._gcRanges = (cast(void[]*) malloc((void[]).sizeof))[0..1];
- _sections._gcRanges[0] = dataSection;
- }
- else
- {
- size_t count = &_DP_end - &_DP_beg;
- auto ranges = cast(void[]*) malloc(count * (void[]).sizeof);
- size_t r = 0;
- void* prev = null;
- for (size_t i = 0; i < count; i++)
- {
- auto off = (&_DP_beg)[i];
- if (off == 0) // skip zero entries added by incremental linking
- continue; // assumes there is no D-pointer at the very beginning of .data
- void* addr = dataSection.ptr + off;
- debug(PRINTF) printf(" scan %p\n", addr);
- // combine consecutive pointers into single range
- if (prev + (void*).sizeof == addr)
- ranges[r-1] = ranges[r-1].ptr[0 .. ranges[r-1].length + (void*).sizeof];
- else
- ranges[r++] = (cast(void**)addr)[0..1];
- prev = addr;
- }
- _sections._gcRanges = ranges[0..r];
- }
-}
-
-void finiSections() nothrow @nogc
-{
- .free(cast(void*)_sections.modules.ptr);
- .free(_sections._gcRanges.ptr);
-}
-
-void[] initTLSRanges() nothrow @nogc
-{
- void* pbeg;
- void* pend;
- // with VS2017 15.3.1, the linker no longer puts TLS segments into a
- // separate image section. That way _tls_start and _tls_end no
- // longer generate offsets into .tls, but DATA.
- // Use the TEB entry to find the start of TLS instead and read the
- // length from the TLS directory
- version (D_InlineAsm_X86)
- {
- asm @nogc nothrow
- {
- mov EAX, _tls_index;
- mov ECX, FS:[0x2C]; // _tls_array
- mov EAX, [ECX+4*EAX];
- mov pbeg, EAX;
- add EAX, [_tls_used+4]; // end
- sub EAX, [_tls_used+0]; // start
- mov pend, EAX;
- }
- }
- else version (D_InlineAsm_X86_64)
- {
- asm @nogc nothrow
- {
- xor RAX, RAX;
- mov EAX, _tls_index;
- mov RCX, 0x58;
- mov RCX, GS:[RCX]; // _tls_array (immediate value causes fixup)
- mov RAX, [RCX+8*RAX];
- mov pbeg, RAX;
- add RAX, [_tls_used+8]; // end
- sub RAX, [_tls_used+0]; // start
- mov pend, RAX;
- }
- }
- else
- static assert(false, "Architecture not supported.");
-
- return pbeg[0 .. pend - pbeg];
-}
-
-void finiTLSRanges(void[] rng) nothrow @nogc
-{
-}
-
-void scanTLSRanges(void[] rng, scope void delegate(void* pbeg, void* pend) nothrow dg) nothrow
-{
- if (conservative)
- {
- dg(rng.ptr, rng.ptr + rng.length);
- }
- else
- {
- for (auto p = &_TP_beg; p < &_TP_end; )
- {
- uint beg = *p++;
- uint end = beg + cast(uint)((void*).sizeof);
- while (p < &_TP_end && *p == end)
- {
- end += (void*).sizeof;
- p++;
- }
- dg(rng.ptr + beg, rng.ptr + end);
- }
- }
-}
-
-private:
-__gshared SectionGroup _sections;
-
-extern(C)
-{
- extern __gshared void* _minfo_beg;
- extern __gshared void* _minfo_end;
-}
-
-immutable(ModuleInfo*)[] getModuleInfos() nothrow @nogc
-out (result)
-{
- foreach (m; result)
- assert(m !is null);
-}
-body
-{
- auto m = (cast(immutable(ModuleInfo*)*)&_minfo_beg)[1 .. &_minfo_end - &_minfo_beg];
- /* Because of alignment inserted by the linker, various null pointers
- * are there. We need to filter them out.
- */
- auto p = m.ptr;
- auto pend = m.ptr + m.length;
-
- // count non-null pointers
- size_t cnt;
- for (; p < pend; ++p)
- {
- if (*p !is null) ++cnt;
- }
-
- auto result = (cast(immutable(ModuleInfo)**).malloc(cnt * size_t.sizeof))[0 .. cnt];
-
- p = m.ptr;
- cnt = 0;
- for (; p < pend; ++p)
- if (*p !is null) result[cnt++] = *p;
-
- return cast(immutable)result;
-}
-
-extern(C)
-{
- /* Symbols created by the compiler/linker and inserted into the
- * object file that 'bracket' sections.
- */
- extern __gshared
- {
- void* __ImageBase;
-
- void* _deh_beg;
- void* _deh_end;
-
- uint _DP_beg;
- uint _DP_end;
- uint _TP_beg;
- uint _TP_end;
-
- void*[2] _tls_used; // start, end
- int _tls_index;
- }
-}
-
-/////////////////////////////////////////////////////////////////////
-
-enum IMAGE_DOS_SIGNATURE = 0x5A4D; // MZ
-
-struct IMAGE_DOS_HEADER // DOS .EXE header
-{
- ushort e_magic; // Magic number
- ushort[29] e_res2; // Reserved ushorts
- int e_lfanew; // File address of new exe header
-}
-
-struct IMAGE_FILE_HEADER
-{
- ushort Machine;
- ushort NumberOfSections;
- uint TimeDateStamp;
- uint PointerToSymbolTable;
- uint NumberOfSymbols;
- ushort SizeOfOptionalHeader;
- ushort Characteristics;
-}
-
-struct IMAGE_NT_HEADERS
-{
- uint Signature;
- IMAGE_FILE_HEADER FileHeader;
- // optional header follows
-}
-
-struct IMAGE_SECTION_HEADER
-{
- char[8] Name = 0;
- union {
- uint PhysicalAddress;
- uint VirtualSize;
- }
- uint VirtualAddress;
- uint SizeOfRawData;
- uint PointerToRawData;
- uint PointerToRelocations;
- uint PointerToLinenumbers;
- ushort NumberOfRelocations;
- ushort NumberOfLinenumbers;
- uint Characteristics;
-}
-
-bool compareSectionName(ref IMAGE_SECTION_HEADER section, string name) nothrow @nogc
-{
- if (name[] != section.Name[0 .. name.length])
- return false;
- return name.length == 8 || section.Name[name.length] == 0;
-}
-
-void[] findImageSection(string name) nothrow @nogc
-{
- if (name.length > 8) // section name from string table not supported
- return null;
- IMAGE_DOS_HEADER* doshdr = cast(IMAGE_DOS_HEADER*) &__ImageBase;
- if (doshdr.e_magic != IMAGE_DOS_SIGNATURE)
- return null;
-
- auto nthdr = cast(IMAGE_NT_HEADERS*)(cast(void*)doshdr + doshdr.e_lfanew);
- auto sections = cast(IMAGE_SECTION_HEADER*)(cast(void*)nthdr + IMAGE_NT_HEADERS.sizeof + nthdr.FileHeader.SizeOfOptionalHeader);
- for (ushort i = 0; i < nthdr.FileHeader.NumberOfSections; i++)
- if (compareSectionName (sections[i], name))
- return (cast(void*)&__ImageBase + sections[i].VirtualAddress)[0 .. sections[i].VirtualSize];
-
- return null;
-}