Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions lib/Target/X86/x86_64Relocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,9 +274,17 @@ void x86_64Relocator::scanLocalReloc(InputFile &pInputFile, Relocation &pReloc,
std::lock_guard<std::mutex> relocGuard(m_RelocMutex);
if (rsym->reserved() & ReserveGOT)
return;
// Create a TLS IE GOT entry.
x86_64GOT *G = m_Target.createGOT(GOT::TLS_IE, Obj, rsym);
G->setValueType(GOT::TLSStaticSymbolValue);
// For executables, the symbol's offset from the thread pointer is fixed at
// link time. For shared objects, the dynamic loader must compute the offset
// at load time, so emit R_X86_64_TPOFF64.
if (config().isBuildingExecutable()) {
G->setValueType(GOT::TLSStaticSymbolValue);
} else {
helper_DynRel_init(Obj, &pReloc, rsym, G, 0x0,
llvm::ELF::R_X86_64_TPOFF64, m_Target);
m_Target.setHasStaticTLS();
}
rsym->setReserved(rsym->reserved() | ReserveGOT);
return;
}
Expand Down Expand Up @@ -408,13 +416,14 @@ void x86_64Relocator::scanGlobalReloc(InputFile &pInputFile, Relocation &pReloc,
if (rsym->reserved() & ReserveGOT)
return;
x86_64GOT *G = m_Target.createGOT(GOT::TLS_IE, Obj, rsym);
const bool isExec = (config().codeGenType() == LinkerConfig::Exec);
const bool isExec = config().isBuildingExecutable();
const bool preemptible = m_Target.isSymbolPreemptible(*rsym);
if (isExec && !preemptible) {
G->setValueType(GOT::TLSStaticSymbolValue);
} else {
helper_DynRel_init(Obj, &pReloc, rsym, G, 0x0,
llvm::ELF::R_X86_64_TPOFF64, m_Target);
m_Target.setHasStaticTLS();
}
rsym->setReserved(rsym->reserved() | ReserveGOT);
return;
Expand Down
19 changes: 19 additions & 0 deletions test/x86_64/linux/TLSIEHiddenGlobal/TLSIEHiddenGlobal.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/// Verifies the global-symbol path of R_X86_64_GOTTPOFF for a non-preemptible
/// TLS variable. In -pie the symbol's TP offset is fixed at link time,
/// so no R_X86_64_TPOFF64 should be emitted. In -shared the
/// dynamic loader resolves the offset at load time, so the dyn reloc and
/// DF_STATIC_TLS are both required.

// RUN: %clang %clangopts -c -x c %s -fPIC -ftls-model=initial-exec -o %t.o
// RUN: %link %linkopts -shared %t.o -o %t.shared.so
// RUN: %readelf -r -d %t.shared.so | %filecheck %s --check-prefix=SHARED
// RUN: %link %linkopts -pie %t.o -o %t.pie --defsym __libc_start_main=0
// RUN: %readelf -r %t.pie | %filecheck %s --check-prefix=PIE

// SHARED: STATIC_TLS
// SHARED: R_X86_64_TPOFF64

// PIE-NOT: R_X86_64_TPOFF64

__attribute__((visibility("hidden"))) __thread int g = 20;
int bar(void) { return g; }
21 changes: 21 additions & 0 deletions test/x86_64/linux/TLSIELocalSymbol/TLSIELocalSymbol.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/// Verifies that R_X86_64_GOTTPOFF against a file-local TLS symbol emits a
/// R_X86_64_TPOFF64 dynamic relocation in -shared output, and is statically
/// resolved into the GOT slot in -pie.

// RUN: %clang %clangopts -c -x c %s -fPIC -ftls-model=initial-exec -o %t.o
// RUN: %link %linkopts -shared %t.o -o %t.shared.so
// RUN: %readelf -r -x .got -d %t.shared.so | %filecheck %s --check-prefix=SHARED
// RUN: %link %linkopts -pie %t.o -o %t.pie --defsym __libc_start_main=0
// RUN: %readelf -r -x .got %t.pie | %filecheck %s --check-prefix=PIE

// SHARED: STATIC_TLS
// SHARED: R_X86_64_TPOFF64
// SHARED-LABEL: Hex dump of section '.got':
// SHARED-NEXT: 0x{{[0-9a-f]+}} 00000000 00000000

// PIE-NOT: R_X86_64_TPOFF64
// PIE-LABEL: Hex dump of section '.got':
// PIE-NEXT: 0x{{[0-9a-f]+}} fcffffff ffffffff

static __thread int a = 10;
int foo(void) { return a; }
Loading