Bug 215709 - Use of thread_local produces linking errors [now with gcc]
Summary: Use of thread_local produces linking errors [now with gcc]
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: threads (show other bugs)
Version: 11.0-RELEASE
Hardware: Any Any
: --- Affects Some People
Assignee: freebsd-threads (Nobody)
Keywords: patch
Depends on:
Reported: 2017-01-02 14:29 UTC by Hannes Hauswedell
Modified: 2017-07-27 07:19 UTC (History)
3 users (show)

See Also:

Provide __cxa_thread_atexit_impl(), split __cxa_thread_atexit() into separate .o. (10.28 KB, patch)
2017-01-03 17:03 UTC, Konstantin Belousov
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Hannes Hauswedell 2017-01-02 14:29:01 UTC
192320 implemented __cxa_thread_atexit so that base's clang now supports c++11's thread_local keyword. However, this seems to now have broken static linking with the GCCs that complain about double definitions:

cd /home/mi/h4nn3s/devel/lambda-build/pkg/src && /usr/local/bin/cmake -E cmake_link_script CMakeFiles/lambda.dir/link.txt --verbose=1
/usr/local/libexec/ccache/g++6     -fopenmp -Wno-vla -O3 -DNDEBUG -flto=8 -s   -static CMakeFiles/lambda.dir/lambda.cpp.o  -o ../bin/lambda  -lpthread -lexecinfo -lelf -lz -lbz2 
//usr/lib/libc.a(cxa_thread_atexit.o): In function `__cxa_thread_atexit':
/usr/src/lib/libc/stdlib/cxa_thread_atexit.c:(.text+0x0): multiple definition of `__cxa_thread_atexit'
/usr/local/lib/gcc6/gcc/x86_64-portbld-freebsd11.0/6.3.0/../../../libstdc++.a(atexit_thread.o):/wrkdirs/usr/ports/lang/gcc6/work/gcc-6.3.0/libstdc++-v3/libsupc++/atexit_thread.cc:117: first defined here
collect2: error: ld returned 1 exit status

So now a I have a workaround for FreeBSD<11 + LLVM and I seem to need one for FreeBSD>=11 + GCC. Needless to say, static linking with LLVM already doesn't work at all, because the necessary openmp .a is not shipped.
It's starting to really get confusing :o

Anything I can do to help fix this?

Comment 1 Konstantin Belousov freebsd_committer 2017-01-02 16:16:34 UTC
This is a bug in gcc.  The libsupc++ configuration assumes that there are exactly two possibilities: either libc is glibc and implements __cxa_thread_atexit() using __cxa_thread_atexit_impl(), or libsupc++ must provide an implementation on its own.  Right solution is to add detection of __cxa_thread_atexit() in libc, to libstdc++ configure.ac and libsupc++/atexit_thread.cc.

A workaround for you is might be use of --allow-multiple-definition switch to ld.  But what is not quite clear to me, is why libc  __cxa_thread_atexit was searched for at all, since static linker should be satisfied with the first definition it found.  Ensure that libstdc++.a appears strictly before libc.a on the linker invocation' command line.
Comment 2 Hannes Hauswedell 2017-01-02 16:40:35 UTC
(In reply to Konstantin Belousov from comment #1)

ok, I have opened an issue over at gcc:

Let's see what they say.

Concerning your proposed workaround: Since all the magic is done by cmake I have little influence on the order, although it does seem like it gets into libstdc++ first (see the "first defined here").

I have a different workaround in the code that I have also been using for FreeBSD<11 + LLVM and that I am now just expanding so that thread_local is just never used on FreeBSD right now.
Comment 3 Hannes Hauswedell 2017-01-03 14:21:50 UTC
Upstream would be willing to create a workaround, however they are irritated with FreeBSD's solution and the workaround would of course only affect some future releases and not fix the current situation. 
Upstream suggested there is a better way to solving the whole __cxa_thread_atexit thing and/or that LLVM already has a (different) solution. Are there chances this will be changed, should I re-open https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=192320 ?

Comment 4 Konstantin Belousov freebsd_committer 2017-01-03 17:03:41 UTC
Created attachment 178484 [details]
Provide __cxa_thread_atexit_impl(), split __cxa_thread_atexit() into separate .o.

This patch should help with gcc libstdc++ configured on stable/11 with __cxa_thread_atexit() already existing in libc. With the patch applied, gcc configure should detect __cxa_thread_atexit_impl() and generate only a wrapper cxa_thread_atexit() for libsupc++.

If gcc was configured on system where __cxa_thread_atexit(3) was not provided, but used on a system where it is, the patch does not make a difference.
Comment 5 Tavian Barnes 2017-01-03 17:53:43 UTC
Note that since https://reviews.llvm.org/D21803, upstream LLVM does basically the same thing as GCC.  That is, it checks for __cxa_thread_atexit_impl in the libc, calling it if available, and emulating it if not.  In either case, libc++abi unconditionally defines __cxa_thread_atexit.
Comment 6 commit-hook freebsd_committer 2017-01-07 16:06:13 UTC
A commit references this bug:

Author: kib
Date: Sat Jan  7 16:05:19 UTC 2017
New revision: 311651
URL: https://svnweb.freebsd.org/changeset/base/311651

  Export __cxa_thread_atexit_impl as an alias for __cxa_thread_atexit.

  libstdc++ before gcc r244057 expected that libc provided
  __cxa_thread_atexit_impl, and libstdc++ implemented
  __cxa_thread_atexit, by forwarding the calls to _impl.  Mentioned gcc
  revision checks for __cxa_thread_atexit in libc and does not provide
  the symbol from libstdc++ if found.

  This change helps older gcc, in particular, all released versions
  which implement thread_local, by consolidating the implementation into
  libc.  For that versions, if configured with the current libc, the
  __cxa_thread_atexit is exported from libstdc++ as a trivial wrapper
  around libc::__cxa_thread_atexit_impl.

  The __cxa_thread_atexit implementation is put into separate source
  file to allow for static linking with older libstdc++.a.

  gcc bugzilla:	https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78968
  Reported by:	Hannes Hauswedell <h2+fbsdports@fsfe.org>
  PR:	215709
  Sponsored by:	The FreeBSD Foundation
  MFC after:	2 weeks

Comment 7 Ed Maste freebsd_committer 2017-07-27 02:08:28 UTC
Is this still waiting on MFC?