thread_local is a c++11 feature that newer software is increasingly using. It 
is available with gcc 4.8+, and with clang since about clang-3.5. On macOS 
(darwin) it requires system supports that arrived in 10.7. 

My goal is to get thread_local with clang-5.0 and newer on 10.6 (and 10.5). 
Turns out this may actually be not too hard to do. The LLVM team has enabled a 
form of thread_local called emulated-tls that is based on emultls.c in the llvm 
compiler-runtime project. This is currently enabled by default for a few OS 
versions.


With three very simple patches, clang-5.0 can be made to support thread_local 
on 10.6, using emutls.c.

1. Tell clang it is allowed to support thread_local on older systems:
<https://github.com/kencu/SnowLeopardPorts/blob/master/lang/llvm-5.0/files/9998-patch-tools-clang-lib-basic-targets-force-tls.diff>

2. pass the -femulated-tls flag by default on older systems:
<https://github.com/kencu/SnowLeopardPorts/blob/master/lang/llvm-5.0/files/9998-patch-tools-clang-lib-basic-targets-force-tls.diff>

3. tell clang to call __cxa_thread_atexit instead of _tlv_atexit on older 
darwin systems that don't have _tlv_atexit
<https://github.com/kencu/SnowLeopardPorts/blob/master/lang/llvm-5.0/files/9998-patch-tools-clang-lib-codegen-itanium-cxa-atexit.diff>


With those minor changes, clang-5.0 supports thread_local quite nicely, it 
appears, to build software that requires __thread and thread_local support. 
This works reasonably when linked against the newer libstdc++ , using 
-stdlib=macports-libstdc++ as MacPorts does currently. 


But there is a slight issue that I'm stuck on. I prefer to use libc++. First of 
all, to support this, the file cxa_thread_atexit.c is not compiled into 
libc++abi by default on Darwin, but it's not too difficult to add it to the 
build and compile it in. 

Once that is done, software built with thread support against libc++ works for 
simple (automatic) destructors, but with non-trivial destructors, there is an 
error I can't sort out: 

$ ./thread-test
dyld: lazy symbol binding failed: Symbol not found: ___emutls_get_address
 Referenced from: /usr/lib/libc++abi.dylib
 Expected in: flat namespace
Trace/BPT trap


__emutls_get_address is a function in emutls.c, from the clang-runtime library. 
It is indeed compiled into the thread-test program

$ nm thread-test | grep emu
0000000100003e20 t ___emutls_get_address
0000000100005228 d ___emutls_v.__tls_guard
0000000100005208 d ___emutls_v.tlobj
0000000100003fb0 t _emutls_init
0000000100005248 d _emutls_init_once.once
0000000100003fd0 t _emutls_key_destructor
0000000100005258 d _emutls_mutex
00000001000052a8 b _emutls_num_object
00000001000052b0 b _emutls_pthread_key

and disassembling the executable shows proper looking code (very similar to the 
code that is generated when linked against -stdlib=macports-libstdc++, in fact).

But for some reason, libc++abi.dylib apparently can't see the symbol for 
___emutls_get_address in the executable. The exact same code works normally 
when linked against /opt/local/lib/libgcc/libstdc++.6.dylib

I tried -flat_namespace and -force_flat_namespace but that didn't fix it.



So -- I thought I'd ask here in case anyone sees something silly or obvious I'm 
forgetting to do. 

Thanks to anyone who has taken the trouble to read through to this point.

Ken






Reply via email to