forked from OSchip/llvm-project
[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_@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 llvm-svn: 362078
This commit is contained in:
parent
3475a46ec2
commit
0526c0cd8e
|
@ -584,24 +584,28 @@ static Relocation *getRISCVPCRelHi20(const Symbol *Sym, uint64_t Addend) {
|
||||||
|
|
||||||
// A TLS symbol's virtual address is relative to the TLS segment. Add a
|
// A TLS symbol's virtual address is relative to the TLS segment. Add a
|
||||||
// target-specific adjustment to produce a thread-pointer-relative offset.
|
// 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) {
|
switch (Config->EMachine) {
|
||||||
case EM_ARM:
|
case EM_ARM:
|
||||||
case EM_AARCH64:
|
case EM_AARCH64:
|
||||||
// Variant 1. The thread pointer points to a TCB with a fixed 2-word size,
|
// 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
|
// followed by a variable amount of alignment padding, followed by the TLS
|
||||||
// segment.
|
// 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_386:
|
||||||
case EM_X86_64:
|
case EM_X86_64:
|
||||||
// Variant 2. The TLS segment is located just before the thread pointer.
|
// 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:
|
case EM_PPC64:
|
||||||
// The thread pointer points to a fixed offset from the start of the
|
// 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
|
// 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
|
// offset to reach 0x1000 of TCB/thread-library data and 0xf000 of the
|
||||||
// program's TLS segment.
|
// program's TLS segment.
|
||||||
return -0x7000;
|
return S.getVA(0) - 0x7000;
|
||||||
default:
|
default:
|
||||||
llvm_unreachable("unhandled Config->EMachine");
|
llvm_unreachable("unhandled Config->EMachine");
|
||||||
}
|
}
|
||||||
|
@ -745,12 +749,12 @@ static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
|
||||||
// loaders.
|
// loaders.
|
||||||
if (Sym.isUndefined())
|
if (Sym.isUndefined())
|
||||||
return A;
|
return A;
|
||||||
return Sym.getVA(A) + getTlsTpOffset();
|
return getTlsTpOffset(Sym) + A;
|
||||||
case R_RELAX_TLS_GD_TO_LE_NEG:
|
case R_RELAX_TLS_GD_TO_LE_NEG:
|
||||||
case R_NEG_TLS:
|
case R_NEG_TLS:
|
||||||
if (Sym.isUndefined())
|
if (Sym.isUndefined())
|
||||||
return A;
|
return A;
|
||||||
return -Sym.getVA(0) - getTlsTpOffset() + A;
|
return -getTlsTpOffset(Sym) + A;
|
||||||
case R_SIZE:
|
case R_SIZE:
|
||||||
return Sym.getSize() + A;
|
return Sym.getSize() + A;
|
||||||
case R_TLSDESC:
|
case R_TLSDESC:
|
||||||
|
|
|
@ -39,6 +39,7 @@ Defined *ElfSym::MipsGpDisp;
|
||||||
Defined *ElfSym::MipsLocalGp;
|
Defined *ElfSym::MipsLocalGp;
|
||||||
Defined *ElfSym::RelaIpltStart;
|
Defined *ElfSym::RelaIpltStart;
|
||||||
Defined *ElfSym::RelaIpltEnd;
|
Defined *ElfSym::RelaIpltEnd;
|
||||||
|
Defined *ElfSym::TlsModuleBase;
|
||||||
|
|
||||||
static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) {
|
static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) {
|
||||||
switch (Sym.kind()) {
|
switch (Sym.kind()) {
|
||||||
|
|
|
@ -436,6 +436,9 @@ struct ElfSym {
|
||||||
// __rel{,a}_iplt_{start,end} symbols.
|
// __rel{,a}_iplt_{start,end} symbols.
|
||||||
static Defined *RelaIpltStart;
|
static Defined *RelaIpltStart;
|
||||||
static Defined *RelaIpltEnd;
|
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
|
// A buffer class that is large enough to hold any Symbol-derived
|
||||||
|
|
|
@ -1606,6 +1606,27 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
|
||||||
if (!dyn_cast_or_null<Defined>(Symtab->find("__global_pointer$")))
|
if (!dyn_cast_or_null<Defined>(Symtab->find("__global_pointer$")))
|
||||||
addOptionalRegular("__global_pointer$", findSection(".sdata"), 0x800);
|
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
|
// This responsible for splitting up .eh_frame section into
|
||||||
// pieces. The relocation scan uses those pieces, so this has to be
|
// pieces. The relocation scan uses those pieces, so this has to be
|
||||||
// earlier.
|
// earlier.
|
||||||
|
|
|
@ -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_@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
|
Loading…
Reference in New Issue