// A TLS symbol's virtual address is relative to the TLS segment. Add a
// target-specific adjustment to produce a thread-pointer-relative offset.
-static int64_t getTlsTpOffset() {
+static int64_t getTlsTpOffset(const Symbol &S) {
+ // On targets that support TLSDESC, _TLS_MODULE_BASE_@tpoff = 0.
+ if (&S == ElfSym::TlsModuleBase)
+ return 0;
+
switch (Config->EMachine) {
case EM_ARM:
case EM_AARCH64:
// Variant 1. The thread pointer points to a TCB with a fixed 2-word size,
// followed by a variable amount of alignment padding, followed by the TLS
// segment.
- return alignTo(Config->Wordsize * 2, Out::TlsPhdr->p_align);
+ return S.getVA(0) + alignTo(Config->Wordsize * 2, Out::TlsPhdr->p_align);
case EM_386:
case EM_X86_64:
// Variant 2. The TLS segment is located just before the thread pointer.
- return -alignTo(Out::TlsPhdr->p_memsz, Out::TlsPhdr->p_align);
+ return S.getVA(0) - alignTo(Out::TlsPhdr->p_memsz, Out::TlsPhdr->p_align);
case EM_PPC64:
// The thread pointer points to a fixed offset from the start of the
// executable's TLS segment. An offset of 0x7000 allows a signed 16-bit
// offset to reach 0x1000 of TCB/thread-library data and 0xf000 of the
// program's TLS segment.
- return -0x7000;
+ return S.getVA(0) - 0x7000;
default:
llvm_unreachable("unhandled Config->EMachine");
}
// loaders.
if (Sym.isUndefined())
return A;
- return Sym.getVA(A) + getTlsTpOffset();
+ return getTlsTpOffset(Sym) + A;
case R_RELAX_TLS_GD_TO_LE_NEG:
case R_NEG_TLS:
if (Sym.isUndefined())
return A;
- return -Sym.getVA(0) - getTlsTpOffset() + A;
+ return -getTlsTpOffset(Sym) + A;
case R_SIZE:
return Sym.getSize() + A;
case R_TLSDESC:
Defined *ElfSym::MipsLocalGp;
Defined *ElfSym::RelaIpltStart;
Defined *ElfSym::RelaIpltEnd;
+Defined *ElfSym::TlsModuleBase;
static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) {
switch (Sym.kind()) {
// __rel{,a}_iplt_{start,end} symbols.
static Defined *RelaIpltStart;
static Defined *RelaIpltEnd;
+
+ // _TLS_MODULE_BASE_ on targets that support TLSDESC.
+ static Defined *TlsModuleBase;
};
// A buffer class that is large enough to hold any Symbol-derived
if (!dyn_cast_or_null<Defined>(Symtab->find("__global_pointer$")))
addOptionalRegular("__global_pointer$", findSection(".sdata"), 0x800);
+ if (Config->EMachine == EM_X86_64) {
+ // On targets that support TLSDESC, _TLS_MODULE_BASE_ is defined in such a
+ // way that:
+ //
+ // 1) Without relaxation: it produces a dynamic TLSDESC relocation that
+ // computes 0.
+ // 2) With LD->LE relaxation: _TLS_MODULE_BASE_@tpoff = 0 (lowest address in
+ // the TLS block).
+ //
+ // 2) is special cased in @tpoff computation. To satisfy 1), we define it as
+ // an absolute symbol of zero. This is different from GNU linkers which
+ // define _TLS_MODULE_BASE_ relative to the first TLS section.
+ Symbol *S = Symtab->find("_TLS_MODULE_BASE_");
+ if (S && S->isUndefined()) {
+ S->resolve(Defined{/*File=*/nullptr, S->getName(), STB_GLOBAL, STV_HIDDEN,
+ STT_TLS, /*Value=*/0, 0,
+ /*Section=*/nullptr});
+ ElfSym::TlsModuleBase = cast<Defined>(S);
+ }
+ }
+
// This responsible for splitting up .eh_frame section into
// pieces. The relocation scan uses those pieces, so this has to be
// earlier.
--- /dev/null
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
+
+# RUN: ld.lld -shared %t.o -o %t.so
+# RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=LD-REL %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck --check-prefix=LD %s
+
+# RUN: ld.lld %t.o -o %t
+# RUN: llvm-readelf -r %t | FileCheck --check-prefix=NOREL %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=LE %s
+
+## Check _TLS_MODULE_BASE_ used by LD produces a dynamic relocation with a value of 0.
+# LD-REL: .rela.dyn {
+# LD-REL-NEXT: 0x20A0 R_X86_64_TLSDESC - 0x0
+# LD-REL-NEXT: }
+
+## 0x20a0-0x1007 = 4249
+## dtpoff(a) = 8, dtpoff(b) = 12
+# LD: leaq 4249(%rip), %rax
+# LD-NEXT: 1007: callq *(%rax)
+# LD-NEXT: movl %fs:8(%rax), %edx
+# LD-NEXT: addl %fs:12(%rax), %edx
+
+## When producing an executable, the LD code sequence can be relaxed to LE.
+## It is the same as GD->LE.
+## tpoff(_TLS_MODULE_BASE_) = 0, tpoff(a) = -8, tpoff(b) = -4
+
+# NOREL: no relocations
+
+# LE: movq $0, %rax
+# LE-NEXT: nop
+# LE-NEXT: movl %fs:-8(%rax), %edx
+# LE-NEXT: addl %fs:-4(%rax), %edx
+
+leaq _TLS_MODULE_BASE_@tlsdesc(%rip), %rax
+call *_TLS_MODULE_BASE_@tlscall(%rax)
+movl %fs:a@dtpoff(%rax), %edx
+addl %fs:b@dtpoff(%rax), %edx
+
+.section .tbss
+.zero 8
+a:
+.zero 4
+b:
+.zero 4