public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/users/ibuclaw/heads/darwin)] libphobos: Align interface of gcc.sections.osx with gcc.sections.elf_shared
@ 2021-01-28 17:31 Iain Buclaw
0 siblings, 0 replies; 12+ messages in thread
From: Iain Buclaw @ 2021-01-28 17:31 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:81a86a17e19ad0b95a63fc2e1855dfd7ff9f9c18
commit 81a86a17e19ad0b95a63fc2e1855dfd7ff9f9c18
Author: Iain Buclaw <ibuclaw@gdcproject.org>
Date: Mon Dec 7 01:25:17 2020 +0100
libphobos: Align interface of gcc.sections.osx with gcc.sections.elf_shared
Diff:
---
libphobos/libdruntime/Makefile.am | 23 +-
libphobos/libdruntime/Makefile.in | 31 +-
libphobos/libdruntime/core/sys/darwin/execinfo.d | 11 +-
libphobos/libdruntime/gcc/sections/common.d | 48 --
libphobos/libdruntime/gcc/sections/osx.d | 569 ++++++++++++++++++++---
5 files changed, 543 insertions(+), 139 deletions(-)
diff --git a/libphobos/libdruntime/Makefile.am b/libphobos/libdruntime/Makefile.am
index 9673613a98b..09e154b6dcf 100644
--- a/libphobos/libdruntime/Makefile.am
+++ b/libphobos/libdruntime/Makefile.am
@@ -185,18 +185,17 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \
gc/impl/conservative/gc.d gc/impl/manual/gc.d gc/os.d gc/pooltable.d \
gc/proxy.d gcc/attribute.d gcc/backtrace.d gcc/builtins.d gcc/deh.d \
gcc/emutls.d gcc/gthread.d gcc/sections/android.d \
- gcc/sections/common.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/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
DRUNTIME_DSOURCES_STDCXX = core/stdcpp/exception.d \
core/stdcpp/typeinfo.d
diff --git a/libphobos/libdruntime/Makefile.in b/libphobos/libdruntime/Makefile.in
index 31eb921ef7f..60211dba4d0 100644
--- a/libphobos/libdruntime/Makefile.in
+++ b/libphobos/libdruntime/Makefile.in
@@ -210,10 +210,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/backtrace.lo \
gcc/builtins.lo gcc/deh.lo gcc/emutls.lo gcc/gthread.lo \
- gcc/sections/android.lo gcc/sections/common.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/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/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 \
@@ -805,18 +804,17 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \
gc/impl/conservative/gc.d gc/impl/manual/gc.d gc/os.d gc/pooltable.d \
gc/proxy.d gcc/attribute.d gcc/backtrace.d gcc/builtins.d gcc/deh.d \
gcc/emutls.d gcc/gthread.d gcc/sections/android.d \
- gcc/sections/common.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/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
DRUNTIME_DSOURCES_STDCXX = core/stdcpp/exception.d \
core/stdcpp/typeinfo.d
@@ -1196,7 +1194,6 @@ gcc/sections/$(am__dirstamp):
@$(MKDIR_P) gcc/sections
@: > gcc/sections/$(am__dirstamp)
gcc/sections/android.lo: gcc/sections/$(am__dirstamp)
-gcc/sections/common.lo: gcc/sections/$(am__dirstamp)
gcc/sections/elf_shared.lo: gcc/sections/$(am__dirstamp)
gcc/sections/osx.lo: gcc/sections/$(am__dirstamp)
gcc/sections/package.lo: gcc/sections/$(am__dirstamp)
diff --git a/libphobos/libdruntime/core/sys/darwin/execinfo.d b/libphobos/libdruntime/core/sys/darwin/execinfo.d
index c929cc2f88d..d9607f392eb 100644
--- a/libphobos/libdruntime/core/sys/darwin/execinfo.d
+++ b/libphobos/libdruntime/core/sys/darwin/execinfo.d
@@ -21,6 +21,11 @@ extern (C):
nothrow:
@nogc:
-int backtrace(void** buffer, int size);
-char** backtrace_symbols(const(void*)* buffer, int size);
-void backtrace_symbols_fd(const(void*)* buffer, int size, int fd);
+import core.sys.darwin.config;
+
+static if (__traits(getTargetInfo, "osxVersionMin") >= __MAC_10_5)
+{
+ int backtrace(void** buffer, int size);
+ char** backtrace_symbols(const(void*)* buffer, int size);
+ void backtrace_symbols_fd(const(void*)* buffer, int size, int fd);
+}
diff --git a/libphobos/libdruntime/gcc/sections/common.d b/libphobos/libdruntime/gcc/sections/common.d
deleted file mode 100644
index b2d2322347d..00000000000
--- a/libphobos/libdruntime/gcc/sections/common.d
+++ /dev/null
@@ -1,48 +0,0 @@
-// Common support routines for retrieving platform-specific sections.
-// Copyright (C) 2019 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 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.).
- */
-void safeAssert(bool condition, scope string msg, size_t line = __LINE__) @nogc nothrow @safe
-{
- import core.internal.abort;
- condition || abort(msg, __FILE__, line);
-}
-
-/****
- * 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]; }
diff --git a/libphobos/libdruntime/gcc/sections/osx.d b/libphobos/libdruntime/gcc/sections/osx.d
index 2f807bb98e0..fef19f761c5 100644
--- a/libphobos/libdruntime/gcc/sections/osx.d
+++ b/libphobos/libdruntime/gcc/sections/osx.d
@@ -24,17 +24,31 @@ module gcc.sections.osx;
version (OSX):
-import gcc.sections.common;
-
+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;
version (GNU_EMUTLS)
import gcc.emutls;
+/****
+ * 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.).
+ */
+void safeAssert(bool condition, scope string msg, size_t line = __LINE__) @nogc nothrow @safe
+{
+ import core.internal.abort;
+ condition || abort(msg, __FILE__, line);
+}
+
alias DSO SectionGroup;
struct DSO
{
@@ -74,8 +88,22 @@ struct DSO
}
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
+ }
}
/****
@@ -99,63 +127,185 @@ void finiSections() nothrow @nogc
_isRuntimeInitialized = false;
}
-void[]* initTLSRanges() nothrow @nogc
-{
- return null;
-}
+alias ScanDG = void delegate(void* pbeg, void* pend) nothrow;
-void finiTLSRanges(void[]* rng) nothrow @nogc
+version (Shared)
{
-}
+ /***
+ * Called once per thread; returns array of thread local storage ranges
+ */
+ Array!(ThreadDSO)* initTLSRanges() @nogc nothrow
+ {
+ return &_loadedDSOs();
+ }
-void scanTLSRanges(void[]* rng, scope void delegate(void* pbeg, void* pend) nothrow dg) nothrow
-{
- version (GNU_EMUTLS)
- _d_emutls_scan(dg);
- else
- static assert(0, "Native TLS unimplemented");
-}
+ 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");
+ }
-version (Shared)
-{
// interface for core.thread to inherit loaded libraries
void* pinLoadedLibraries() nothrow @nogc
{
- return null;
+ 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;
}
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.
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.
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:
-/*
- * Static DSOs loaded by the runtime linker. This includes the
- * executable. These can't be unloaded.
- */
-@property ref Array!(DSO*) _loadedDSOs() @nogc nothrow
+version (Shared)
{
- __gshared Array!(DSO*) x;
- return x;
+ /*
+ * 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;
+ }
-/*
- * Set to true during rt_loadLibrary/rt_unloadLibrary calls.
- */
-enum _rtLoading = false;
+ enum _rtLoading = false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Compiler to runtime interface.
+///////////////////////////////////////////////////////////////////////////////
struct MachHeader
{
@@ -163,9 +313,18 @@ struct MachHeader
intptr_t slide; // virtural memory address slide amount
}
-///////////////////////////////////////////////////////////////////////////////
-// 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().
@@ -180,27 +339,57 @@ extern(C) void _d_dso_registry(CompilerDSOData* data)
// 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 info = void;
- const headerFound = findDSOHeaderForAddr(data._slot, &info);
+ MachHeader header = void;
+ const headerFound = findImageHeaderForAddr(data._slot, header);
safeAssert(headerFound, "Failed to find image header.");
- foreach (e; dataSegs)
+ 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
{
- 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]);
+ foreach (p; _loadedDSOs)
+ safeAssert(p !is pdso, "DSO already registered.");
+ _loadedDSOs.insertBack(pdso);
}
- 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
@@ -208,22 +397,274 @@ extern(C) void _d_dso_registry(CompilerDSOData* data)
DSO* pdso = cast(DSO*)*data._slot;
*data._slot = null;
- // static DSOs are unloaded in reverse order
- safeAssert(pdso == _loadedDSOs.back, "DSO being unregistered isn't current last one.");
- _loadedDSOs.popBack();
+ // 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();
+ }
- pdso._gcRanges.reset();
- .free(pdso);
+ 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
@@ -231,28 +672,38 @@ extern(C) void _d_dso_registry(CompilerDSOData* data)
* true if found, and *result is filled in
*/
-bool findDSOHeaderForAddr(in void* addr, MachHeader* result)
+bool findImageHeaderForAddr(in void* addr, out MachHeader result)
{
+ Dl_info info;
+ if (dladdr(addr, &info) == 0)
+ return false;
+
foreach (i; 0 .. _dyld_image_count())
{
- const header = _dyld_get_image_header(i);
- const slide = _dyld_get_image_vmaddr_slide(i);
- const section = getSection(header, slide, SEG_DATA, SECT_DATA);
-
- // less than base address of section means quick reject
- if (!section.length || addr < section.ptr)
- continue;
-
- if (addr < section.ptr + section.length)
+ if (info.dli_fbase == _dyld_get_image_header(i))
{
- result.header = header;
- result.slide = slide;
+ 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;
^ permalink raw reply [flat|nested] 12+ messages in thread
* [gcc(refs/users/ibuclaw/heads/darwin)] libphobos: Align interface of gcc.sections.osx with gcc.sections.elf_shared
@ 2021-09-17 14:34 Iain Buclaw
0 siblings, 0 replies; 12+ messages in thread
From: Iain Buclaw @ 2021-09-17 14:34 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:a2f5cd6d62f8ea06e8082487de801f55334e84a6
commit a2f5cd6d62f8ea06e8082487de801f55334e84a6
Author: Iain Buclaw <ibuclaw@gdcproject.org>
Date: Mon Dec 7 01:25:17 2020 +0100
libphobos: Align interface of gcc.sections.osx with gcc.sections.elf_shared
Diff:
---
libphobos/libdruntime/core/sys/darwin/execinfo.d | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/libphobos/libdruntime/core/sys/darwin/execinfo.d b/libphobos/libdruntime/core/sys/darwin/execinfo.d
index c929cc2f88d..d9607f392eb 100644
--- a/libphobos/libdruntime/core/sys/darwin/execinfo.d
+++ b/libphobos/libdruntime/core/sys/darwin/execinfo.d
@@ -21,6 +21,11 @@ extern (C):
nothrow:
@nogc:
-int backtrace(void** buffer, int size);
-char** backtrace_symbols(const(void*)* buffer, int size);
-void backtrace_symbols_fd(const(void*)* buffer, int size, int fd);
+import core.sys.darwin.config;
+
+static if (__traits(getTargetInfo, "osxVersionMin") >= __MAC_10_5)
+{
+ int backtrace(void** buffer, int size);
+ char** backtrace_symbols(const(void*)* buffer, int size);
+ void backtrace_symbols_fd(const(void*)* buffer, int size, int fd);
+}
^ permalink raw reply [flat|nested] 12+ messages in thread
* [gcc(refs/users/ibuclaw/heads/darwin)] libphobos: Align interface of gcc.sections.osx with gcc.sections.elf_shared
@ 2021-04-19 18:06 Iain Buclaw
0 siblings, 0 replies; 12+ messages in thread
From: Iain Buclaw @ 2021-04-19 18:06 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:29c699dd18da03d2dda9cfb92070d9853205c1c3
commit 29c699dd18da03d2dda9cfb92070d9853205c1c3
Author: Iain Buclaw <ibuclaw@gdcproject.org>
Date: Mon Dec 7 01:25:17 2020 +0100
libphobos: Align interface of gcc.sections.osx with gcc.sections.elf_shared
Diff:
---
libphobos/libdruntime/core/sys/darwin/execinfo.d | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/libphobos/libdruntime/core/sys/darwin/execinfo.d b/libphobos/libdruntime/core/sys/darwin/execinfo.d
index c929cc2f88d..d9607f392eb 100644
--- a/libphobos/libdruntime/core/sys/darwin/execinfo.d
+++ b/libphobos/libdruntime/core/sys/darwin/execinfo.d
@@ -21,6 +21,11 @@ extern (C):
nothrow:
@nogc:
-int backtrace(void** buffer, int size);
-char** backtrace_symbols(const(void*)* buffer, int size);
-void backtrace_symbols_fd(const(void*)* buffer, int size, int fd);
+import core.sys.darwin.config;
+
+static if (__traits(getTargetInfo, "osxVersionMin") >= __MAC_10_5)
+{
+ int backtrace(void** buffer, int size);
+ char** backtrace_symbols(const(void*)* buffer, int size);
+ void backtrace_symbols_fd(const(void*)* buffer, int size, int fd);
+}
^ permalink raw reply [flat|nested] 12+ messages in thread
* [gcc(refs/users/ibuclaw/heads/darwin)] libphobos: Align interface of gcc.sections.osx with gcc.sections.elf_shared
@ 2021-04-10 17:01 Iain Buclaw
0 siblings, 0 replies; 12+ messages in thread
From: Iain Buclaw @ 2021-04-10 17:01 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:d2984ae9a7635dc4e65d23743616e064d6bf7918
commit d2984ae9a7635dc4e65d23743616e064d6bf7918
Author: Iain Buclaw <ibuclaw@gdcproject.org>
Date: Mon Dec 7 01:25:17 2020 +0100
libphobos: Align interface of gcc.sections.osx with gcc.sections.elf_shared
Diff:
---
libphobos/libdruntime/core/sys/darwin/execinfo.d | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/libphobos/libdruntime/core/sys/darwin/execinfo.d b/libphobos/libdruntime/core/sys/darwin/execinfo.d
index c929cc2f88d..d9607f392eb 100644
--- a/libphobos/libdruntime/core/sys/darwin/execinfo.d
+++ b/libphobos/libdruntime/core/sys/darwin/execinfo.d
@@ -21,6 +21,11 @@ extern (C):
nothrow:
@nogc:
-int backtrace(void** buffer, int size);
-char** backtrace_symbols(const(void*)* buffer, int size);
-void backtrace_symbols_fd(const(void*)* buffer, int size, int fd);
+import core.sys.darwin.config;
+
+static if (__traits(getTargetInfo, "osxVersionMin") >= __MAC_10_5)
+{
+ int backtrace(void** buffer, int size);
+ char** backtrace_symbols(const(void*)* buffer, int size);
+ void backtrace_symbols_fd(const(void*)* buffer, int size, int fd);
+}
^ permalink raw reply [flat|nested] 12+ messages in thread
* [gcc(refs/users/ibuclaw/heads/darwin)] libphobos: Align interface of gcc.sections.osx with gcc.sections.elf_shared
@ 2021-04-10 15:04 Iain Buclaw
0 siblings, 0 replies; 12+ messages in thread
From: Iain Buclaw @ 2021-04-10 15:04 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:3125c2c54d5c2e35b2f7c2be8751d036987d4cb7
commit 3125c2c54d5c2e35b2f7c2be8751d036987d4cb7
Author: Iain Buclaw <ibuclaw@gdcproject.org>
Date: Mon Dec 7 01:25:17 2020 +0100
libphobos: Align interface of gcc.sections.osx with gcc.sections.elf_shared
Diff:
---
libphobos/libdruntime/core/sys/darwin/execinfo.d | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/libphobos/libdruntime/core/sys/darwin/execinfo.d b/libphobos/libdruntime/core/sys/darwin/execinfo.d
index c929cc2f88d..d9607f392eb 100644
--- a/libphobos/libdruntime/core/sys/darwin/execinfo.d
+++ b/libphobos/libdruntime/core/sys/darwin/execinfo.d
@@ -21,6 +21,11 @@ extern (C):
nothrow:
@nogc:
-int backtrace(void** buffer, int size);
-char** backtrace_symbols(const(void*)* buffer, int size);
-void backtrace_symbols_fd(const(void*)* buffer, int size, int fd);
+import core.sys.darwin.config;
+
+static if (__traits(getTargetInfo, "osxVersionMin") >= __MAC_10_5)
+{
+ int backtrace(void** buffer, int size);
+ char** backtrace_symbols(const(void*)* buffer, int size);
+ void backtrace_symbols_fd(const(void*)* buffer, int size, int fd);
+}
^ permalink raw reply [flat|nested] 12+ messages in thread
* [gcc(refs/users/ibuclaw/heads/darwin)] libphobos: Align interface of gcc.sections.osx with gcc.sections.elf_shared
@ 2021-03-14 22:00 Iain Buclaw
0 siblings, 0 replies; 12+ messages in thread
From: Iain Buclaw @ 2021-03-14 22:00 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:a9a5a783eca4ba7e0a93b3c56f983b82b9d3db3a
commit a9a5a783eca4ba7e0a93b3c56f983b82b9d3db3a
Author: Iain Buclaw <ibuclaw@gdcproject.org>
Date: Mon Dec 7 01:25:17 2020 +0100
libphobos: Align interface of gcc.sections.osx with gcc.sections.elf_shared
Diff:
---
libphobos/libdruntime/Makefile.am | 16 +-
libphobos/libdruntime/Makefile.in | 24 +-
libphobos/libdruntime/core/sys/darwin/execinfo.d | 11 +-
libphobos/libdruntime/gcc/sections/common.d | 48 --
libphobos/libdruntime/gcc/sections/osx.d | 569 ++++++++++++++++++++---
5 files changed, 537 insertions(+), 131 deletions(-)
diff --git a/libphobos/libdruntime/Makefile.am b/libphobos/libdruntime/Makefile.am
index 9d66f07c19a..f6c1fc55d9e 100644
--- a/libphobos/libdruntime/Makefile.am
+++ b/libphobos/libdruntime/Makefile.am
@@ -186,14 +186,14 @@ 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/backtrace.d \
gcc/builtins.d gcc/deh.d gcc/emutls.d gcc/gthread.d \
- gcc/sections/android.d gcc/sections/common.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 \
+ 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 \
diff --git a/libphobos/libdruntime/Makefile.in b/libphobos/libdruntime/Makefile.in
index 1bb20559e20..0782f4f0b53 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/backtrace.lo \
gcc/builtins.lo gcc/deh.lo gcc/emutls.lo gcc/gthread.lo \
- gcc/sections/android.lo gcc/sections/common.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/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/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 \
@@ -814,14 +813,14 @@ 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/backtrace.d \
gcc/builtins.d gcc/deh.d gcc/emutls.d gcc/gthread.d \
- gcc/sections/android.d gcc/sections/common.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 \
+ 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 \
@@ -1213,7 +1212,6 @@ gcc/sections/$(am__dirstamp):
@$(MKDIR_P) gcc/sections
@: > gcc/sections/$(am__dirstamp)
gcc/sections/android.lo: gcc/sections/$(am__dirstamp)
-gcc/sections/common.lo: gcc/sections/$(am__dirstamp)
gcc/sections/elf_shared.lo: gcc/sections/$(am__dirstamp)
gcc/sections/osx.lo: gcc/sections/$(am__dirstamp)
gcc/sections/package.lo: gcc/sections/$(am__dirstamp)
diff --git a/libphobos/libdruntime/core/sys/darwin/execinfo.d b/libphobos/libdruntime/core/sys/darwin/execinfo.d
index c929cc2f88d..d9607f392eb 100644
--- a/libphobos/libdruntime/core/sys/darwin/execinfo.d
+++ b/libphobos/libdruntime/core/sys/darwin/execinfo.d
@@ -21,6 +21,11 @@ extern (C):
nothrow:
@nogc:
-int backtrace(void** buffer, int size);
-char** backtrace_symbols(const(void*)* buffer, int size);
-void backtrace_symbols_fd(const(void*)* buffer, int size, int fd);
+import core.sys.darwin.config;
+
+static if (__traits(getTargetInfo, "osxVersionMin") >= __MAC_10_5)
+{
+ int backtrace(void** buffer, int size);
+ char** backtrace_symbols(const(void*)* buffer, int size);
+ void backtrace_symbols_fd(const(void*)* buffer, int size, int fd);
+}
diff --git a/libphobos/libdruntime/gcc/sections/common.d b/libphobos/libdruntime/gcc/sections/common.d
deleted file mode 100644
index b2d2322347d..00000000000
--- a/libphobos/libdruntime/gcc/sections/common.d
+++ /dev/null
@@ -1,48 +0,0 @@
-// Common support routines for retrieving platform-specific sections.
-// Copyright (C) 2019 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 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.).
- */
-void safeAssert(bool condition, scope string msg, size_t line = __LINE__) @nogc nothrow @safe
-{
- import core.internal.abort;
- condition || abort(msg, __FILE__, line);
-}
-
-/****
- * 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]; }
diff --git a/libphobos/libdruntime/gcc/sections/osx.d b/libphobos/libdruntime/gcc/sections/osx.d
index 2f807bb98e0..fef19f761c5 100644
--- a/libphobos/libdruntime/gcc/sections/osx.d
+++ b/libphobos/libdruntime/gcc/sections/osx.d
@@ -24,17 +24,31 @@ module gcc.sections.osx;
version (OSX):
-import gcc.sections.common;
-
+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;
version (GNU_EMUTLS)
import gcc.emutls;
+/****
+ * 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.).
+ */
+void safeAssert(bool condition, scope string msg, size_t line = __LINE__) @nogc nothrow @safe
+{
+ import core.internal.abort;
+ condition || abort(msg, __FILE__, line);
+}
+
alias DSO SectionGroup;
struct DSO
{
@@ -74,8 +88,22 @@ struct DSO
}
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
+ }
}
/****
@@ -99,63 +127,185 @@ void finiSections() nothrow @nogc
_isRuntimeInitialized = false;
}
-void[]* initTLSRanges() nothrow @nogc
-{
- return null;
-}
+alias ScanDG = void delegate(void* pbeg, void* pend) nothrow;
-void finiTLSRanges(void[]* rng) nothrow @nogc
+version (Shared)
{
-}
+ /***
+ * Called once per thread; returns array of thread local storage ranges
+ */
+ Array!(ThreadDSO)* initTLSRanges() @nogc nothrow
+ {
+ return &_loadedDSOs();
+ }
-void scanTLSRanges(void[]* rng, scope void delegate(void* pbeg, void* pend) nothrow dg) nothrow
-{
- version (GNU_EMUTLS)
- _d_emutls_scan(dg);
- else
- static assert(0, "Native TLS unimplemented");
-}
+ 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");
+ }
-version (Shared)
-{
// interface for core.thread to inherit loaded libraries
void* pinLoadedLibraries() nothrow @nogc
{
- return null;
+ 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;
}
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.
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.
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:
-/*
- * Static DSOs loaded by the runtime linker. This includes the
- * executable. These can't be unloaded.
- */
-@property ref Array!(DSO*) _loadedDSOs() @nogc nothrow
+version (Shared)
{
- __gshared Array!(DSO*) x;
- return x;
+ /*
+ * 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;
+ }
-/*
- * Set to true during rt_loadLibrary/rt_unloadLibrary calls.
- */
-enum _rtLoading = false;
+ enum _rtLoading = false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Compiler to runtime interface.
+///////////////////////////////////////////////////////////////////////////////
struct MachHeader
{
@@ -163,9 +313,18 @@ struct MachHeader
intptr_t slide; // virtural memory address slide amount
}
-///////////////////////////////////////////////////////////////////////////////
-// 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().
@@ -180,27 +339,57 @@ extern(C) void _d_dso_registry(CompilerDSOData* data)
// 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 info = void;
- const headerFound = findDSOHeaderForAddr(data._slot, &info);
+ MachHeader header = void;
+ const headerFound = findImageHeaderForAddr(data._slot, header);
safeAssert(headerFound, "Failed to find image header.");
- foreach (e; dataSegs)
+ 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
{
- 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]);
+ foreach (p; _loadedDSOs)
+ safeAssert(p !is pdso, "DSO already registered.");
+ _loadedDSOs.insertBack(pdso);
}
- 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
@@ -208,22 +397,274 @@ extern(C) void _d_dso_registry(CompilerDSOData* data)
DSO* pdso = cast(DSO*)*data._slot;
*data._slot = null;
- // static DSOs are unloaded in reverse order
- safeAssert(pdso == _loadedDSOs.back, "DSO being unregistered isn't current last one.");
- _loadedDSOs.popBack();
+ // 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();
+ }
- pdso._gcRanges.reset();
- .free(pdso);
+ 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
@@ -231,28 +672,38 @@ extern(C) void _d_dso_registry(CompilerDSOData* data)
* true if found, and *result is filled in
*/
-bool findDSOHeaderForAddr(in void* addr, MachHeader* result)
+bool findImageHeaderForAddr(in void* addr, out MachHeader result)
{
+ Dl_info info;
+ if (dladdr(addr, &info) == 0)
+ return false;
+
foreach (i; 0 .. _dyld_image_count())
{
- const header = _dyld_get_image_header(i);
- const slide = _dyld_get_image_vmaddr_slide(i);
- const section = getSection(header, slide, SEG_DATA, SECT_DATA);
-
- // less than base address of section means quick reject
- if (!section.length || addr < section.ptr)
- continue;
-
- if (addr < section.ptr + section.length)
+ if (info.dli_fbase == _dyld_get_image_header(i))
{
- result.header = header;
- result.slide = slide;
+ 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;
^ permalink raw reply [flat|nested] 12+ messages in thread
* [gcc(refs/users/ibuclaw/heads/darwin)] libphobos: Align interface of gcc.sections.osx with gcc.sections.elf_shared
@ 2021-03-07 17:01 Iain Buclaw
0 siblings, 0 replies; 12+ messages in thread
From: Iain Buclaw @ 2021-03-07 17:01 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:5332ea0b84daeb0ed6b8a44dc59d62cd6fc2a1ec
commit 5332ea0b84daeb0ed6b8a44dc59d62cd6fc2a1ec
Author: Iain Buclaw <ibuclaw@gdcproject.org>
Date: Mon Dec 7 01:25:17 2020 +0100
libphobos: Align interface of gcc.sections.osx with gcc.sections.elf_shared
Diff:
---
libphobos/libdruntime/Makefile.am | 16 +-
libphobos/libdruntime/Makefile.in | 24 +-
libphobos/libdruntime/core/sys/darwin/execinfo.d | 11 +-
libphobos/libdruntime/gcc/sections/common.d | 48 --
libphobos/libdruntime/gcc/sections/osx.d | 569 ++++++++++++++++++++---
5 files changed, 537 insertions(+), 131 deletions(-)
diff --git a/libphobos/libdruntime/Makefile.am b/libphobos/libdruntime/Makefile.am
index 9d66f07c19a..f6c1fc55d9e 100644
--- a/libphobos/libdruntime/Makefile.am
+++ b/libphobos/libdruntime/Makefile.am
@@ -186,14 +186,14 @@ 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/backtrace.d \
gcc/builtins.d gcc/deh.d gcc/emutls.d gcc/gthread.d \
- gcc/sections/android.d gcc/sections/common.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 \
+ 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 \
diff --git a/libphobos/libdruntime/Makefile.in b/libphobos/libdruntime/Makefile.in
index 1bb20559e20..0782f4f0b53 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/backtrace.lo \
gcc/builtins.lo gcc/deh.lo gcc/emutls.lo gcc/gthread.lo \
- gcc/sections/android.lo gcc/sections/common.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/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/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 \
@@ -814,14 +813,14 @@ 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/backtrace.d \
gcc/builtins.d gcc/deh.d gcc/emutls.d gcc/gthread.d \
- gcc/sections/android.d gcc/sections/common.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 \
+ 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 \
@@ -1213,7 +1212,6 @@ gcc/sections/$(am__dirstamp):
@$(MKDIR_P) gcc/sections
@: > gcc/sections/$(am__dirstamp)
gcc/sections/android.lo: gcc/sections/$(am__dirstamp)
-gcc/sections/common.lo: gcc/sections/$(am__dirstamp)
gcc/sections/elf_shared.lo: gcc/sections/$(am__dirstamp)
gcc/sections/osx.lo: gcc/sections/$(am__dirstamp)
gcc/sections/package.lo: gcc/sections/$(am__dirstamp)
diff --git a/libphobos/libdruntime/core/sys/darwin/execinfo.d b/libphobos/libdruntime/core/sys/darwin/execinfo.d
index c929cc2f88d..d9607f392eb 100644
--- a/libphobos/libdruntime/core/sys/darwin/execinfo.d
+++ b/libphobos/libdruntime/core/sys/darwin/execinfo.d
@@ -21,6 +21,11 @@ extern (C):
nothrow:
@nogc:
-int backtrace(void** buffer, int size);
-char** backtrace_symbols(const(void*)* buffer, int size);
-void backtrace_symbols_fd(const(void*)* buffer, int size, int fd);
+import core.sys.darwin.config;
+
+static if (__traits(getTargetInfo, "osxVersionMin") >= __MAC_10_5)
+{
+ int backtrace(void** buffer, int size);
+ char** backtrace_symbols(const(void*)* buffer, int size);
+ void backtrace_symbols_fd(const(void*)* buffer, int size, int fd);
+}
diff --git a/libphobos/libdruntime/gcc/sections/common.d b/libphobos/libdruntime/gcc/sections/common.d
deleted file mode 100644
index b2d2322347d..00000000000
--- a/libphobos/libdruntime/gcc/sections/common.d
+++ /dev/null
@@ -1,48 +0,0 @@
-// Common support routines for retrieving platform-specific sections.
-// Copyright (C) 2019 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 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.).
- */
-void safeAssert(bool condition, scope string msg, size_t line = __LINE__) @nogc nothrow @safe
-{
- import core.internal.abort;
- condition || abort(msg, __FILE__, line);
-}
-
-/****
- * 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]; }
diff --git a/libphobos/libdruntime/gcc/sections/osx.d b/libphobos/libdruntime/gcc/sections/osx.d
index 2f807bb98e0..fef19f761c5 100644
--- a/libphobos/libdruntime/gcc/sections/osx.d
+++ b/libphobos/libdruntime/gcc/sections/osx.d
@@ -24,17 +24,31 @@ module gcc.sections.osx;
version (OSX):
-import gcc.sections.common;
-
+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;
version (GNU_EMUTLS)
import gcc.emutls;
+/****
+ * 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.).
+ */
+void safeAssert(bool condition, scope string msg, size_t line = __LINE__) @nogc nothrow @safe
+{
+ import core.internal.abort;
+ condition || abort(msg, __FILE__, line);
+}
+
alias DSO SectionGroup;
struct DSO
{
@@ -74,8 +88,22 @@ struct DSO
}
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
+ }
}
/****
@@ -99,63 +127,185 @@ void finiSections() nothrow @nogc
_isRuntimeInitialized = false;
}
-void[]* initTLSRanges() nothrow @nogc
-{
- return null;
-}
+alias ScanDG = void delegate(void* pbeg, void* pend) nothrow;
-void finiTLSRanges(void[]* rng) nothrow @nogc
+version (Shared)
{
-}
+ /***
+ * Called once per thread; returns array of thread local storage ranges
+ */
+ Array!(ThreadDSO)* initTLSRanges() @nogc nothrow
+ {
+ return &_loadedDSOs();
+ }
-void scanTLSRanges(void[]* rng, scope void delegate(void* pbeg, void* pend) nothrow dg) nothrow
-{
- version (GNU_EMUTLS)
- _d_emutls_scan(dg);
- else
- static assert(0, "Native TLS unimplemented");
-}
+ 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");
+ }
-version (Shared)
-{
// interface for core.thread to inherit loaded libraries
void* pinLoadedLibraries() nothrow @nogc
{
- return null;
+ 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;
}
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.
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.
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:
-/*
- * Static DSOs loaded by the runtime linker. This includes the
- * executable. These can't be unloaded.
- */
-@property ref Array!(DSO*) _loadedDSOs() @nogc nothrow
+version (Shared)
{
- __gshared Array!(DSO*) x;
- return x;
+ /*
+ * 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;
+ }
-/*
- * Set to true during rt_loadLibrary/rt_unloadLibrary calls.
- */
-enum _rtLoading = false;
+ enum _rtLoading = false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Compiler to runtime interface.
+///////////////////////////////////////////////////////////////////////////////
struct MachHeader
{
@@ -163,9 +313,18 @@ struct MachHeader
intptr_t slide; // virtural memory address slide amount
}
-///////////////////////////////////////////////////////////////////////////////
-// 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().
@@ -180,27 +339,57 @@ extern(C) void _d_dso_registry(CompilerDSOData* data)
// 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 info = void;
- const headerFound = findDSOHeaderForAddr(data._slot, &info);
+ MachHeader header = void;
+ const headerFound = findImageHeaderForAddr(data._slot, header);
safeAssert(headerFound, "Failed to find image header.");
- foreach (e; dataSegs)
+ 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
{
- 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]);
+ foreach (p; _loadedDSOs)
+ safeAssert(p !is pdso, "DSO already registered.");
+ _loadedDSOs.insertBack(pdso);
}
- 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
@@ -208,22 +397,274 @@ extern(C) void _d_dso_registry(CompilerDSOData* data)
DSO* pdso = cast(DSO*)*data._slot;
*data._slot = null;
- // static DSOs are unloaded in reverse order
- safeAssert(pdso == _loadedDSOs.back, "DSO being unregistered isn't current last one.");
- _loadedDSOs.popBack();
+ // 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();
+ }
- pdso._gcRanges.reset();
- .free(pdso);
+ 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
@@ -231,28 +672,38 @@ extern(C) void _d_dso_registry(CompilerDSOData* data)
* true if found, and *result is filled in
*/
-bool findDSOHeaderForAddr(in void* addr, MachHeader* result)
+bool findImageHeaderForAddr(in void* addr, out MachHeader result)
{
+ Dl_info info;
+ if (dladdr(addr, &info) == 0)
+ return false;
+
foreach (i; 0 .. _dyld_image_count())
{
- const header = _dyld_get_image_header(i);
- const slide = _dyld_get_image_vmaddr_slide(i);
- const section = getSection(header, slide, SEG_DATA, SECT_DATA);
-
- // less than base address of section means quick reject
- if (!section.length || addr < section.ptr)
- continue;
-
- if (addr < section.ptr + section.length)
+ if (info.dli_fbase == _dyld_get_image_header(i))
{
- result.header = header;
- result.slide = slide;
+ 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;
^ permalink raw reply [flat|nested] 12+ messages in thread
* [gcc(refs/users/ibuclaw/heads/darwin)] libphobos: Align interface of gcc.sections.osx with gcc.sections.elf_shared
@ 2021-01-30 19:08 Iain Buclaw
0 siblings, 0 replies; 12+ messages in thread
From: Iain Buclaw @ 2021-01-30 19:08 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:e98c0e7eb7c646e9e930cf6d0c9adc1d7dcca827
commit e98c0e7eb7c646e9e930cf6d0c9adc1d7dcca827
Author: Iain Buclaw <ibuclaw@gdcproject.org>
Date: Mon Dec 7 01:25:17 2020 +0100
libphobos: Align interface of gcc.sections.osx with gcc.sections.elf_shared
Diff:
---
libphobos/libdruntime/Makefile.am | 23 +-
libphobos/libdruntime/Makefile.in | 31 +-
libphobos/libdruntime/core/sys/darwin/execinfo.d | 11 +-
libphobos/libdruntime/gcc/sections/common.d | 48 --
libphobos/libdruntime/gcc/sections/osx.d | 569 ++++++++++++++++++++---
5 files changed, 543 insertions(+), 139 deletions(-)
diff --git a/libphobos/libdruntime/Makefile.am b/libphobos/libdruntime/Makefile.am
index 9673613a98b..09e154b6dcf 100644
--- a/libphobos/libdruntime/Makefile.am
+++ b/libphobos/libdruntime/Makefile.am
@@ -185,18 +185,17 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \
gc/impl/conservative/gc.d gc/impl/manual/gc.d gc/os.d gc/pooltable.d \
gc/proxy.d gcc/attribute.d gcc/backtrace.d gcc/builtins.d gcc/deh.d \
gcc/emutls.d gcc/gthread.d gcc/sections/android.d \
- gcc/sections/common.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/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
DRUNTIME_DSOURCES_STDCXX = core/stdcpp/exception.d \
core/stdcpp/typeinfo.d
diff --git a/libphobos/libdruntime/Makefile.in b/libphobos/libdruntime/Makefile.in
index 31eb921ef7f..60211dba4d0 100644
--- a/libphobos/libdruntime/Makefile.in
+++ b/libphobos/libdruntime/Makefile.in
@@ -210,10 +210,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/backtrace.lo \
gcc/builtins.lo gcc/deh.lo gcc/emutls.lo gcc/gthread.lo \
- gcc/sections/android.lo gcc/sections/common.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/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/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 \
@@ -805,18 +804,17 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \
gc/impl/conservative/gc.d gc/impl/manual/gc.d gc/os.d gc/pooltable.d \
gc/proxy.d gcc/attribute.d gcc/backtrace.d gcc/builtins.d gcc/deh.d \
gcc/emutls.d gcc/gthread.d gcc/sections/android.d \
- gcc/sections/common.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/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
DRUNTIME_DSOURCES_STDCXX = core/stdcpp/exception.d \
core/stdcpp/typeinfo.d
@@ -1196,7 +1194,6 @@ gcc/sections/$(am__dirstamp):
@$(MKDIR_P) gcc/sections
@: > gcc/sections/$(am__dirstamp)
gcc/sections/android.lo: gcc/sections/$(am__dirstamp)
-gcc/sections/common.lo: gcc/sections/$(am__dirstamp)
gcc/sections/elf_shared.lo: gcc/sections/$(am__dirstamp)
gcc/sections/osx.lo: gcc/sections/$(am__dirstamp)
gcc/sections/package.lo: gcc/sections/$(am__dirstamp)
diff --git a/libphobos/libdruntime/core/sys/darwin/execinfo.d b/libphobos/libdruntime/core/sys/darwin/execinfo.d
index c929cc2f88d..d9607f392eb 100644
--- a/libphobos/libdruntime/core/sys/darwin/execinfo.d
+++ b/libphobos/libdruntime/core/sys/darwin/execinfo.d
@@ -21,6 +21,11 @@ extern (C):
nothrow:
@nogc:
-int backtrace(void** buffer, int size);
-char** backtrace_symbols(const(void*)* buffer, int size);
-void backtrace_symbols_fd(const(void*)* buffer, int size, int fd);
+import core.sys.darwin.config;
+
+static if (__traits(getTargetInfo, "osxVersionMin") >= __MAC_10_5)
+{
+ int backtrace(void** buffer, int size);
+ char** backtrace_symbols(const(void*)* buffer, int size);
+ void backtrace_symbols_fd(const(void*)* buffer, int size, int fd);
+}
diff --git a/libphobos/libdruntime/gcc/sections/common.d b/libphobos/libdruntime/gcc/sections/common.d
deleted file mode 100644
index b2d2322347d..00000000000
--- a/libphobos/libdruntime/gcc/sections/common.d
+++ /dev/null
@@ -1,48 +0,0 @@
-// Common support routines for retrieving platform-specific sections.
-// Copyright (C) 2019 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 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.).
- */
-void safeAssert(bool condition, scope string msg, size_t line = __LINE__) @nogc nothrow @safe
-{
- import core.internal.abort;
- condition || abort(msg, __FILE__, line);
-}
-
-/****
- * 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]; }
diff --git a/libphobos/libdruntime/gcc/sections/osx.d b/libphobos/libdruntime/gcc/sections/osx.d
index 2f807bb98e0..fef19f761c5 100644
--- a/libphobos/libdruntime/gcc/sections/osx.d
+++ b/libphobos/libdruntime/gcc/sections/osx.d
@@ -24,17 +24,31 @@ module gcc.sections.osx;
version (OSX):
-import gcc.sections.common;
-
+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;
version (GNU_EMUTLS)
import gcc.emutls;
+/****
+ * 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.).
+ */
+void safeAssert(bool condition, scope string msg, size_t line = __LINE__) @nogc nothrow @safe
+{
+ import core.internal.abort;
+ condition || abort(msg, __FILE__, line);
+}
+
alias DSO SectionGroup;
struct DSO
{
@@ -74,8 +88,22 @@ struct DSO
}
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
+ }
}
/****
@@ -99,63 +127,185 @@ void finiSections() nothrow @nogc
_isRuntimeInitialized = false;
}
-void[]* initTLSRanges() nothrow @nogc
-{
- return null;
-}
+alias ScanDG = void delegate(void* pbeg, void* pend) nothrow;
-void finiTLSRanges(void[]* rng) nothrow @nogc
+version (Shared)
{
-}
+ /***
+ * Called once per thread; returns array of thread local storage ranges
+ */
+ Array!(ThreadDSO)* initTLSRanges() @nogc nothrow
+ {
+ return &_loadedDSOs();
+ }
-void scanTLSRanges(void[]* rng, scope void delegate(void* pbeg, void* pend) nothrow dg) nothrow
-{
- version (GNU_EMUTLS)
- _d_emutls_scan(dg);
- else
- static assert(0, "Native TLS unimplemented");
-}
+ 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");
+ }
-version (Shared)
-{
// interface for core.thread to inherit loaded libraries
void* pinLoadedLibraries() nothrow @nogc
{
- return null;
+ 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;
}
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.
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.
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:
-/*
- * Static DSOs loaded by the runtime linker. This includes the
- * executable. These can't be unloaded.
- */
-@property ref Array!(DSO*) _loadedDSOs() @nogc nothrow
+version (Shared)
{
- __gshared Array!(DSO*) x;
- return x;
+ /*
+ * 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;
+ }
-/*
- * Set to true during rt_loadLibrary/rt_unloadLibrary calls.
- */
-enum _rtLoading = false;
+ enum _rtLoading = false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Compiler to runtime interface.
+///////////////////////////////////////////////////////////////////////////////
struct MachHeader
{
@@ -163,9 +313,18 @@ struct MachHeader
intptr_t slide; // virtural memory address slide amount
}
-///////////////////////////////////////////////////////////////////////////////
-// 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().
@@ -180,27 +339,57 @@ extern(C) void _d_dso_registry(CompilerDSOData* data)
// 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 info = void;
- const headerFound = findDSOHeaderForAddr(data._slot, &info);
+ MachHeader header = void;
+ const headerFound = findImageHeaderForAddr(data._slot, header);
safeAssert(headerFound, "Failed to find image header.");
- foreach (e; dataSegs)
+ 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
{
- 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]);
+ foreach (p; _loadedDSOs)
+ safeAssert(p !is pdso, "DSO already registered.");
+ _loadedDSOs.insertBack(pdso);
}
- 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
@@ -208,22 +397,274 @@ extern(C) void _d_dso_registry(CompilerDSOData* data)
DSO* pdso = cast(DSO*)*data._slot;
*data._slot = null;
- // static DSOs are unloaded in reverse order
- safeAssert(pdso == _loadedDSOs.back, "DSO being unregistered isn't current last one.");
- _loadedDSOs.popBack();
+ // 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();
+ }
- pdso._gcRanges.reset();
- .free(pdso);
+ 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
@@ -231,28 +672,38 @@ extern(C) void _d_dso_registry(CompilerDSOData* data)
* true if found, and *result is filled in
*/
-bool findDSOHeaderForAddr(in void* addr, MachHeader* result)
+bool findImageHeaderForAddr(in void* addr, out MachHeader result)
{
+ Dl_info info;
+ if (dladdr(addr, &info) == 0)
+ return false;
+
foreach (i; 0 .. _dyld_image_count())
{
- const header = _dyld_get_image_header(i);
- const slide = _dyld_get_image_vmaddr_slide(i);
- const section = getSection(header, slide, SEG_DATA, SECT_DATA);
-
- // less than base address of section means quick reject
- if (!section.length || addr < section.ptr)
- continue;
-
- if (addr < section.ptr + section.length)
+ if (info.dli_fbase == _dyld_get_image_header(i))
{
- result.header = header;
- result.slide = slide;
+ 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;
^ permalink raw reply [flat|nested] 12+ messages in thread
* [gcc(refs/users/ibuclaw/heads/darwin)] libphobos: Align interface of gcc.sections.osx with gcc.sections.elf_shared
@ 2021-01-11 11:39 Iain Buclaw
0 siblings, 0 replies; 12+ messages in thread
From: Iain Buclaw @ 2021-01-11 11:39 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:b3bbe457668387fc3942095485c2972d85c06f2b
commit b3bbe457668387fc3942095485c2972d85c06f2b
Author: Iain Buclaw <ibuclaw@gdcproject.org>
Date: Mon Dec 7 01:25:17 2020 +0100
libphobos: Align interface of gcc.sections.osx with gcc.sections.elf_shared
Diff:
---
libphobos/libdruntime/Makefile.am | 30 +-
libphobos/libdruntime/Makefile.in | 64 +--
libphobos/libdruntime/core/sys/darwin/execinfo.d | 11 +-
libphobos/libdruntime/gcc/sections/common.d | 48 --
libphobos/libdruntime/gcc/sections/osx.d | 569 ++++++++++++++++++++---
5 files changed, 565 insertions(+), 157 deletions(-)
diff --git a/libphobos/libdruntime/Makefile.am b/libphobos/libdruntime/Makefile.am
index bbe8eaea82e..5428c6dcfc5 100644
--- a/libphobos/libdruntime/Makefile.am
+++ b/libphobos/libdruntime/Makefile.am
@@ -183,21 +183,21 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \
gc/impl/conservative/gc.d gc/impl/manual/gc.d gc/os.d gc/pooltable.d \
gc/proxy.d gcc/attribute.d gcc/backtrace.d gcc/builtins.d gcc/deh.d \
gcc/emutls.d gcc/gthread.d gcc/sections/android.d \
- gcc/sections/common.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/typeinfo/ti_Acdouble.d \
- rt/typeinfo/ti_Acfloat.d rt/typeinfo/ti_Acreal.d \
- rt/typeinfo/ti_Adouble.d rt/typeinfo/ti_Afloat.d rt/typeinfo/ti_Ag.d \
- rt/typeinfo/ti_Aint.d rt/typeinfo/ti_Along.d rt/typeinfo/ti_Areal.d \
- rt/typeinfo/ti_Ashort.d rt/typeinfo/ti_C.d rt/typeinfo/ti_byte.d \
- rt/typeinfo/ti_cdouble.d rt/typeinfo/ti_cent.d rt/typeinfo/ti_cfloat.d \
- rt/typeinfo/ti_char.d rt/typeinfo/ti_creal.d rt/typeinfo/ti_dchar.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/typeinfo/ti_Acdouble.d rt/typeinfo/ti_Acfloat.d \
+ rt/typeinfo/ti_Acreal.d rt/typeinfo/ti_Adouble.d \
+ rt/typeinfo/ti_Afloat.d rt/typeinfo/ti_Ag.d rt/typeinfo/ti_Aint.d \
+ rt/typeinfo/ti_Along.d rt/typeinfo/ti_Areal.d rt/typeinfo/ti_Ashort.d \
+ rt/typeinfo/ti_C.d rt/typeinfo/ti_byte.d rt/typeinfo/ti_cdouble.d \
+ rt/typeinfo/ti_cent.d rt/typeinfo/ti_cfloat.d rt/typeinfo/ti_char.d \
+ rt/typeinfo/ti_creal.d rt/typeinfo/ti_dchar.d \
rt/typeinfo/ti_delegate.d rt/typeinfo/ti_double.d \
rt/typeinfo/ti_float.d rt/typeinfo/ti_idouble.d \
rt/typeinfo/ti_ifloat.d rt/typeinfo/ti_int.d rt/typeinfo/ti_ireal.d \
diff --git a/libphobos/libdruntime/Makefile.in b/libphobos/libdruntime/Makefile.in
index 3bf08f52b31..d99998d8934 100644
--- a/libphobos/libdruntime/Makefile.in
+++ b/libphobos/libdruntime/Makefile.in
@@ -207,10 +207,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/backtrace.lo \
gcc/builtins.lo gcc/deh.lo gcc/emutls.lo gcc/gthread.lo \
- gcc/sections/android.lo gcc/sections/common.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/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/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 \
@@ -268,9 +267,10 @@ am__objects_3 = core/sys/posix/aio.lo core/sys/posix/arpa/inet.lo \
core/sys/posix/time.lo core/sys/posix/ucontext.lo \
core/sys/posix/unistd.lo core/sys/posix/utime.lo
@DRUNTIME_OS_POSIX_TRUE@am__objects_4 = $(am__objects_3)
-am__objects_5 = core/sys/darwin/crt_externs.lo \
- core/sys/darwin/dlfcn.lo core/sys/darwin/execinfo.lo \
- core/sys/darwin/mach/dyld.lo core/sys/darwin/mach/getsect.lo \
+am__objects_5 = core/sys/darwin/config.lo \
+ core/sys/darwin/crt_externs.lo core/sys/darwin/dlfcn.lo \
+ core/sys/darwin/execinfo.lo core/sys/darwin/mach/dyld.lo \
+ core/sys/darwin/mach/getsect.lo \
core/sys/darwin/mach/kern_return.lo \
core/sys/darwin/mach/loader.lo core/sys/darwin/mach/port.lo \
core/sys/darwin/mach/semaphore.lo \
@@ -809,21 +809,21 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \
gc/impl/conservative/gc.d gc/impl/manual/gc.d gc/os.d gc/pooltable.d \
gc/proxy.d gcc/attribute.d gcc/backtrace.d gcc/builtins.d gcc/deh.d \
gcc/emutls.d gcc/gthread.d gcc/sections/android.d \
- gcc/sections/common.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/typeinfo/ti_Acdouble.d \
- rt/typeinfo/ti_Acfloat.d rt/typeinfo/ti_Acreal.d \
- rt/typeinfo/ti_Adouble.d rt/typeinfo/ti_Afloat.d rt/typeinfo/ti_Ag.d \
- rt/typeinfo/ti_Aint.d rt/typeinfo/ti_Along.d rt/typeinfo/ti_Areal.d \
- rt/typeinfo/ti_Ashort.d rt/typeinfo/ti_C.d rt/typeinfo/ti_byte.d \
- rt/typeinfo/ti_cdouble.d rt/typeinfo/ti_cent.d rt/typeinfo/ti_cfloat.d \
- rt/typeinfo/ti_char.d rt/typeinfo/ti_creal.d rt/typeinfo/ti_dchar.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/typeinfo/ti_Acdouble.d rt/typeinfo/ti_Acfloat.d \
+ rt/typeinfo/ti_Acreal.d rt/typeinfo/ti_Adouble.d \
+ rt/typeinfo/ti_Afloat.d rt/typeinfo/ti_Ag.d rt/typeinfo/ti_Aint.d \
+ rt/typeinfo/ti_Along.d rt/typeinfo/ti_Areal.d rt/typeinfo/ti_Ashort.d \
+ rt/typeinfo/ti_C.d rt/typeinfo/ti_byte.d rt/typeinfo/ti_cdouble.d \
+ rt/typeinfo/ti_cent.d rt/typeinfo/ti_cfloat.d rt/typeinfo/ti_char.d \
+ rt/typeinfo/ti_creal.d rt/typeinfo/ti_dchar.d \
rt/typeinfo/ti_delegate.d rt/typeinfo/ti_double.d \
rt/typeinfo/ti_float.d rt/typeinfo/ti_idouble.d \
rt/typeinfo/ti_ifloat.d rt/typeinfo/ti_int.d rt/typeinfo/ti_ireal.d \
@@ -841,15 +841,15 @@ DRUNTIME_DSOURCES_STDCXX = core/stdcpp/exception.d \
DRUNTIME_DSOURCES_BIONIC = core/sys/bionic/fcntl.d \
core/sys/bionic/string.d core/sys/bionic/unistd.d
-DRUNTIME_DSOURCES_DARWIN = core/sys/darwin/crt_externs.d \
- core/sys/darwin/dlfcn.d core/sys/darwin/execinfo.d \
- core/sys/darwin/mach/dyld.d core/sys/darwin/mach/getsect.d \
- core/sys/darwin/mach/kern_return.d core/sys/darwin/mach/loader.d \
- core/sys/darwin/mach/port.d core/sys/darwin/mach/semaphore.d \
- core/sys/darwin/mach/thread_act.d core/sys/darwin/netinet/in_.d \
- core/sys/darwin/pthread.d core/sys/darwin/string.d \
- core/sys/darwin/sys/cdefs.d core/sys/darwin/sys/event.d \
- core/sys/darwin/sys/mman.d
+DRUNTIME_DSOURCES_DARWIN = core/sys/darwin/config.d \
+ core/sys/darwin/crt_externs.d core/sys/darwin/dlfcn.d \
+ core/sys/darwin/execinfo.d core/sys/darwin/mach/dyld.d \
+ core/sys/darwin/mach/getsect.d core/sys/darwin/mach/kern_return.d \
+ core/sys/darwin/mach/loader.d core/sys/darwin/mach/port.d \
+ core/sys/darwin/mach/semaphore.d core/sys/darwin/mach/thread_act.d \
+ core/sys/darwin/netinet/in_.d core/sys/darwin/pthread.d \
+ core/sys/darwin/string.d core/sys/darwin/sys/cdefs.d \
+ core/sys/darwin/sys/event.d core/sys/darwin/sys/mman.d
DRUNTIME_DSOURCES_DRAGONFLYBSD = core/sys/dragonflybsd/dlfcn.d \
core/sys/dragonflybsd/execinfo.d core/sys/dragonflybsd/netinet/in_.d \
@@ -1196,7 +1196,6 @@ gcc/sections/$(am__dirstamp):
@$(MKDIR_P) gcc/sections
@: > gcc/sections/$(am__dirstamp)
gcc/sections/android.lo: gcc/sections/$(am__dirstamp)
-gcc/sections/common.lo: gcc/sections/$(am__dirstamp)
gcc/sections/elf_shared.lo: gcc/sections/$(am__dirstamp)
gcc/sections/osx.lo: gcc/sections/$(am__dirstamp)
gcc/sections/package.lo: gcc/sections/$(am__dirstamp)
@@ -1359,6 +1358,7 @@ core/sys/posix/utime.lo: core/sys/posix/$(am__dirstamp)
core/sys/darwin/$(am__dirstamp):
@$(MKDIR_P) core/sys/darwin
@: > core/sys/darwin/$(am__dirstamp)
+core/sys/darwin/config.lo: core/sys/darwin/$(am__dirstamp)
core/sys/darwin/crt_externs.lo: core/sys/darwin/$(am__dirstamp)
core/sys/darwin/dlfcn.lo: core/sys/darwin/$(am__dirstamp)
core/sys/darwin/execinfo.lo: core/sys/darwin/$(am__dirstamp)
diff --git a/libphobos/libdruntime/core/sys/darwin/execinfo.d b/libphobos/libdruntime/core/sys/darwin/execinfo.d
index c929cc2f88d..d9607f392eb 100644
--- a/libphobos/libdruntime/core/sys/darwin/execinfo.d
+++ b/libphobos/libdruntime/core/sys/darwin/execinfo.d
@@ -21,6 +21,11 @@ extern (C):
nothrow:
@nogc:
-int backtrace(void** buffer, int size);
-char** backtrace_symbols(const(void*)* buffer, int size);
-void backtrace_symbols_fd(const(void*)* buffer, int size, int fd);
+import core.sys.darwin.config;
+
+static if (__traits(getTargetInfo, "osxVersionMin") >= __MAC_10_5)
+{
+ int backtrace(void** buffer, int size);
+ char** backtrace_symbols(const(void*)* buffer, int size);
+ void backtrace_symbols_fd(const(void*)* buffer, int size, int fd);
+}
diff --git a/libphobos/libdruntime/gcc/sections/common.d b/libphobos/libdruntime/gcc/sections/common.d
deleted file mode 100644
index b2d2322347d..00000000000
--- a/libphobos/libdruntime/gcc/sections/common.d
+++ /dev/null
@@ -1,48 +0,0 @@
-// Common support routines for retrieving platform-specific sections.
-// Copyright (C) 2019 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 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.).
- */
-void safeAssert(bool condition, scope string msg, size_t line = __LINE__) @nogc nothrow @safe
-{
- import core.internal.abort;
- condition || abort(msg, __FILE__, line);
-}
-
-/****
- * 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]; }
diff --git a/libphobos/libdruntime/gcc/sections/osx.d b/libphobos/libdruntime/gcc/sections/osx.d
index 2f807bb98e0..fef19f761c5 100644
--- a/libphobos/libdruntime/gcc/sections/osx.d
+++ b/libphobos/libdruntime/gcc/sections/osx.d
@@ -24,17 +24,31 @@ module gcc.sections.osx;
version (OSX):
-import gcc.sections.common;
-
+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;
version (GNU_EMUTLS)
import gcc.emutls;
+/****
+ * 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.).
+ */
+void safeAssert(bool condition, scope string msg, size_t line = __LINE__) @nogc nothrow @safe
+{
+ import core.internal.abort;
+ condition || abort(msg, __FILE__, line);
+}
+
alias DSO SectionGroup;
struct DSO
{
@@ -74,8 +88,22 @@ struct DSO
}
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
+ }
}
/****
@@ -99,63 +127,185 @@ void finiSections() nothrow @nogc
_isRuntimeInitialized = false;
}
-void[]* initTLSRanges() nothrow @nogc
-{
- return null;
-}
+alias ScanDG = void delegate(void* pbeg, void* pend) nothrow;
-void finiTLSRanges(void[]* rng) nothrow @nogc
+version (Shared)
{
-}
+ /***
+ * Called once per thread; returns array of thread local storage ranges
+ */
+ Array!(ThreadDSO)* initTLSRanges() @nogc nothrow
+ {
+ return &_loadedDSOs();
+ }
-void scanTLSRanges(void[]* rng, scope void delegate(void* pbeg, void* pend) nothrow dg) nothrow
-{
- version (GNU_EMUTLS)
- _d_emutls_scan(dg);
- else
- static assert(0, "Native TLS unimplemented");
-}
+ 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");
+ }
-version (Shared)
-{
// interface for core.thread to inherit loaded libraries
void* pinLoadedLibraries() nothrow @nogc
{
- return null;
+ 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;
}
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.
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.
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:
-/*
- * Static DSOs loaded by the runtime linker. This includes the
- * executable. These can't be unloaded.
- */
-@property ref Array!(DSO*) _loadedDSOs() @nogc nothrow
+version (Shared)
{
- __gshared Array!(DSO*) x;
- return x;
+ /*
+ * 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;
+ }
-/*
- * Set to true during rt_loadLibrary/rt_unloadLibrary calls.
- */
-enum _rtLoading = false;
+ enum _rtLoading = false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Compiler to runtime interface.
+///////////////////////////////////////////////////////////////////////////////
struct MachHeader
{
@@ -163,9 +313,18 @@ struct MachHeader
intptr_t slide; // virtural memory address slide amount
}
-///////////////////////////////////////////////////////////////////////////////
-// 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().
@@ -180,27 +339,57 @@ extern(C) void _d_dso_registry(CompilerDSOData* data)
// 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 info = void;
- const headerFound = findDSOHeaderForAddr(data._slot, &info);
+ MachHeader header = void;
+ const headerFound = findImageHeaderForAddr(data._slot, header);
safeAssert(headerFound, "Failed to find image header.");
- foreach (e; dataSegs)
+ 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
{
- 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]);
+ foreach (p; _loadedDSOs)
+ safeAssert(p !is pdso, "DSO already registered.");
+ _loadedDSOs.insertBack(pdso);
}
- 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
@@ -208,22 +397,274 @@ extern(C) void _d_dso_registry(CompilerDSOData* data)
DSO* pdso = cast(DSO*)*data._slot;
*data._slot = null;
- // static DSOs are unloaded in reverse order
- safeAssert(pdso == _loadedDSOs.back, "DSO being unregistered isn't current last one.");
- _loadedDSOs.popBack();
+ // 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();
+ }
- pdso._gcRanges.reset();
- .free(pdso);
+ 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
@@ -231,28 +672,38 @@ extern(C) void _d_dso_registry(CompilerDSOData* data)
* true if found, and *result is filled in
*/
-bool findDSOHeaderForAddr(in void* addr, MachHeader* result)
+bool findImageHeaderForAddr(in void* addr, out MachHeader result)
{
+ Dl_info info;
+ if (dladdr(addr, &info) == 0)
+ return false;
+
foreach (i; 0 .. _dyld_image_count())
{
- const header = _dyld_get_image_header(i);
- const slide = _dyld_get_image_vmaddr_slide(i);
- const section = getSection(header, slide, SEG_DATA, SECT_DATA);
-
- // less than base address of section means quick reject
- if (!section.length || addr < section.ptr)
- continue;
-
- if (addr < section.ptr + section.length)
+ if (info.dli_fbase == _dyld_get_image_header(i))
{
- result.header = header;
- result.slide = slide;
+ 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;
^ permalink raw reply [flat|nested] 12+ messages in thread
* [gcc(refs/users/ibuclaw/heads/darwin)] libphobos: Align interface of gcc.sections.osx with gcc.sections.elf_shared
@ 2020-12-22 13:41 Iain Buclaw
0 siblings, 0 replies; 12+ messages in thread
From: Iain Buclaw @ 2020-12-22 13:41 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:c251426f0cf0c0b510eda1b5c67452a385a6f660
commit c251426f0cf0c0b510eda1b5c67452a385a6f660
Author: Iain Buclaw <ibuclaw@gdcproject.org>
Date: Mon Dec 7 01:25:17 2020 +0100
libphobos: Align interface of gcc.sections.osx with gcc.sections.elf_shared
Diff:
---
libphobos/libdruntime/Makefile.am | 30 +-
libphobos/libdruntime/Makefile.in | 64 +--
libphobos/libdruntime/core/sys/darwin/execinfo.d | 11 +-
libphobos/libdruntime/gcc/sections/common.d | 48 --
libphobos/libdruntime/gcc/sections/osx.d | 569 ++++++++++++++++++++---
5 files changed, 565 insertions(+), 157 deletions(-)
diff --git a/libphobos/libdruntime/Makefile.am b/libphobos/libdruntime/Makefile.am
index 124d5b049d0..722f1edfe09 100644
--- a/libphobos/libdruntime/Makefile.am
+++ b/libphobos/libdruntime/Makefile.am
@@ -183,21 +183,21 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \
gc/impl/conservative/gc.d gc/impl/manual/gc.d gc/os.d gc/pooltable.d \
gc/proxy.d gcc/attribute.d gcc/backtrace.d gcc/builtins.d gcc/deh.d \
gcc/emutls.d gcc/gthread.d gcc/sections/android.d \
- gcc/sections/common.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/typeinfo/ti_Acdouble.d \
- rt/typeinfo/ti_Acfloat.d rt/typeinfo/ti_Acreal.d \
- rt/typeinfo/ti_Adouble.d rt/typeinfo/ti_Afloat.d rt/typeinfo/ti_Ag.d \
- rt/typeinfo/ti_Aint.d rt/typeinfo/ti_Along.d rt/typeinfo/ti_Areal.d \
- rt/typeinfo/ti_Ashort.d rt/typeinfo/ti_C.d rt/typeinfo/ti_byte.d \
- rt/typeinfo/ti_cdouble.d rt/typeinfo/ti_cent.d rt/typeinfo/ti_cfloat.d \
- rt/typeinfo/ti_char.d rt/typeinfo/ti_creal.d rt/typeinfo/ti_dchar.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/typeinfo/ti_Acdouble.d rt/typeinfo/ti_Acfloat.d \
+ rt/typeinfo/ti_Acreal.d rt/typeinfo/ti_Adouble.d \
+ rt/typeinfo/ti_Afloat.d rt/typeinfo/ti_Ag.d rt/typeinfo/ti_Aint.d \
+ rt/typeinfo/ti_Along.d rt/typeinfo/ti_Areal.d rt/typeinfo/ti_Ashort.d \
+ rt/typeinfo/ti_C.d rt/typeinfo/ti_byte.d rt/typeinfo/ti_cdouble.d \
+ rt/typeinfo/ti_cent.d rt/typeinfo/ti_cfloat.d rt/typeinfo/ti_char.d \
+ rt/typeinfo/ti_creal.d rt/typeinfo/ti_dchar.d \
rt/typeinfo/ti_delegate.d rt/typeinfo/ti_double.d \
rt/typeinfo/ti_float.d rt/typeinfo/ti_idouble.d \
rt/typeinfo/ti_ifloat.d rt/typeinfo/ti_int.d rt/typeinfo/ti_ireal.d \
diff --git a/libphobos/libdruntime/Makefile.in b/libphobos/libdruntime/Makefile.in
index 3bf08f52b31..d99998d8934 100644
--- a/libphobos/libdruntime/Makefile.in
+++ b/libphobos/libdruntime/Makefile.in
@@ -207,10 +207,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/backtrace.lo \
gcc/builtins.lo gcc/deh.lo gcc/emutls.lo gcc/gthread.lo \
- gcc/sections/android.lo gcc/sections/common.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/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/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 \
@@ -268,9 +267,10 @@ am__objects_3 = core/sys/posix/aio.lo core/sys/posix/arpa/inet.lo \
core/sys/posix/time.lo core/sys/posix/ucontext.lo \
core/sys/posix/unistd.lo core/sys/posix/utime.lo
@DRUNTIME_OS_POSIX_TRUE@am__objects_4 = $(am__objects_3)
-am__objects_5 = core/sys/darwin/crt_externs.lo \
- core/sys/darwin/dlfcn.lo core/sys/darwin/execinfo.lo \
- core/sys/darwin/mach/dyld.lo core/sys/darwin/mach/getsect.lo \
+am__objects_5 = core/sys/darwin/config.lo \
+ core/sys/darwin/crt_externs.lo core/sys/darwin/dlfcn.lo \
+ core/sys/darwin/execinfo.lo core/sys/darwin/mach/dyld.lo \
+ core/sys/darwin/mach/getsect.lo \
core/sys/darwin/mach/kern_return.lo \
core/sys/darwin/mach/loader.lo core/sys/darwin/mach/port.lo \
core/sys/darwin/mach/semaphore.lo \
@@ -809,21 +809,21 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \
gc/impl/conservative/gc.d gc/impl/manual/gc.d gc/os.d gc/pooltable.d \
gc/proxy.d gcc/attribute.d gcc/backtrace.d gcc/builtins.d gcc/deh.d \
gcc/emutls.d gcc/gthread.d gcc/sections/android.d \
- gcc/sections/common.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/typeinfo/ti_Acdouble.d \
- rt/typeinfo/ti_Acfloat.d rt/typeinfo/ti_Acreal.d \
- rt/typeinfo/ti_Adouble.d rt/typeinfo/ti_Afloat.d rt/typeinfo/ti_Ag.d \
- rt/typeinfo/ti_Aint.d rt/typeinfo/ti_Along.d rt/typeinfo/ti_Areal.d \
- rt/typeinfo/ti_Ashort.d rt/typeinfo/ti_C.d rt/typeinfo/ti_byte.d \
- rt/typeinfo/ti_cdouble.d rt/typeinfo/ti_cent.d rt/typeinfo/ti_cfloat.d \
- rt/typeinfo/ti_char.d rt/typeinfo/ti_creal.d rt/typeinfo/ti_dchar.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/typeinfo/ti_Acdouble.d rt/typeinfo/ti_Acfloat.d \
+ rt/typeinfo/ti_Acreal.d rt/typeinfo/ti_Adouble.d \
+ rt/typeinfo/ti_Afloat.d rt/typeinfo/ti_Ag.d rt/typeinfo/ti_Aint.d \
+ rt/typeinfo/ti_Along.d rt/typeinfo/ti_Areal.d rt/typeinfo/ti_Ashort.d \
+ rt/typeinfo/ti_C.d rt/typeinfo/ti_byte.d rt/typeinfo/ti_cdouble.d \
+ rt/typeinfo/ti_cent.d rt/typeinfo/ti_cfloat.d rt/typeinfo/ti_char.d \
+ rt/typeinfo/ti_creal.d rt/typeinfo/ti_dchar.d \
rt/typeinfo/ti_delegate.d rt/typeinfo/ti_double.d \
rt/typeinfo/ti_float.d rt/typeinfo/ti_idouble.d \
rt/typeinfo/ti_ifloat.d rt/typeinfo/ti_int.d rt/typeinfo/ti_ireal.d \
@@ -841,15 +841,15 @@ DRUNTIME_DSOURCES_STDCXX = core/stdcpp/exception.d \
DRUNTIME_DSOURCES_BIONIC = core/sys/bionic/fcntl.d \
core/sys/bionic/string.d core/sys/bionic/unistd.d
-DRUNTIME_DSOURCES_DARWIN = core/sys/darwin/crt_externs.d \
- core/sys/darwin/dlfcn.d core/sys/darwin/execinfo.d \
- core/sys/darwin/mach/dyld.d core/sys/darwin/mach/getsect.d \
- core/sys/darwin/mach/kern_return.d core/sys/darwin/mach/loader.d \
- core/sys/darwin/mach/port.d core/sys/darwin/mach/semaphore.d \
- core/sys/darwin/mach/thread_act.d core/sys/darwin/netinet/in_.d \
- core/sys/darwin/pthread.d core/sys/darwin/string.d \
- core/sys/darwin/sys/cdefs.d core/sys/darwin/sys/event.d \
- core/sys/darwin/sys/mman.d
+DRUNTIME_DSOURCES_DARWIN = core/sys/darwin/config.d \
+ core/sys/darwin/crt_externs.d core/sys/darwin/dlfcn.d \
+ core/sys/darwin/execinfo.d core/sys/darwin/mach/dyld.d \
+ core/sys/darwin/mach/getsect.d core/sys/darwin/mach/kern_return.d \
+ core/sys/darwin/mach/loader.d core/sys/darwin/mach/port.d \
+ core/sys/darwin/mach/semaphore.d core/sys/darwin/mach/thread_act.d \
+ core/sys/darwin/netinet/in_.d core/sys/darwin/pthread.d \
+ core/sys/darwin/string.d core/sys/darwin/sys/cdefs.d \
+ core/sys/darwin/sys/event.d core/sys/darwin/sys/mman.d
DRUNTIME_DSOURCES_DRAGONFLYBSD = core/sys/dragonflybsd/dlfcn.d \
core/sys/dragonflybsd/execinfo.d core/sys/dragonflybsd/netinet/in_.d \
@@ -1196,7 +1196,6 @@ gcc/sections/$(am__dirstamp):
@$(MKDIR_P) gcc/sections
@: > gcc/sections/$(am__dirstamp)
gcc/sections/android.lo: gcc/sections/$(am__dirstamp)
-gcc/sections/common.lo: gcc/sections/$(am__dirstamp)
gcc/sections/elf_shared.lo: gcc/sections/$(am__dirstamp)
gcc/sections/osx.lo: gcc/sections/$(am__dirstamp)
gcc/sections/package.lo: gcc/sections/$(am__dirstamp)
@@ -1359,6 +1358,7 @@ core/sys/posix/utime.lo: core/sys/posix/$(am__dirstamp)
core/sys/darwin/$(am__dirstamp):
@$(MKDIR_P) core/sys/darwin
@: > core/sys/darwin/$(am__dirstamp)
+core/sys/darwin/config.lo: core/sys/darwin/$(am__dirstamp)
core/sys/darwin/crt_externs.lo: core/sys/darwin/$(am__dirstamp)
core/sys/darwin/dlfcn.lo: core/sys/darwin/$(am__dirstamp)
core/sys/darwin/execinfo.lo: core/sys/darwin/$(am__dirstamp)
diff --git a/libphobos/libdruntime/core/sys/darwin/execinfo.d b/libphobos/libdruntime/core/sys/darwin/execinfo.d
index c929cc2f88d..d9607f392eb 100644
--- a/libphobos/libdruntime/core/sys/darwin/execinfo.d
+++ b/libphobos/libdruntime/core/sys/darwin/execinfo.d
@@ -21,6 +21,11 @@ extern (C):
nothrow:
@nogc:
-int backtrace(void** buffer, int size);
-char** backtrace_symbols(const(void*)* buffer, int size);
-void backtrace_symbols_fd(const(void*)* buffer, int size, int fd);
+import core.sys.darwin.config;
+
+static if (__traits(getTargetInfo, "osxVersionMin") >= __MAC_10_5)
+{
+ int backtrace(void** buffer, int size);
+ char** backtrace_symbols(const(void*)* buffer, int size);
+ void backtrace_symbols_fd(const(void*)* buffer, int size, int fd);
+}
diff --git a/libphobos/libdruntime/gcc/sections/common.d b/libphobos/libdruntime/gcc/sections/common.d
deleted file mode 100644
index b2d2322347d..00000000000
--- a/libphobos/libdruntime/gcc/sections/common.d
+++ /dev/null
@@ -1,48 +0,0 @@
-// Common support routines for retrieving platform-specific sections.
-// Copyright (C) 2019 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 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.).
- */
-void safeAssert(bool condition, scope string msg, size_t line = __LINE__) @nogc nothrow @safe
-{
- import core.internal.abort;
- condition || abort(msg, __FILE__, line);
-}
-
-/****
- * 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]; }
diff --git a/libphobos/libdruntime/gcc/sections/osx.d b/libphobos/libdruntime/gcc/sections/osx.d
index 6ace2da4a8b..9ec5b79974e 100644
--- a/libphobos/libdruntime/gcc/sections/osx.d
+++ b/libphobos/libdruntime/gcc/sections/osx.d
@@ -24,17 +24,31 @@ module gcc.sections.osx;
version (OSX):
-import gcc.sections.common;
-
+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;
version (GNU_EMUTLS)
import gcc.emutls;
+/****
+ * 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.).
+ */
+void safeAssert(bool condition, scope string msg, size_t line = __LINE__) @nogc nothrow @safe
+{
+ import core.internal.abort;
+ condition || abort(msg, __FILE__, line);
+}
+
alias DSO SectionGroup;
struct DSO
{
@@ -74,8 +88,22 @@ struct DSO
}
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
+ }
}
/****
@@ -99,63 +127,185 @@ void finiSections() nothrow @nogc
_isRuntimeInitialized = false;
}
-void[]* initTLSRanges() nothrow @nogc
-{
- return null;
-}
+alias ScanDG = void delegate(void* pbeg, void* pend) nothrow;
-void finiTLSRanges(void[]* rng) nothrow @nogc
+version (Shared)
{
-}
+ /***
+ * Called once per thread; returns array of thread local storage ranges
+ */
+ Array!(ThreadDSO)* initTLSRanges() @nogc nothrow
+ {
+ return &_loadedDSOs();
+ }
-void scanTLSRanges(void[]* rng, scope void delegate(void* pbeg, void* pend) nothrow dg) nothrow
-{
- version (GNU_EMUTLS)
- _d_emutls_scan(dg);
- else
- static assert(0, "Native TLS unimplemented");
-}
+ 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");
+ }
-version (Shared)
-{
// interface for core.thread to inherit loaded libraries
void* pinLoadedLibraries() nothrow @nogc
{
- return null;
+ 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;
}
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.
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.
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:
-/*
- * Static DSOs loaded by the runtime linker. This includes the
- * executable. These can't be unloaded.
- */
-@property ref Array!(DSO*) _loadedDSOs() @nogc nothrow
+version (Shared)
{
- __gshared Array!(DSO*) x;
- return x;
+ /*
+ * 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;
+ }
-/*
- * Set to true during rt_loadLibrary/rt_unloadLibrary calls.
- */
-enum _rtLoading = false;
+ enum _rtLoading = false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Compiler to runtime interface.
+///////////////////////////////////////////////////////////////////////////////
struct MachHeader
{
@@ -163,9 +313,18 @@ struct MachHeader
intptr_t slide; // virtural memory address slide amount
}
-///////////////////////////////////////////////////////////////////////////////
-// 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().
@@ -180,27 +339,57 @@ extern(C) void _d_dso_registry(CompilerDSOData* data)
// 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 info = void;
- const headerFound = findDSOHeaderForAddr(data._slot, &info);
+ MachHeader header = void;
+ const headerFound = findImageHeaderForAddr(data._slot, header);
safeAssert(headerFound, "Failed to find image header.");
- foreach (e; dataSegs)
+ 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
{
- 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]);
+ foreach (p; _loadedDSOs)
+ safeAssert(p !is pdso, "DSO already registered.");
+ _loadedDSOs.insertBack(pdso);
}
- 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
@@ -208,22 +397,274 @@ extern(C) void _d_dso_registry(CompilerDSOData* data)
DSO* pdso = cast(DSO*)*data._slot;
*data._slot = null;
- // static DSOs are unloaded in reverse order
- safeAssert(pdso == _loadedDSOs.back, "DSO being unregistered isn't current last one.");
- _loadedDSOs.popBack();
+ // 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();
+ }
- pdso._gcRanges.reset();
- .free(pdso);
+ 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
@@ -231,28 +672,38 @@ extern(C) void _d_dso_registry(CompilerDSOData* data)
* true if found, and *result is filled in
*/
-bool findDSOHeaderForAddr(in void* addr, MachHeader* result)
+bool findImageHeaderForAddr(in void* addr, out MachHeader result)
{
+ Dl_info info;
+ if (dladdr(addr, &info) == 0)
+ return false;
+
foreach (i; 0 .. _dyld_image_count())
{
- const header = _dyld_get_image_header(i);
- const slide = _dyld_get_image_vmaddr_slide(i);
- const section = getSection(header, slide, SEG_DATA, SECT_DATA);
-
- // less than base address of section means quick reject
- if (!section.length || addr < section.ptr)
- continue;
-
- if (addr < section.ptr + section.length)
+ if (info.dli_fbase == _dyld_get_image_header(i))
{
- result.header = header;
- result.slide = slide;
+ 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;
^ permalink raw reply [flat|nested] 12+ messages in thread
* [gcc(refs/users/ibuclaw/heads/darwin)] libphobos: Align interface of gcc.sections.osx with gcc.sections.elf_shared
@ 2020-12-09 9:51 Iain Buclaw
0 siblings, 0 replies; 12+ messages in thread
From: Iain Buclaw @ 2020-12-09 9:51 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:9cdebb410c71dbcf4c1e3400328cf73758000447
commit 9cdebb410c71dbcf4c1e3400328cf73758000447
Author: Iain Buclaw <ibuclaw@gdcproject.org>
Date: Mon Dec 7 01:25:17 2020 +0100
libphobos: Align interface of gcc.sections.osx with gcc.sections.elf_shared
Diff:
---
libphobos/libdruntime/Makefile.am | 30 +-
libphobos/libdruntime/Makefile.in | 64 +--
libphobos/libdruntime/core/sys/darwin/execinfo.d | 11 +-
libphobos/libdruntime/gcc/sections/common.d | 48 --
libphobos/libdruntime/gcc/sections/osx.d | 569 ++++++++++++++++++++---
5 files changed, 565 insertions(+), 157 deletions(-)
diff --git a/libphobos/libdruntime/Makefile.am b/libphobos/libdruntime/Makefile.am
index 124d5b049d0..722f1edfe09 100644
--- a/libphobos/libdruntime/Makefile.am
+++ b/libphobos/libdruntime/Makefile.am
@@ -183,21 +183,21 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \
gc/impl/conservative/gc.d gc/impl/manual/gc.d gc/os.d gc/pooltable.d \
gc/proxy.d gcc/attribute.d gcc/backtrace.d gcc/builtins.d gcc/deh.d \
gcc/emutls.d gcc/gthread.d gcc/sections/android.d \
- gcc/sections/common.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/typeinfo/ti_Acdouble.d \
- rt/typeinfo/ti_Acfloat.d rt/typeinfo/ti_Acreal.d \
- rt/typeinfo/ti_Adouble.d rt/typeinfo/ti_Afloat.d rt/typeinfo/ti_Ag.d \
- rt/typeinfo/ti_Aint.d rt/typeinfo/ti_Along.d rt/typeinfo/ti_Areal.d \
- rt/typeinfo/ti_Ashort.d rt/typeinfo/ti_C.d rt/typeinfo/ti_byte.d \
- rt/typeinfo/ti_cdouble.d rt/typeinfo/ti_cent.d rt/typeinfo/ti_cfloat.d \
- rt/typeinfo/ti_char.d rt/typeinfo/ti_creal.d rt/typeinfo/ti_dchar.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/typeinfo/ti_Acdouble.d rt/typeinfo/ti_Acfloat.d \
+ rt/typeinfo/ti_Acreal.d rt/typeinfo/ti_Adouble.d \
+ rt/typeinfo/ti_Afloat.d rt/typeinfo/ti_Ag.d rt/typeinfo/ti_Aint.d \
+ rt/typeinfo/ti_Along.d rt/typeinfo/ti_Areal.d rt/typeinfo/ti_Ashort.d \
+ rt/typeinfo/ti_C.d rt/typeinfo/ti_byte.d rt/typeinfo/ti_cdouble.d \
+ rt/typeinfo/ti_cent.d rt/typeinfo/ti_cfloat.d rt/typeinfo/ti_char.d \
+ rt/typeinfo/ti_creal.d rt/typeinfo/ti_dchar.d \
rt/typeinfo/ti_delegate.d rt/typeinfo/ti_double.d \
rt/typeinfo/ti_float.d rt/typeinfo/ti_idouble.d \
rt/typeinfo/ti_ifloat.d rt/typeinfo/ti_int.d rt/typeinfo/ti_ireal.d \
diff --git a/libphobos/libdruntime/Makefile.in b/libphobos/libdruntime/Makefile.in
index 3bf08f52b31..d99998d8934 100644
--- a/libphobos/libdruntime/Makefile.in
+++ b/libphobos/libdruntime/Makefile.in
@@ -207,10 +207,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/backtrace.lo \
gcc/builtins.lo gcc/deh.lo gcc/emutls.lo gcc/gthread.lo \
- gcc/sections/android.lo gcc/sections/common.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/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/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 \
@@ -268,9 +267,10 @@ am__objects_3 = core/sys/posix/aio.lo core/sys/posix/arpa/inet.lo \
core/sys/posix/time.lo core/sys/posix/ucontext.lo \
core/sys/posix/unistd.lo core/sys/posix/utime.lo
@DRUNTIME_OS_POSIX_TRUE@am__objects_4 = $(am__objects_3)
-am__objects_5 = core/sys/darwin/crt_externs.lo \
- core/sys/darwin/dlfcn.lo core/sys/darwin/execinfo.lo \
- core/sys/darwin/mach/dyld.lo core/sys/darwin/mach/getsect.lo \
+am__objects_5 = core/sys/darwin/config.lo \
+ core/sys/darwin/crt_externs.lo core/sys/darwin/dlfcn.lo \
+ core/sys/darwin/execinfo.lo core/sys/darwin/mach/dyld.lo \
+ core/sys/darwin/mach/getsect.lo \
core/sys/darwin/mach/kern_return.lo \
core/sys/darwin/mach/loader.lo core/sys/darwin/mach/port.lo \
core/sys/darwin/mach/semaphore.lo \
@@ -809,21 +809,21 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \
gc/impl/conservative/gc.d gc/impl/manual/gc.d gc/os.d gc/pooltable.d \
gc/proxy.d gcc/attribute.d gcc/backtrace.d gcc/builtins.d gcc/deh.d \
gcc/emutls.d gcc/gthread.d gcc/sections/android.d \
- gcc/sections/common.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/typeinfo/ti_Acdouble.d \
- rt/typeinfo/ti_Acfloat.d rt/typeinfo/ti_Acreal.d \
- rt/typeinfo/ti_Adouble.d rt/typeinfo/ti_Afloat.d rt/typeinfo/ti_Ag.d \
- rt/typeinfo/ti_Aint.d rt/typeinfo/ti_Along.d rt/typeinfo/ti_Areal.d \
- rt/typeinfo/ti_Ashort.d rt/typeinfo/ti_C.d rt/typeinfo/ti_byte.d \
- rt/typeinfo/ti_cdouble.d rt/typeinfo/ti_cent.d rt/typeinfo/ti_cfloat.d \
- rt/typeinfo/ti_char.d rt/typeinfo/ti_creal.d rt/typeinfo/ti_dchar.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/typeinfo/ti_Acdouble.d rt/typeinfo/ti_Acfloat.d \
+ rt/typeinfo/ti_Acreal.d rt/typeinfo/ti_Adouble.d \
+ rt/typeinfo/ti_Afloat.d rt/typeinfo/ti_Ag.d rt/typeinfo/ti_Aint.d \
+ rt/typeinfo/ti_Along.d rt/typeinfo/ti_Areal.d rt/typeinfo/ti_Ashort.d \
+ rt/typeinfo/ti_C.d rt/typeinfo/ti_byte.d rt/typeinfo/ti_cdouble.d \
+ rt/typeinfo/ti_cent.d rt/typeinfo/ti_cfloat.d rt/typeinfo/ti_char.d \
+ rt/typeinfo/ti_creal.d rt/typeinfo/ti_dchar.d \
rt/typeinfo/ti_delegate.d rt/typeinfo/ti_double.d \
rt/typeinfo/ti_float.d rt/typeinfo/ti_idouble.d \
rt/typeinfo/ti_ifloat.d rt/typeinfo/ti_int.d rt/typeinfo/ti_ireal.d \
@@ -841,15 +841,15 @@ DRUNTIME_DSOURCES_STDCXX = core/stdcpp/exception.d \
DRUNTIME_DSOURCES_BIONIC = core/sys/bionic/fcntl.d \
core/sys/bionic/string.d core/sys/bionic/unistd.d
-DRUNTIME_DSOURCES_DARWIN = core/sys/darwin/crt_externs.d \
- core/sys/darwin/dlfcn.d core/sys/darwin/execinfo.d \
- core/sys/darwin/mach/dyld.d core/sys/darwin/mach/getsect.d \
- core/sys/darwin/mach/kern_return.d core/sys/darwin/mach/loader.d \
- core/sys/darwin/mach/port.d core/sys/darwin/mach/semaphore.d \
- core/sys/darwin/mach/thread_act.d core/sys/darwin/netinet/in_.d \
- core/sys/darwin/pthread.d core/sys/darwin/string.d \
- core/sys/darwin/sys/cdefs.d core/sys/darwin/sys/event.d \
- core/sys/darwin/sys/mman.d
+DRUNTIME_DSOURCES_DARWIN = core/sys/darwin/config.d \
+ core/sys/darwin/crt_externs.d core/sys/darwin/dlfcn.d \
+ core/sys/darwin/execinfo.d core/sys/darwin/mach/dyld.d \
+ core/sys/darwin/mach/getsect.d core/sys/darwin/mach/kern_return.d \
+ core/sys/darwin/mach/loader.d core/sys/darwin/mach/port.d \
+ core/sys/darwin/mach/semaphore.d core/sys/darwin/mach/thread_act.d \
+ core/sys/darwin/netinet/in_.d core/sys/darwin/pthread.d \
+ core/sys/darwin/string.d core/sys/darwin/sys/cdefs.d \
+ core/sys/darwin/sys/event.d core/sys/darwin/sys/mman.d
DRUNTIME_DSOURCES_DRAGONFLYBSD = core/sys/dragonflybsd/dlfcn.d \
core/sys/dragonflybsd/execinfo.d core/sys/dragonflybsd/netinet/in_.d \
@@ -1196,7 +1196,6 @@ gcc/sections/$(am__dirstamp):
@$(MKDIR_P) gcc/sections
@: > gcc/sections/$(am__dirstamp)
gcc/sections/android.lo: gcc/sections/$(am__dirstamp)
-gcc/sections/common.lo: gcc/sections/$(am__dirstamp)
gcc/sections/elf_shared.lo: gcc/sections/$(am__dirstamp)
gcc/sections/osx.lo: gcc/sections/$(am__dirstamp)
gcc/sections/package.lo: gcc/sections/$(am__dirstamp)
@@ -1359,6 +1358,7 @@ core/sys/posix/utime.lo: core/sys/posix/$(am__dirstamp)
core/sys/darwin/$(am__dirstamp):
@$(MKDIR_P) core/sys/darwin
@: > core/sys/darwin/$(am__dirstamp)
+core/sys/darwin/config.lo: core/sys/darwin/$(am__dirstamp)
core/sys/darwin/crt_externs.lo: core/sys/darwin/$(am__dirstamp)
core/sys/darwin/dlfcn.lo: core/sys/darwin/$(am__dirstamp)
core/sys/darwin/execinfo.lo: core/sys/darwin/$(am__dirstamp)
diff --git a/libphobos/libdruntime/core/sys/darwin/execinfo.d b/libphobos/libdruntime/core/sys/darwin/execinfo.d
index c929cc2f88d..d9607f392eb 100644
--- a/libphobos/libdruntime/core/sys/darwin/execinfo.d
+++ b/libphobos/libdruntime/core/sys/darwin/execinfo.d
@@ -21,6 +21,11 @@ extern (C):
nothrow:
@nogc:
-int backtrace(void** buffer, int size);
-char** backtrace_symbols(const(void*)* buffer, int size);
-void backtrace_symbols_fd(const(void*)* buffer, int size, int fd);
+import core.sys.darwin.config;
+
+static if (__traits(getTargetInfo, "osxVersionMin") >= __MAC_10_5)
+{
+ int backtrace(void** buffer, int size);
+ char** backtrace_symbols(const(void*)* buffer, int size);
+ void backtrace_symbols_fd(const(void*)* buffer, int size, int fd);
+}
diff --git a/libphobos/libdruntime/gcc/sections/common.d b/libphobos/libdruntime/gcc/sections/common.d
deleted file mode 100644
index b2d2322347d..00000000000
--- a/libphobos/libdruntime/gcc/sections/common.d
+++ /dev/null
@@ -1,48 +0,0 @@
-// Common support routines for retrieving platform-specific sections.
-// Copyright (C) 2019 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 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.).
- */
-void safeAssert(bool condition, scope string msg, size_t line = __LINE__) @nogc nothrow @safe
-{
- import core.internal.abort;
- condition || abort(msg, __FILE__, line);
-}
-
-/****
- * 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]; }
diff --git a/libphobos/libdruntime/gcc/sections/osx.d b/libphobos/libdruntime/gcc/sections/osx.d
index 6ace2da4a8b..9ec5b79974e 100644
--- a/libphobos/libdruntime/gcc/sections/osx.d
+++ b/libphobos/libdruntime/gcc/sections/osx.d
@@ -24,17 +24,31 @@ module gcc.sections.osx;
version (OSX):
-import gcc.sections.common;
-
+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;
version (GNU_EMUTLS)
import gcc.emutls;
+/****
+ * 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.).
+ */
+void safeAssert(bool condition, scope string msg, size_t line = __LINE__) @nogc nothrow @safe
+{
+ import core.internal.abort;
+ condition || abort(msg, __FILE__, line);
+}
+
alias DSO SectionGroup;
struct DSO
{
@@ -74,8 +88,22 @@ struct DSO
}
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
+ }
}
/****
@@ -99,63 +127,185 @@ void finiSections() nothrow @nogc
_isRuntimeInitialized = false;
}
-void[]* initTLSRanges() nothrow @nogc
-{
- return null;
-}
+alias ScanDG = void delegate(void* pbeg, void* pend) nothrow;
-void finiTLSRanges(void[]* rng) nothrow @nogc
+version (Shared)
{
-}
+ /***
+ * Called once per thread; returns array of thread local storage ranges
+ */
+ Array!(ThreadDSO)* initTLSRanges() @nogc nothrow
+ {
+ return &_loadedDSOs();
+ }
-void scanTLSRanges(void[]* rng, scope void delegate(void* pbeg, void* pend) nothrow dg) nothrow
-{
- version (GNU_EMUTLS)
- _d_emutls_scan(dg);
- else
- static assert(0, "Native TLS unimplemented");
-}
+ 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");
+ }
-version (Shared)
-{
// interface for core.thread to inherit loaded libraries
void* pinLoadedLibraries() nothrow @nogc
{
- return null;
+ 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;
}
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.
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.
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:
-/*
- * Static DSOs loaded by the runtime linker. This includes the
- * executable. These can't be unloaded.
- */
-@property ref Array!(DSO*) _loadedDSOs() @nogc nothrow
+version (Shared)
{
- __gshared Array!(DSO*) x;
- return x;
+ /*
+ * 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;
+ }
-/*
- * Set to true during rt_loadLibrary/rt_unloadLibrary calls.
- */
-enum _rtLoading = false;
+ enum _rtLoading = false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Compiler to runtime interface.
+///////////////////////////////////////////////////////////////////////////////
struct MachHeader
{
@@ -163,9 +313,18 @@ struct MachHeader
intptr_t slide; // virtural memory address slide amount
}
-///////////////////////////////////////////////////////////////////////////////
-// 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().
@@ -180,27 +339,57 @@ extern(C) void _d_dso_registry(CompilerDSOData* data)
// 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 info = void;
- const headerFound = findDSOHeaderForAddr(data._slot, &info);
+ MachHeader header = void;
+ const headerFound = findImageHeaderForAddr(data._slot, header);
safeAssert(headerFound, "Failed to find image header.");
- foreach (e; dataSegs)
+ 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
{
- 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]);
+ foreach (p; _loadedDSOs)
+ safeAssert(p !is pdso, "DSO already registered.");
+ _loadedDSOs.insertBack(pdso);
}
- 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
@@ -208,22 +397,274 @@ extern(C) void _d_dso_registry(CompilerDSOData* data)
DSO* pdso = cast(DSO*)*data._slot;
*data._slot = null;
- // static DSOs are unloaded in reverse order
- safeAssert(pdso == _loadedDSOs.back, "DSO being unregistered isn't current last one.");
- _loadedDSOs.popBack();
+ // 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();
+ }
- pdso._gcRanges.reset();
- .free(pdso);
+ 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
@@ -231,28 +672,38 @@ extern(C) void _d_dso_registry(CompilerDSOData* data)
* true if found, and *result is filled in
*/
-bool findDSOHeaderForAddr(in void* addr, MachHeader* result)
+bool findImageHeaderForAddr(in void* addr, out MachHeader result)
{
+ Dl_info info;
+ if (dladdr(addr, &info) == 0)
+ return false;
+
foreach (i; 0 .. _dyld_image_count())
{
- const header = _dyld_get_image_header(i);
- const slide = _dyld_get_image_vmaddr_slide(i);
- const section = getSection(header, slide, SEG_DATA, SECT_DATA);
-
- // less than base address of section means quick reject
- if (!section.length || addr < section.ptr)
- continue;
-
- if (addr < section.ptr + section.length)
+ if (info.dli_fbase == _dyld_get_image_header(i))
{
- result.header = header;
- result.slide = slide;
+ 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;
^ permalink raw reply [flat|nested] 12+ messages in thread
* [gcc(refs/users/ibuclaw/heads/darwin)] libphobos: Align interface of gcc.sections.osx with gcc.sections.elf_shared
@ 2020-12-07 0:40 Iain Buclaw
0 siblings, 0 replies; 12+ messages in thread
From: Iain Buclaw @ 2020-12-07 0:40 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:a09e8e1e390a649775d9c5eb0de22992edaac3ac
commit a09e8e1e390a649775d9c5eb0de22992edaac3ac
Author: Iain Buclaw <ibuclaw@gdcproject.org>
Date: Mon Dec 7 01:25:17 2020 +0100
libphobos: Align interface of gcc.sections.osx with gcc.sections.elf_shared
Diff:
---
libphobos/libdruntime/Makefile.am | 30 +-
libphobos/libdruntime/Makefile.in | 64 +--
libphobos/libdruntime/core/sys/darwin/execinfo.d | 11 +-
libphobos/libdruntime/gcc/sections/common.d | 48 --
libphobos/libdruntime/gcc/sections/osx.d | 569 ++++++++++++++++++++---
5 files changed, 565 insertions(+), 157 deletions(-)
diff --git a/libphobos/libdruntime/Makefile.am b/libphobos/libdruntime/Makefile.am
index 124d5b049d0..722f1edfe09 100644
--- a/libphobos/libdruntime/Makefile.am
+++ b/libphobos/libdruntime/Makefile.am
@@ -183,21 +183,21 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \
gc/impl/conservative/gc.d gc/impl/manual/gc.d gc/os.d gc/pooltable.d \
gc/proxy.d gcc/attribute.d gcc/backtrace.d gcc/builtins.d gcc/deh.d \
gcc/emutls.d gcc/gthread.d gcc/sections/android.d \
- gcc/sections/common.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/typeinfo/ti_Acdouble.d \
- rt/typeinfo/ti_Acfloat.d rt/typeinfo/ti_Acreal.d \
- rt/typeinfo/ti_Adouble.d rt/typeinfo/ti_Afloat.d rt/typeinfo/ti_Ag.d \
- rt/typeinfo/ti_Aint.d rt/typeinfo/ti_Along.d rt/typeinfo/ti_Areal.d \
- rt/typeinfo/ti_Ashort.d rt/typeinfo/ti_C.d rt/typeinfo/ti_byte.d \
- rt/typeinfo/ti_cdouble.d rt/typeinfo/ti_cent.d rt/typeinfo/ti_cfloat.d \
- rt/typeinfo/ti_char.d rt/typeinfo/ti_creal.d rt/typeinfo/ti_dchar.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/typeinfo/ti_Acdouble.d rt/typeinfo/ti_Acfloat.d \
+ rt/typeinfo/ti_Acreal.d rt/typeinfo/ti_Adouble.d \
+ rt/typeinfo/ti_Afloat.d rt/typeinfo/ti_Ag.d rt/typeinfo/ti_Aint.d \
+ rt/typeinfo/ti_Along.d rt/typeinfo/ti_Areal.d rt/typeinfo/ti_Ashort.d \
+ rt/typeinfo/ti_C.d rt/typeinfo/ti_byte.d rt/typeinfo/ti_cdouble.d \
+ rt/typeinfo/ti_cent.d rt/typeinfo/ti_cfloat.d rt/typeinfo/ti_char.d \
+ rt/typeinfo/ti_creal.d rt/typeinfo/ti_dchar.d \
rt/typeinfo/ti_delegate.d rt/typeinfo/ti_double.d \
rt/typeinfo/ti_float.d rt/typeinfo/ti_idouble.d \
rt/typeinfo/ti_ifloat.d rt/typeinfo/ti_int.d rt/typeinfo/ti_ireal.d \
diff --git a/libphobos/libdruntime/Makefile.in b/libphobos/libdruntime/Makefile.in
index 3bf08f52b31..d99998d8934 100644
--- a/libphobos/libdruntime/Makefile.in
+++ b/libphobos/libdruntime/Makefile.in
@@ -207,10 +207,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/backtrace.lo \
gcc/builtins.lo gcc/deh.lo gcc/emutls.lo gcc/gthread.lo \
- gcc/sections/android.lo gcc/sections/common.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/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/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 \
@@ -268,9 +267,10 @@ am__objects_3 = core/sys/posix/aio.lo core/sys/posix/arpa/inet.lo \
core/sys/posix/time.lo core/sys/posix/ucontext.lo \
core/sys/posix/unistd.lo core/sys/posix/utime.lo
@DRUNTIME_OS_POSIX_TRUE@am__objects_4 = $(am__objects_3)
-am__objects_5 = core/sys/darwin/crt_externs.lo \
- core/sys/darwin/dlfcn.lo core/sys/darwin/execinfo.lo \
- core/sys/darwin/mach/dyld.lo core/sys/darwin/mach/getsect.lo \
+am__objects_5 = core/sys/darwin/config.lo \
+ core/sys/darwin/crt_externs.lo core/sys/darwin/dlfcn.lo \
+ core/sys/darwin/execinfo.lo core/sys/darwin/mach/dyld.lo \
+ core/sys/darwin/mach/getsect.lo \
core/sys/darwin/mach/kern_return.lo \
core/sys/darwin/mach/loader.lo core/sys/darwin/mach/port.lo \
core/sys/darwin/mach/semaphore.lo \
@@ -809,21 +809,21 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \
gc/impl/conservative/gc.d gc/impl/manual/gc.d gc/os.d gc/pooltable.d \
gc/proxy.d gcc/attribute.d gcc/backtrace.d gcc/builtins.d gcc/deh.d \
gcc/emutls.d gcc/gthread.d gcc/sections/android.d \
- gcc/sections/common.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/typeinfo/ti_Acdouble.d \
- rt/typeinfo/ti_Acfloat.d rt/typeinfo/ti_Acreal.d \
- rt/typeinfo/ti_Adouble.d rt/typeinfo/ti_Afloat.d rt/typeinfo/ti_Ag.d \
- rt/typeinfo/ti_Aint.d rt/typeinfo/ti_Along.d rt/typeinfo/ti_Areal.d \
- rt/typeinfo/ti_Ashort.d rt/typeinfo/ti_C.d rt/typeinfo/ti_byte.d \
- rt/typeinfo/ti_cdouble.d rt/typeinfo/ti_cent.d rt/typeinfo/ti_cfloat.d \
- rt/typeinfo/ti_char.d rt/typeinfo/ti_creal.d rt/typeinfo/ti_dchar.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/typeinfo/ti_Acdouble.d rt/typeinfo/ti_Acfloat.d \
+ rt/typeinfo/ti_Acreal.d rt/typeinfo/ti_Adouble.d \
+ rt/typeinfo/ti_Afloat.d rt/typeinfo/ti_Ag.d rt/typeinfo/ti_Aint.d \
+ rt/typeinfo/ti_Along.d rt/typeinfo/ti_Areal.d rt/typeinfo/ti_Ashort.d \
+ rt/typeinfo/ti_C.d rt/typeinfo/ti_byte.d rt/typeinfo/ti_cdouble.d \
+ rt/typeinfo/ti_cent.d rt/typeinfo/ti_cfloat.d rt/typeinfo/ti_char.d \
+ rt/typeinfo/ti_creal.d rt/typeinfo/ti_dchar.d \
rt/typeinfo/ti_delegate.d rt/typeinfo/ti_double.d \
rt/typeinfo/ti_float.d rt/typeinfo/ti_idouble.d \
rt/typeinfo/ti_ifloat.d rt/typeinfo/ti_int.d rt/typeinfo/ti_ireal.d \
@@ -841,15 +841,15 @@ DRUNTIME_DSOURCES_STDCXX = core/stdcpp/exception.d \
DRUNTIME_DSOURCES_BIONIC = core/sys/bionic/fcntl.d \
core/sys/bionic/string.d core/sys/bionic/unistd.d
-DRUNTIME_DSOURCES_DARWIN = core/sys/darwin/crt_externs.d \
- core/sys/darwin/dlfcn.d core/sys/darwin/execinfo.d \
- core/sys/darwin/mach/dyld.d core/sys/darwin/mach/getsect.d \
- core/sys/darwin/mach/kern_return.d core/sys/darwin/mach/loader.d \
- core/sys/darwin/mach/port.d core/sys/darwin/mach/semaphore.d \
- core/sys/darwin/mach/thread_act.d core/sys/darwin/netinet/in_.d \
- core/sys/darwin/pthread.d core/sys/darwin/string.d \
- core/sys/darwin/sys/cdefs.d core/sys/darwin/sys/event.d \
- core/sys/darwin/sys/mman.d
+DRUNTIME_DSOURCES_DARWIN = core/sys/darwin/config.d \
+ core/sys/darwin/crt_externs.d core/sys/darwin/dlfcn.d \
+ core/sys/darwin/execinfo.d core/sys/darwin/mach/dyld.d \
+ core/sys/darwin/mach/getsect.d core/sys/darwin/mach/kern_return.d \
+ core/sys/darwin/mach/loader.d core/sys/darwin/mach/port.d \
+ core/sys/darwin/mach/semaphore.d core/sys/darwin/mach/thread_act.d \
+ core/sys/darwin/netinet/in_.d core/sys/darwin/pthread.d \
+ core/sys/darwin/string.d core/sys/darwin/sys/cdefs.d \
+ core/sys/darwin/sys/event.d core/sys/darwin/sys/mman.d
DRUNTIME_DSOURCES_DRAGONFLYBSD = core/sys/dragonflybsd/dlfcn.d \
core/sys/dragonflybsd/execinfo.d core/sys/dragonflybsd/netinet/in_.d \
@@ -1196,7 +1196,6 @@ gcc/sections/$(am__dirstamp):
@$(MKDIR_P) gcc/sections
@: > gcc/sections/$(am__dirstamp)
gcc/sections/android.lo: gcc/sections/$(am__dirstamp)
-gcc/sections/common.lo: gcc/sections/$(am__dirstamp)
gcc/sections/elf_shared.lo: gcc/sections/$(am__dirstamp)
gcc/sections/osx.lo: gcc/sections/$(am__dirstamp)
gcc/sections/package.lo: gcc/sections/$(am__dirstamp)
@@ -1359,6 +1358,7 @@ core/sys/posix/utime.lo: core/sys/posix/$(am__dirstamp)
core/sys/darwin/$(am__dirstamp):
@$(MKDIR_P) core/sys/darwin
@: > core/sys/darwin/$(am__dirstamp)
+core/sys/darwin/config.lo: core/sys/darwin/$(am__dirstamp)
core/sys/darwin/crt_externs.lo: core/sys/darwin/$(am__dirstamp)
core/sys/darwin/dlfcn.lo: core/sys/darwin/$(am__dirstamp)
core/sys/darwin/execinfo.lo: core/sys/darwin/$(am__dirstamp)
diff --git a/libphobos/libdruntime/core/sys/darwin/execinfo.d b/libphobos/libdruntime/core/sys/darwin/execinfo.d
index c929cc2f88d..d9607f392eb 100644
--- a/libphobos/libdruntime/core/sys/darwin/execinfo.d
+++ b/libphobos/libdruntime/core/sys/darwin/execinfo.d
@@ -21,6 +21,11 @@ extern (C):
nothrow:
@nogc:
-int backtrace(void** buffer, int size);
-char** backtrace_symbols(const(void*)* buffer, int size);
-void backtrace_symbols_fd(const(void*)* buffer, int size, int fd);
+import core.sys.darwin.config;
+
+static if (__traits(getTargetInfo, "osxVersionMin") >= __MAC_10_5)
+{
+ int backtrace(void** buffer, int size);
+ char** backtrace_symbols(const(void*)* buffer, int size);
+ void backtrace_symbols_fd(const(void*)* buffer, int size, int fd);
+}
diff --git a/libphobos/libdruntime/gcc/sections/common.d b/libphobos/libdruntime/gcc/sections/common.d
deleted file mode 100644
index b2d2322347d..00000000000
--- a/libphobos/libdruntime/gcc/sections/common.d
+++ /dev/null
@@ -1,48 +0,0 @@
-// Common support routines for retrieving platform-specific sections.
-// Copyright (C) 2019 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 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.).
- */
-void safeAssert(bool condition, scope string msg, size_t line = __LINE__) @nogc nothrow @safe
-{
- import core.internal.abort;
- condition || abort(msg, __FILE__, line);
-}
-
-/****
- * 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]; }
diff --git a/libphobos/libdruntime/gcc/sections/osx.d b/libphobos/libdruntime/gcc/sections/osx.d
index 6ace2da4a8b..9ec5b79974e 100644
--- a/libphobos/libdruntime/gcc/sections/osx.d
+++ b/libphobos/libdruntime/gcc/sections/osx.d
@@ -24,17 +24,31 @@ module gcc.sections.osx;
version (OSX):
-import gcc.sections.common;
-
+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;
version (GNU_EMUTLS)
import gcc.emutls;
+/****
+ * 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.).
+ */
+void safeAssert(bool condition, scope string msg, size_t line = __LINE__) @nogc nothrow @safe
+{
+ import core.internal.abort;
+ condition || abort(msg, __FILE__, line);
+}
+
alias DSO SectionGroup;
struct DSO
{
@@ -74,8 +88,22 @@ struct DSO
}
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
+ }
}
/****
@@ -99,63 +127,185 @@ void finiSections() nothrow @nogc
_isRuntimeInitialized = false;
}
-void[]* initTLSRanges() nothrow @nogc
-{
- return null;
-}
+alias ScanDG = void delegate(void* pbeg, void* pend) nothrow;
-void finiTLSRanges(void[]* rng) nothrow @nogc
+version (Shared)
{
-}
+ /***
+ * Called once per thread; returns array of thread local storage ranges
+ */
+ Array!(ThreadDSO)* initTLSRanges() @nogc nothrow
+ {
+ return &_loadedDSOs();
+ }
-void scanTLSRanges(void[]* rng, scope void delegate(void* pbeg, void* pend) nothrow dg) nothrow
-{
- version (GNU_EMUTLS)
- _d_emutls_scan(dg);
- else
- static assert(0, "Native TLS unimplemented");
-}
+ 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");
+ }
-version (Shared)
-{
// interface for core.thread to inherit loaded libraries
void* pinLoadedLibraries() nothrow @nogc
{
- return null;
+ 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;
}
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.
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.
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:
-/*
- * Static DSOs loaded by the runtime linker. This includes the
- * executable. These can't be unloaded.
- */
-@property ref Array!(DSO*) _loadedDSOs() @nogc nothrow
+version (Shared)
{
- __gshared Array!(DSO*) x;
- return x;
+ /*
+ * 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;
+ }
-/*
- * Set to true during rt_loadLibrary/rt_unloadLibrary calls.
- */
-enum _rtLoading = false;
+ enum _rtLoading = false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Compiler to runtime interface.
+///////////////////////////////////////////////////////////////////////////////
struct MachHeader
{
@@ -163,9 +313,18 @@ struct MachHeader
intptr_t slide; // virtural memory address slide amount
}
-///////////////////////////////////////////////////////////////////////////////
-// 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().
@@ -180,27 +339,57 @@ extern(C) void _d_dso_registry(CompilerDSOData* data)
// 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 info = void;
- const headerFound = findDSOHeaderForAddr(data._slot, &info);
+ MachHeader header = void;
+ const headerFound = findImageHeaderForAddr(data._slot, header);
safeAssert(headerFound, "Failed to find image header.");
- foreach (e; dataSegs)
+ 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
{
- 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]);
+ foreach (p; _loadedDSOs)
+ safeAssert(p !is pdso, "DSO already registered.");
+ _loadedDSOs.insertBack(pdso);
}
- 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
@@ -208,22 +397,274 @@ extern(C) void _d_dso_registry(CompilerDSOData* data)
DSO* pdso = cast(DSO*)*data._slot;
*data._slot = null;
- // static DSOs are unloaded in reverse order
- safeAssert(pdso == _loadedDSOs.back, "DSO being unregistered isn't current last one.");
- _loadedDSOs.popBack();
+ // 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();
+ }
- pdso._gcRanges.reset();
- .free(pdso);
+ 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
@@ -231,28 +672,38 @@ extern(C) void _d_dso_registry(CompilerDSOData* data)
* true if found, and *result is filled in
*/
-bool findDSOHeaderForAddr(in void* addr, MachHeader* result)
+bool findImageHeaderForAddr(in void* addr, out MachHeader result)
{
+ Dl_info info;
+ if (dladdr(addr, &info) == 0)
+ return false;
+
foreach (i; 0 .. _dyld_image_count())
{
- const header = _dyld_get_image_header(i);
- const slide = _dyld_get_image_vmaddr_slide(i);
- const section = getSection(header, slide, SEG_DATA, SECT_DATA);
-
- // less than base address of section means quick reject
- if (!section.length || addr < section.ptr)
- continue;
-
- if (addr < section.ptr + section.length)
+ if (info.dli_fbase == _dyld_get_image_header(i))
{
- result.header = header;
- result.slide = slide;
+ 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;
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2021-09-17 14:34 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-01-28 17:31 [gcc(refs/users/ibuclaw/heads/darwin)] libphobos: Align interface of gcc.sections.osx with gcc.sections.elf_shared Iain Buclaw
-- strict thread matches above, loose matches on Subject: below --
2021-09-17 14:34 Iain Buclaw
2021-04-19 18:06 Iain Buclaw
2021-04-10 17:01 Iain Buclaw
2021-04-10 15:04 Iain Buclaw
2021-03-14 22:00 Iain Buclaw
2021-03-07 17:01 Iain Buclaw
2021-01-30 19:08 Iain Buclaw
2021-01-11 11:39 Iain Buclaw
2020-12-22 13:41 Iain Buclaw
2020-12-09 9:51 Iain Buclaw
2020-12-07 0:40 Iain Buclaw
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).