Intended usage of _GLIBCXX_HAVE_TLS / emutls symbols on OSX

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



I am having a problem building on OSX with clang, against the gcc
standard library (there are project constraints behind why I am doing
this). I am using homebrew packages for both clang and gcc. This
pattern worked fine until a recent gcc package upgrade and I would at
least like to understand better what has happened. I don't believe
there's anything wrong in gcc - however, I was hoping someone could
help me understand the *intended* situation so I can decide what to
do...

Here's my example.cpp:
#include <mutex>
#include <iostream>
int main()
{
    std::once_flag flag;
    std::call_once(flag, [](){ std::cout << "Foo\n"; });
    return 0;
}

If I build and run with any of (homebrew) clang 7.1.0, gcc 7.4.0 or
gcc 7.5.0, it builds and runs fine:
> /usr/local/Cellar/llvm@7/7.1.0_1/bin/clang++ -std=c++17 example.cpp -o example
> /usr/local/Cellar/gcc@7/7.4.0_2/bin/g++-7 -std=c++17 example.cpp -o example
> /usr/local/Cellar/gcc@7/7.5.0/bin/g++-7 -std=c++17 example.cpp -o example

If I build with clang, but link against the gcc 7.4.0 std lib, it also
builds and runs fine:
> /usr/local/Cellar/llvm@7/7.1.0_1/bin/clang++ -isystem /usr/local/Cellar/gcc@7/7.4.0_2/include/c++/7.4.0 -isystem /usr/local/Cellar/gcc@7/7.4.0_2/include/c++/7.4.0/x86_64-apple-darwin18.5.0 -isystem /usr/local/Cellar/gcc@7/7.4.0_2/include/c++/7.4.0/backward -L /usr/local/Cellar/gcc@7/7.4.0_2/lib/gcc/7 -nostdinc++ -stdlib=libstdc++ -std=c++17 example.cpp -o example

In this case, the executable has the following undefined symbols which
are provided by the runtime stdc++ library:
> nm example | grep __once
                 U __ZSt14__once_functor
                 U ___once_proxy
> nm /usr/local/Cellar/gcc\@7/7.4.0_2/lib/gcc/7/libstdc++.6.dylib | grep __once
0000000000139420 S __ZSt14__once_functor
00000000001357c0 s
__ZZN12_GLOBAL__N_127__get_once_functor_lock_ptrEvE23__once_functor_lock_ptr
00000000001354b0 d
__ZZN9__gnu_cxx18__common_pool_baseINS_6__poolELb1EE18_S_initialize_onceEvE6__once
00000000000bb590 T ___once_proxy

However, if I now upgrade my homebrew gcc package to 7.5.0, things
change. I see that in this new version, _GLIBCXX_HAVE_TLS is #defined
as 1 in c++config.h (where previously it was undefined). Building with
gcc, <mutex> is now using __once_call and we link to the emulated TLS
versions from the standard library:
> /usr/local/Cellar/gcc@7/7.5.0/bin/g++-7 -std=c++17 example.cpp -o example
> nm example | grep __once
                 U ___emutls_v._ZSt11__once_call
                 U ___emutls_v._ZSt15__once_callable
                 U ___once_proxy
> nm /usr/local/Cellar/gcc\@7/7.5.0/lib/gcc/7/libstdc++.6.dylib | grep __once
0000000000135160 d
__ZZN9__gnu_cxx18__common_pool_baseINS_6__poolELb1EE18_S_initialize_onceEvE6__once
00000000001357a0 D ___emutls_v._ZSt11__once_call
0000000000135780 D ___emutls_v._ZSt15__once_callable
00000000000b7f90 T ___once_proxy


However, if I build with clang, I get unresolved symbols - the
compiler emits an object file that depends on _ZSt11__once_call,
instead of ___emutls_v._ZSt11__once_call:
> /usr/local/Cellar/llvm@7/7.1.0_1/bin/clang++ -isystem /usr/local/Cellar/gcc@7/7.5.0/include/c++/7.5.0 -isystem /usr/local/Cellar/gcc@7/7.5.0/include/c++/7.5.0/x86_64-apple-darwin18.7.0 -isystem /usr/local/Cellar/gcc@7/7.5.0/include/c++/7.5.0/backward -L /usr/local/Cellar/gcc@7/7.5.0/lib/gcc/7 -nostdinc++ -stdlib=libstdc++ -std=c++17 example.cpp -o example
Undefined symbols for architecture x86_64:
  "std::__once_call", referenced from:
      void std::call_once<main::$_0>(std::once_flag&, main::$_0&&) in
example-cba81f.o
  "std::__once_callable", referenced from:
      void std::call_once<main::$_0>(std::once_flag&, main::$_0&&) in
example-cba81f.o
      void std::call_once<main::$_0>(std::once_flag&,
main::$_0&&)::'lambda0'()::operator()() const in example-cba81f.o
ld: symbol(s) not found for architecture x86_64
clang-7: error: linker command failed with exit code 1 (use -v to see
invocation)

I thought maybe I could fix this by adding -femulated-tls. This seems
to cause the compiler to link to the correct symbol name in the
standard lib, but it segfaults at runtime when calling call_once:
> /usr/local/Cellar/llvm@7/7.1.0_1/bin/clang++ -isystem /usr/local/Cellar/gcc@7/7.5.0/include/c++/7.5.0 -isystem /usr/local/Cellar/gcc@7/7.5.0/include/c++/7.5.0/x86_64-apple-darwin18.7.0 -isystem /usr/local/Cellar/gcc@7/7.5.0/include/c++/7.5.0/backward -L /usr/local/Cellar/gcc@7/7.5.0/lib/gcc/7 -nostdinc++ -stdlib=libstdc++ -std=c++17 example.cpp -o example -femulated-tls
> ./example
Segmentation fault: 11 (core dumped)



I am unclear on the following:
1. Is it valid/sensible to define _GLIBCXX_HAVE_TLS for the gcc build
on OSX? I asked this also on the homebrew forum:
https://discourse.brew.sh/t/is-it-deliberate-that-the-gcc-7-7-5-formula-now-has-glibcxx-have-tls-defined/6500
2. Is there any performance or functionality reason to force the
decision on whether this should be defined or not?
3. Given that it works if I build with gcc 7.5.0 against its own std
lib, why does the clang build with -femulated-tls segfault?


As I said above I realise this is an issue with how these compiler
packages are being built and what I am trying to do with them, not a
gcc problem - and it may just be unsupported. However I would be very
appreciative of any insight on my above questions or suggestions of
where to go from here.

Dave




[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux