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:
Martin Kinkelin 2024-06-11 15:39:17 +02:00 committed by The Dlang Bot
parent 94057dfdc0
commit 635aeb79c2
7 changed files with 15 additions and 306 deletions

View file

@ -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

View file

@ -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 \

View file

@ -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 \

View file

@ -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*);

View file

@ -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

View file

@ -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;
}
}
}

View file

@ -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):