thread_local storage on 10.6.8 (and earlier) with clang-7.0

Ken Cunningham ken.cunningham.webuse at
Wed Dec 12 16:54:02 UTC 2018

Some more detailed / better answers to your raised issues:

On 2018-12-09, at 9:50 PM, Jeremy Sequoia wrote:

>> The issue is the "___emutls_get_address" function, which is called from libc++abi.dylib, and is built into clang_rt:
>> $ nm /opt/local/libexec/llvm-5.0/lib/clang/5.0.1/lib/darwin/libclang_rt.10.4.a  | grep emu
>> /opt/local/libexec/llvm-5.0/lib/clang/5.0.1/lib/darwin/libclang_rt.10.4.a(emutls.c.o):
>> 0000000000000000 T ___emutls_get_address
>> 00000000000001a0 t _emutls_init
>> 0000000000000210 d _emutls_init_once.once
>> 00000000000001c0 t _emutls_key_destructor
>> 0000000000000220 d _emutls_mutex
>> 00000000000002f8 b _emutls_num_object
>> 0000000000000300 b _emutls_pthread_key
>> These objects appear to be included in the built executables,  but are apparently NOT visible to libc++abi.dylib at runtime (you can see the small "t" indicating they are local only, and generate a runtime error when you try to run it.
> Are they intended to be exported?  If so, you should be able to add the to the exports list or adjust the symbol visibility at compile time (I forget which approach libc++abi uses).

>> If I try to fix it like this by forcing the symbol to be exported, I get a clue:
>> $ clang++ -std=c++11 -stdlib=libc++ -Wl,-exported_symbol,___emutls_get_address  -o 4 4.cpp
>> ld: warning: cannot export hidden symbol ___emutls_get_address from /opt/local/libexec/llvm-5.0/lib/clang/5.0.1/lib/darwin/libclang_rt.osx.a(emutls.c.o)
> It is explicitly marked as hidden so as to not be exported.  Do you know why?

I was under the (mistaken) impression that some of these symbols which are incorporated into the executable from libclang_rt were supposed to be used by libc++abi.dylib at runtime, but were somehow not visible. I could not sort out why they were not visible.

BUT I now know that symbols in static libraries that are linked in by an executable are specifically always hidden to prevent name collisions, and making such symbols in executables visible might be either very difficult or perhaps not possible at all.

In the end to fix it I needed to specifically force libc++abi to link against libclang_rt during the build, because "nodefaultlibs" is used during the libc++abi build so it wasn't done automatically.

Simple, once you know the problem...

>> $ nm 4 | grep emu

>> $ ./4
>> info: testing pthread_create
>> dyld: lazy symbol binding failed: Symbol not found: ___emutls_get_address
>> Referenced from: /usr/lib/libc++abi.dylib
>> Expected in: flat namespace
> How is this even linking?  Are you using -undefined dynamic_lookup?  Please don’t as that masks problems.

the libc++abi build script indeed uses -undefined dynamic_lookup -- I think it always has done.

The details of why it is done are in the cxa_thread_atexit.c source file, but has to do with building a thread_local enabled libc++abi while on a system without a thread_local enabled toolchain, I believe. 

Some symbols are resolved dynamically at runtime, and fallbacks used if they are unavailable.

So it did mask the problem with emutls_get_address.



More information about the macports-dev mailing list