Bug 59364 - thread_local link error
Summary: thread_local link error
Status: RESOLVED DUPLICATE of bug 55800
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.8.2
: P3 major
Target Milestone: ---
Assignee: Not yet assigned to anyone
Depends on:
Blocks: 59994
  Show dependency treegraph
Reported: 2013-12-02 02:30 UTC by Conrad S
Modified: 2014-01-31 15:48 UTC (History)
9 users (show)

See Also:
Known to work: 4.9.0
Known to fail: 4.8.2
Last reconfirmed:

reduced test case (421 bytes, application/x-gzip)
2013-12-10 07:10 UTC, Conrad S

Note You need to log in before you can comment on or make changes to this bug.
Description Conrad S 2013-12-02 02:30:48 UTC
Short description:

Declaring a variable as extern thread_local in a C++11 program leads to "undefined reference to `TLS init function for ..." during linking.

Long description:

Consider three files: rng.hpp, a.cpp and b.cpp, listed below.
Compile using:
g++ a.cpp -c -o a.o -std=c++11
g++ b.cpp -c -o b.o -std=c++11
g++ a.o b.o -o prog -std=c++11

b.o: In function `TLS wrapper function for rng_instance':
b.cpp:(.text._ZTW12rng_instance[_ZTW12rng_instance]+0x5): undefined reference to `TLS init function for rng_instance'

Things only work if thread_local is removed.

gcc version 4.8.2 20131017 (Red Hat 4.8.2-1) on Fedora 19 (x86-64).


#include <random>

class rng {
  std::mt19937_64 engine;
  std::uniform_real_distribution<double> distr;
  double get_val() { return distr(engine); }


#include "rng.hpp"
thread_local rng rng_instance;


#include <iostream>
#include "rng.hpp"

extern thread_local rng rng_instance;

int main(int argc, char** argv)
  std::cout << "val: " << rng_instance.get_val() << std::endl;
  return 0;
Comment 1 Tom De Caluwé 2013-12-10 05:52:36 UTC
This seems to be a duplicate of bug #55800. The workaround mentioned in the comments fixes the problem.
Comment 2 Conrad S 2013-12-10 06:45:39 UTC
I wouldn't call the method presented in the comments to bug #55800 as a workaround.

"at least adding .globl  _ZTWN3xyz3blaE _ZTWN3xyz3blaE = __tls_init manually at the end of the assembly seems to make the code do what it is supposed to"

Editing the assembly is not a workaround -- it's a one off hack.
Comment 3 Conrad S 2013-12-10 07:06:01 UTC
Reduced test case.  Compile with:

g++ a.cpp -c -o a.o -std=c++11
g++ b.cpp -c -o b.o -std=c++11
g++ a.o b.o -o prog -std=c++11

file foo.hpp:

class foo
  inline  foo() {}
  inline ~foo() {}
  inline double bar() { return 123.456; }

file a.cpp:

#include "foo.hpp"
thread_local foo foo_instance;

file b.cpp:

#include "foo.hpp"
extern thread_local foo foo_instance;

int main(int argc, char** argv)
  double bar = foo_instance.bar();
  return 0;
Comment 4 Conrad S 2013-12-10 07:10:49 UTC
Created attachment 31406 [details]
reduced test case

Attached reduced_test_case.tar.gz

No need for pre-processed input, as it doesn't include any system headers.
Comment 5 Richard Biener 2014-01-30 15:20:21 UTC
Works in 4.9.
Comment 6 Conrad S 2014-01-30 15:34:58 UTC
Any chance of a backport of this fix to gcc 4.8.3 ?
Comment 7 Jakub Jelinek 2014-01-30 15:46:34 UTC
I thought I've commented on this, perhaps in other PR, but can't find it right now.  The link error disappeared with r199577, which certainly doesn't seem to be backportable nor a change with the intent to fix this, and furthermore, I'd say that for such a trivial (sure, not in C++ terminology) ctor we'd better not to require dynamic initialization of the TLS var.
Comment 8 Jason Merrill 2014-01-31 15:48:25 UTC
Duplicate, yes.

*** This bug has been marked as a duplicate of bug 55800 ***