[lld] r362078 - [ELF] Implement Local Dynamic style TLSDESC for x86-64
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Thu May 30 03:00:20 PDT 2019
Author: maskray
Date: Thu May 30 03:00:20 2019
New Revision: 362078
URL: http://llvm.org/viewvc/llvm-project?rev=362078&view=rev
Log:
[ELF] Implement Local Dynamic style TLSDESC for x86-64
For the Local Dynamic case of TLSDESC, _TLS_MODULE_BASE_ is defined as a
special TLS symbol that makes:
1) Without relaxation: it produces a dynamic TLSDESC relocation that
computes 0. Adding @dtpoff to access a TLS symbol.
2) With LD->LE relaxation: _TLS_MODULE_BASE_ at tpoff = 0 (lowest address in
the TLS block). Adding @tpoff to access a TLS symbol.
For 1), this saves dynamic relocations and GOT slots as otherwise
(General Dynamic) we would create an R_X86_64_TLSDESC and reserve two
GOT slots for each symbol.
Add ElfSym::TlsModuleBase and change the signature of getTlsTpOffset()
to special case _TLS_MODULE_BASE_.
Reviewed By: ruiu
Differential Revision: https://reviews.llvm.org/D62577
Added:
lld/trunk/test/ELF/x86-64-tlsdesc-ld.s
Modified:
lld/trunk/ELF/InputSection.cpp
lld/trunk/ELF/Symbols.cpp
lld/trunk/ELF/Symbols.h
lld/trunk/ELF/Writer.cpp
Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=362078&r1=362077&r2=362078&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Thu May 30 03:00:20 2019
@@ -584,24 +584,28 @@ static Relocation *getRISCVPCRelHi20(con
// 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_ at 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");
}
@@ -745,12 +749,12 @@ static uint64_t getRelocTargetVA(const I
// 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:
Modified: lld/trunk/ELF/Symbols.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.cpp?rev=362078&r1=362077&r2=362078&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.cpp (original)
+++ lld/trunk/ELF/Symbols.cpp Thu May 30 03:00:20 2019
@@ -39,6 +39,7 @@ Defined *ElfSym::MipsGpDisp;
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()) {
Modified: lld/trunk/ELF/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.h?rev=362078&r1=362077&r2=362078&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.h (original)
+++ lld/trunk/ELF/Symbols.h Thu May 30 03:00:20 2019
@@ -436,6 +436,9 @@ struct ElfSym {
// __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
Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=362078&r1=362077&r2=362078&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Thu May 30 03:00:20 2019
@@ -1606,6 +1606,27 @@ template <class ELFT> void Writer<ELFT>:
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_ at 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.
Added: lld/trunk/test/ELF/x86-64-tlsdesc-ld.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/x86-64-tlsdesc-ld.s?rev=362078&view=auto
==============================================================================
--- lld/trunk/test/ELF/x86-64-tlsdesc-ld.s (added)
+++ lld/trunk/test/ELF/x86-64-tlsdesc-ld.s Thu May 30 03:00:20 2019
@@ -0,0 +1,45 @@
+# 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_ at tlsdesc(%rip), %rax
+call *_TLS_MODULE_BASE_ at tlscall(%rax)
+movl %fs:a at dtpoff(%rax), %edx
+addl %fs:b at dtpoff(%rax), %edx
+
+.section .tbss
+.zero 8
+a:
+.zero 4
+b:
+.zero 4
More information about the llvm-commits
mailing list