thread_local with clang-5.0 on 10.6 (and lower) -- works , but slight issue with libc++ that I would appreciate some help with.

Ken Cunningham ken.cunningham.webuse at
Sat Feb 24 22:34:08 UTC 2018

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:

2. pass the -femulated-tls flag by default on older systems:

3. tell clang to call __cxa_thread_atexit instead of _tlv_atexit on older darwin systems that don't have _tlv_atexit

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.


More information about the macports-users mailing list