clang generates globally visible symbols for TLS wrappers on Mac |
|||||||
Issue description
Here's a minimal test case:
$ cat test.cc
thread_local int tls_global = 42;
int& global() {
return tls_global;
}
$ clang -fPIC -shared -std=c++11 test.cc
$ nm | grep global
0000000000000f90 T __Z6globalv
0000000000000fa0 T __ZTW10tls_global # globally exported TLS wrapper
0000000000001000 s _tls_global
0000000000001018 s _tls_global$tlv$init
Setting visibility=hidden does not affect these symbols:
$ clang -fPIC -shared -std=c++11 test.cc -fvisibility=hidden
$ nm | grep global
0000000000000f90 t __Z6globalv
0000000000000fa0 T __ZTW10tls_global # visibility=hidden does not work here
0000000000001000 s _tls_global
0000000000001018 s _tls_global$tlv$init
,
Apr 4 2018
cc'ing a few folks in case they know something about this
,
Apr 5 2018
I don't know exactly what's going on here, but this seems to be the code for computing the wrapper's linkage, and it has a Darwin-specific thing:
static bool isThreadWrapperReplaceable(const VarDecl *VD,
CodeGen::CodeGenModule &CGM) {
assert(!VD->isStaticLocal() && "static local VarDecls don't need wrappers!");
// Darwin prefers to have references to thread local variables to go through
// the thread wrapper instead of directly referencing the backing variable.
return VD->getTLSKind() == VarDecl::TLS_Dynamic &&
CGM.getTarget().getTriple().isOSDarwin();
}
/// Get the appropriate linkage for the wrapper function. This is essentially
/// the weak form of the variable's linkage; every translation unit which needs
/// the wrapper emits a copy, and we want the linker to merge them.
static llvm::GlobalValue::LinkageTypes
getThreadLocalWrapperLinkage(const VarDecl *VD, CodeGen::CodeGenModule &CGM) {
llvm::GlobalValue::LinkageTypes VarLinkage =
CGM.getLLVMLinkageVarDefinition(VD, /*isConstant=*/false);
// For internal linkage variables, we don't need an external or weak wrapper.
if (llvm::GlobalValue::isLocalLinkage(VarLinkage))
return VarLinkage;
// If the thread wrapper is replaceable, give it appropriate linkage.
if (isThreadWrapperReplaceable(VD, CGM))
if (!llvm::GlobalVariable::isLinkOnceLinkage(VarLinkage) &&
!llvm::GlobalVariable::isWeakODRLinkage(VarLinkage))
return VarLinkage;
return llvm::GlobalValue::WeakODRLinkage;
}
(From lib/CodeGen/ItaniumCXXABI.cpp)
,
Apr 19 2018
Mac triage: marking Assigned.
,
Jan 15
lfg@ I'm interested in using thread_local in chromium as well and reached this bug. Could you explain why the symbol visibility is an issue? It seems like on Darwin the __ZTW* thread wrapper is used instead of the symbol to reference the TLS var and doing some simple tests on macOS using thread_local I wasn't able to hit a failure that explained this bug.
,
Jan 15
I pinged lfg@ over gchat and he gave me the following link for context https://groups.google.com/a/google.com/forum/#!msg/chrome-mac-dev/lXZB33SF5nk/ETnTT69lAQAJ I had mistakenly assumed that the issue had to do with cross-DSO symbol resolution in component builds instead of simply visible symbols in the final build. I'm looking at the original Darwin visibility changes in LLVM to try to understand the context of why they were added.
,
Jan 15
I've filed an LLVM bug https://bugs.llvm.org/show_bug.cgi?id=40327
,
Jan 17
(5 days ago)
,
Jan 17
(5 days ago)
It should be fixed upstream, just needs a clang roll.
,
Today
(17 hours ago)
The clang roll has landed. I've verified that the new clang on macOS correctly handles symbol visibility for the provided example. |
|||||||
►
Sign in to add a comment |
|||||||
Comment 1 by lfg@chromium.org
, Apr 4 2018I also tested on Linux, and it works correctly: $ cat test.cc thread_local int tls_global = 42; int& global() { return tls_global; } $ clang-3.9 -shared test.cc -std=c++11 -fPIC $ llvm-nm-3.9 |grep global 00000000000006d0 T _Z6globalv 00000000000006e0 t _ZTW10tls_global # locally exported wrapper 0000000000000680 t __do_global_dtors_aux 0000000000200de8 n __do_global_dtors_aux_fini_array_entry 0000000000000000 D tls_global