TLS for Android (and iOS)
Dan Olson
zans.is.for.cans at yahoo.com
Sun Mar 30 01:22:14 PDT 2014
"Joakim" <joakim at airpost.net> writes:
> On Thursday, 27 March 2014 at 16:01:31 UTC, Dan Olson wrote:
>
>> If nobody is working on the emulated TLS for LDC, I will give it a
>> try.
>> Nothing to lose.
>
> Whatever I do to implement packed TLS in the dmd backend is not going
> to work for ldc anyway, so nothing stopping you from making your own
> effort. You will have to patch llvm also, if the weak symbols bug
> David pointed out is still around in llvm 3.5. Let us know what
> approach you take.
The approach I started with was to make LLVM do the work. I read
through all of the comments in this thread and decided this might be the
most fun.
ARMISelLowering.cpp has TLS disabled for all but ELF targets. I
commented out an assertion blocking other targets to see what would
happen for iOS (Mach-O). To my suprise, found that Mach-O tls sections
are generated (__thread_vars, __thread_data, .tbss) and populated with
the D thread local vars.
The load/store instructions were treating TLS vars like global data
though. So I looked at the Mach-O X86 version and saw what it is trying
to do. LLVM coding is still a mystery to me, but managed after many
hours today to hack together something that would turn this D code
module tlsd;
int a;
void test()
{
a += 4; // access a
}
into this:
movw r0, :lower16:(__D4tlsd1ai-(LPC4_0+4))
movt r0, :upper16:(__D4tlsd1ai-(LPC4_0+4))
LPC4_0:
add r0, pc
blx ___tls_get_addr
ldr r1, [r0]
adds r1, #4
str r1, [r0]
...
.tbss __D4tlsd1ai$tlv$init, 4, 2
.section __DATA,__thread_vars,thread_local_variables
.globl __D4tlsd1ai
__D4tlsd1ai:
.long __tlv_bootstrap
.long 0
.long __D4tlsd1ai$tlv$init
The following link helped explain what is going on with the
__thread_vars data layout.
http://www.opensource.apple.com/source/dyld/dyld-210.2.3/src/threadLocalVariables.c
Mach-O dyln replaces tlv_bootstrap (thunk) with tlv_get_addr in the
TLVDescriptor (__thread_vars). My LLVM hack for now is just doing a
direct call to __tls_get_addr instead of indirect to tlv_get_addr. For
proof of concept (one thread only), I have __tls_get_addr hard wired as
follows:
extern (C)
{
struct TLVDescriptor
{
void* function(TLVDescriptor*) thunk;
uint key;
uint offset;
}
//void* tlv_get_addr(TLVDescriptor* d)
//void* __tls_get_addr(void* ptr)
void* __tls_get_addr(TLVDescriptor* tlvd)
{
__gshared static ubyte data[512];
printf("__tls_get_addr %p \n", tlvd);
printf("thunk %p, key %u, offset %u\n",
tlvd.thunk, tlvd.key, tlvd.offset);
return data.ptr + tlvd.offset;
}
void _tlv_bootstrap()
{
assert(false, "Should not get here");
}
}
It looks promising. Next step is to add in some realistic runtime
support. Not sure if I will base it on dmd's sections-osx or the Apple
dyld. Probably a hybrid.
Eventually will need some help getting the LLVM changes clean instead of
my hack job.
Now that I've gone down this path a bit, I am beginning to wonder if
changing LLVM to support iOS thread locals will have issues. Would LLVM
want changes that affect Darwin/Mach-O (Apple's turf)? I suppose they
could be optional.
--
Dan
More information about the digitalmars-d-ldc
mailing list