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