TLS for Android (and iOS)

Jacob Carlborg doob at me.com
Sun Mar 30 03:40:36 PDT 2014


On 2014-03-30 10:22, Dan Olson wrote:
> "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.

I would follow the native TLS implementation in OS X, i.e. using 
"tlv_get_addr", as close as possible. In theory it should be possible to 
move the code from threadLocalVariables.c and threadLocalHelpers.s 
directly in to druntime.

Hopefully that would mean the same code for generating TLS access could 
be used both on OS X and iOS.

-- 
/Jacob Carlborg


More information about the digitalmars-d-ldc mailing list