mirror of
https://github.com/dlang/dmd.git
synced 2025-04-26 05:00:16 +03:00
Android: Use rt.sections_elf_shared, not rt.sections_android
Android supports native ELF TLS since API level 29 (Android v10), so we can use the generic rt.sections_elf_shared implementation now, which among other things also enables *shared* druntime/Phobos libs.
This commit is contained in:
parent
94057dfdc0
commit
635aeb79c2
7 changed files with 15 additions and 306 deletions
|
@ -52,7 +52,6 @@ src/rt/dwarfeh.d @WalterBright
|
|||
src/rt/lifetime.d @rainers @schveiguy @Burgos
|
||||
src/rt/minfo.d @schveiguy
|
||||
src/rt/msvc* @rainers
|
||||
src/rt/sections_android.d @joakim-noah
|
||||
src/rt/sections_win* @rainers @CyberShadow
|
||||
src/rt/sections_osx* @jacob-carlborg @klickverbot
|
||||
src/rt/sections_elf_shared* @Burgos
|
||||
|
|
|
@ -565,7 +565,6 @@ DOCS=\
|
|||
$(DOCDIR)\rt_lifetime.html \
|
||||
$(DOCDIR)\rt_minfo.html \
|
||||
$(DOCDIR)\rt_profilegc.html \
|
||||
$(DOCDIR)\rt_sections_android.html \
|
||||
$(DOCDIR)\rt_sections_elf_shared.html \
|
||||
$(DOCDIR)\rt_sections_osx_x86.html \
|
||||
$(DOCDIR)\rt_sections_osx_x86_64.html \
|
||||
|
|
|
@ -581,7 +581,6 @@ SRCS=\
|
|||
src\rt\msvc_math.d \
|
||||
src\rt\profilegc.d \
|
||||
src\rt\sections.d \
|
||||
src\rt\sections_android.d \
|
||||
src\rt\sections_darwin_64.d \
|
||||
src\rt\sections_elf_shared.d \
|
||||
src\rt\sections_osx_x86.d \
|
||||
|
|
|
@ -372,12 +372,20 @@ else version (Solaris)
|
|||
}
|
||||
else version (CRuntime_Bionic)
|
||||
{
|
||||
enum
|
||||
enum RTLD_LOCAL = 0;
|
||||
enum RTLD_LAZY = 0x00001;
|
||||
enum RTLD_NOLOAD = 0x00004;
|
||||
enum RTLD_NODELETE = 0x01000;
|
||||
|
||||
version (D_LP64)
|
||||
{
|
||||
RTLD_NOW = 0,
|
||||
RTLD_LAZY = 1,
|
||||
RTLD_LOCAL = 0,
|
||||
RTLD_GLOBAL = 2
|
||||
enum RTLD_NOW = 0x00002;
|
||||
enum RTLD_GLOBAL = 0x00100;
|
||||
}
|
||||
else // NDK: 'LP32 is broken for historical reasons'
|
||||
{
|
||||
enum RTLD_NOW = 0;
|
||||
enum RTLD_GLOBAL = 0x00002;
|
||||
}
|
||||
|
||||
int dladdr(const scope void*, Dl_info*);
|
||||
|
|
|
@ -52,7 +52,7 @@ else version (Darwin)
|
|||
else version (CRuntime_Microsoft)
|
||||
public import rt.sections_win64;
|
||||
else version (CRuntime_Bionic)
|
||||
public import rt.sections_android;
|
||||
public import rt.sections_elf_shared;
|
||||
else version (CRuntime_UClibc)
|
||||
public import rt.sections_elf_shared;
|
||||
else
|
||||
|
|
|
@ -1,297 +0,0 @@
|
|||
/**
|
||||
* Written in the D programming language.
|
||||
* This module provides bionic-specific support for sections.
|
||||
*
|
||||
* Copyright: Copyright Martin Nowak 2012-2013.
|
||||
* License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
|
||||
* Authors: Martin Nowak
|
||||
* Source: $(DRUNTIMESRC rt/_sections_android.d)
|
||||
*/
|
||||
|
||||
module rt.sections_android;
|
||||
|
||||
version (CRuntime_Bionic):
|
||||
|
||||
// debug = PRINTF;
|
||||
debug(PRINTF) import core.stdc.stdio;
|
||||
import core.internal.elf.dl : SharedObject;
|
||||
import core.sys.posix.pthread;
|
||||
import core.stdc.stdlib : calloc, malloc, free;
|
||||
import core.stdc.string : memcpy;
|
||||
import rt.deh;
|
||||
import rt.minfo;
|
||||
import rt.util.utility : safeAssert;
|
||||
|
||||
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 return nothrow @nogc
|
||||
{
|
||||
return _moduleGroup;
|
||||
}
|
||||
|
||||
version (DigitalMars)
|
||||
@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);
|
||||
|
||||
SharedObject object;
|
||||
const success = SharedObject.findForAddress(&_sections, object);
|
||||
safeAssert(success, "cannot find ELF object");
|
||||
|
||||
_staticTLSRange = getStaticTLSRange(object, _tlsAlignment);
|
||||
// prevent the linker from stripping the TLS alignment symbols
|
||||
if (_staticTLSRange is null) // should never happen
|
||||
safeAssert(alignmentForTDATA == alignmentForTBSS, "unreachable");
|
||||
|
||||
version (LDC)
|
||||
{
|
||||
auto mbeg = cast(immutable ModuleInfo**)&__start___minfo;
|
||||
auto mend = cast(immutable ModuleInfo**)&__stop___minfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto mbeg = cast(immutable ModuleInfo**)&__start_minfo;
|
||||
auto mend = cast(immutable ModuleInfo**)&__stop_minfo;
|
||||
}
|
||||
_sections.moduleGroup = ModuleGroup(mbeg[0 .. mend - mbeg]);
|
||||
|
||||
// iterate over ELF segments to determine data segment range
|
||||
import core.sys.linux.elf;
|
||||
foreach (ref phdr; object)
|
||||
{
|
||||
if (phdr.p_type == PT_LOAD && (phdr.p_flags & PF_W)) // writeable data segment
|
||||
{
|
||||
safeAssert(_sections._gcRanges[0] is null, "expected a single data segment");
|
||||
|
||||
void* start = object.baseAddress + phdr.p_vaddr;
|
||||
void* end = start + phdr.p_memsz;
|
||||
debug(PRINTF) printf("data segment: %p - %p\n", start, end);
|
||||
|
||||
// pointer-align up
|
||||
enum mask = size_t.sizeof - 1;
|
||||
start = cast(void*) ((cast(size_t)start + mask) & ~mask);
|
||||
|
||||
_sections._gcRanges[0] = start[0 .. end-start];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
* .tdata/.tbss ELF sections, which are marked with the SHF_TLS/STT_TLS
|
||||
* flags. So instead we roll our own emulation (e.g., in LDC's LLVM fork)
|
||||
* by keeping static TLS data in the .tdata/.tbss sections but removing
|
||||
* the SHF_TLS/STT_TLS flags, and access the TLS data using this function.
|
||||
*
|
||||
* 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);
|
||||
const offset = cast(size_t) (p - _staticTLSRange.ptr);
|
||||
assert(offset < _staticTLSRange.length,
|
||||
"invalid TLS address or initSections() not called yet");
|
||||
// The following would only be safe if no TLS variables are accessed
|
||||
// before calling initTLSRanges():
|
||||
//return (cast(void[]*) pthread_getspecific(_tlsKey)).ptr + offset;
|
||||
return getTLSBlock().ptr + offset;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
__gshared pthread_key_t _tlsKey;
|
||||
__gshared void[] _staticTLSRange;
|
||||
__gshared uint _tlsAlignment;
|
||||
__gshared SectionGroup _sections;
|
||||
|
||||
/* The following code relies on the .tdata (non-zero initialized) and .tbss
|
||||
* (zero-initialized) sections to end up adjacent to each other in the final
|
||||
* linked binary.
|
||||
* This allows to merge both (and thus all TLS data) to a single contiguous
|
||||
* memory block.
|
||||
*/
|
||||
|
||||
/* Enforce some minimum alignment for both sections.
|
||||
* The relative offset of the 2nd section from the first (in memory) needs to be
|
||||
* a multiple of the 2nd section's alignment, so that the 2nd section ends up
|
||||
* suitably aligned in each thread's TLS block.
|
||||
*/
|
||||
enum minAlignment = 16;
|
||||
align(minAlignment)
|
||||
{
|
||||
byte alignmentForTDATA = 1;
|
||||
byte alignmentForTBSS;
|
||||
}
|
||||
|
||||
// aligned_alloc is only available since API level 28
|
||||
extern(C) int posix_memalign(void** memptr, size_t alignment, size_t size) nothrow @nogc;
|
||||
|
||||
ref void[] getTLSBlock() nothrow @nogc
|
||||
{
|
||||
auto pary = cast(void[]*) pthread_getspecific(_tlsKey);
|
||||
|
||||
version (LDC)
|
||||
{
|
||||
import ldc.intrinsics;
|
||||
const isUninitialized = llvm_expect(pary is null, false);
|
||||
}
|
||||
else
|
||||
const isUninitialized = pary is null;
|
||||
|
||||
if (isUninitialized)
|
||||
{
|
||||
pary = cast(void[]*) calloc(1, (void[]).sizeof);
|
||||
safeAssert(pary !is null, "cannot allocate TLS block slice");
|
||||
|
||||
if (pthread_setspecific(_tlsKey, pary) != 0)
|
||||
{
|
||||
import core.stdc.stdio;
|
||||
perror("pthread_setspecific failed with");
|
||||
assert(0);
|
||||
}
|
||||
|
||||
safeAssert(_staticTLSRange.ptr !is null, "initSections() not called yet");
|
||||
if (const size = _staticTLSRange.length)
|
||||
{
|
||||
void* p;
|
||||
const error = posix_memalign(&p, _tlsAlignment, size);
|
||||
safeAssert(error == 0, "cannot allocate TLS block");
|
||||
memcpy(p, _staticTLSRange.ptr, size);
|
||||
*pary = p[0 .. size];
|
||||
}
|
||||
}
|
||||
|
||||
return *pary;
|
||||
}
|
||||
|
||||
// Returns the static TLS data range (.tdata and .tbss sections).
|
||||
// `alignment` is set to the max overall TLS alignment, to be used to align each
|
||||
// thread's TLS block.
|
||||
void[] getStaticTLSRange(const ref SharedObject object, out uint alignment) nothrow @nogc
|
||||
{
|
||||
import core.internal.elf.io;
|
||||
|
||||
const(char)[] path = object.name();
|
||||
char[512] pathBuffer = void;
|
||||
if (path[0] != '/')
|
||||
{
|
||||
path = object.getPath(pathBuffer);
|
||||
safeAssert(path !is null, "cannot get path of ELF object");
|
||||
}
|
||||
debug(PRINTF) printf("ELF file path: %s\n", path.ptr);
|
||||
|
||||
ElfFile file;
|
||||
const success = ElfFile.open(path.ptr, file);
|
||||
safeAssert(success, "cannot open ELF file");
|
||||
|
||||
void* start, end;
|
||||
alignment = minAlignment;
|
||||
foreach (index, name, sectionHeader; file.namedSections)
|
||||
{
|
||||
if (name == ".tdata" || name == ".tbss")
|
||||
{
|
||||
void* sectionStart = object.baseAddress + sectionHeader.sh_addr;
|
||||
void* sectionEnd = sectionStart + sectionHeader.sh_size;
|
||||
const sectionAlignment = cast(uint) sectionHeader.sh_addralign;
|
||||
debug(PRINTF) printf("section %s: %p - %p, alignment: %u\n", name.ptr, sectionStart, sectionEnd, sectionAlignment);
|
||||
|
||||
if (sectionAlignment > alignment)
|
||||
alignment = sectionAlignment;
|
||||
|
||||
if (!start)
|
||||
{
|
||||
start = sectionStart;
|
||||
end = sectionEnd;
|
||||
}
|
||||
else
|
||||
{
|
||||
const bytesInbetweenSections = sectionStart - end;
|
||||
safeAssert(bytesInbetweenSections >= 0 && bytesInbetweenSections < alignment,
|
||||
"expected .tdata and .tbss sections to be adjacent (hint: try ld.bfd linker)");
|
||||
safeAssert(sectionAlignment == 0 || ((sectionStart - start) & (sectionAlignment - 1)) == 0,
|
||||
"offset of .tbss section from .tdata isn't a multiple of the .tbss alignment (workaround: align .tdata manually)");
|
||||
end = sectionEnd;
|
||||
break; // we've found both sections
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return an empty but non-null slice if there's no TLS data
|
||||
return start ? start[0 .. end-start] : object.baseAddress[0..0];
|
||||
}
|
||||
|
||||
extern(C)
|
||||
{
|
||||
/* Symbols created by the linker and inserted into the object file that
|
||||
* 'bracket' sections.
|
||||
*/
|
||||
extern __gshared
|
||||
{
|
||||
version (LDC)
|
||||
{
|
||||
void* __start___minfo;
|
||||
void* __stop___minfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
void* __start_deh;
|
||||
void* __stop_deh;
|
||||
void* __start_minfo;
|
||||
void* __stop_minfo;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@ else version (CRuntime_Musl) enum SharedELF = true;
|
|||
else version (FreeBSD) enum SharedELF = true;
|
||||
else version (NetBSD) enum SharedELF = true;
|
||||
else version (DragonFlyBSD) enum SharedELF = true;
|
||||
else version (CRuntime_Bionic) enum SharedELF = true;
|
||||
else version (CRuntime_UClibc) enum SharedELF = true;
|
||||
else enum SharedELF = false;
|
||||
static if (SharedELF):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue