forked from OSchip/llvm-project
[ELF] Refactor per-target TLS layout configuration. NFC.
Summary: There are really three different kinds of TLS layouts: * A fixed TLS-to-TP offset. On architectures like PowerPC, MIPS, and RISC-V, the thread pointer points to a fixed offset from the start of the executable's TLS segment. The offset is 0x7000 for PowerPC and MIPS, which allows a signed 16-bit offset to reach 0x1000 of per-thread implementation data and 0xf000 of the application's TLS segment. The size and layout of the TCB isn't relevant to the static linker and might not be known. * A fixed TCB size. This is the format documented as "variant 1" in Ulrich Drepper's TLS spec. The thread pointer points to a 2-word TCB followed by the executable's TLS segment. The first word is always the DTV pointer. Used on ARM. The thread pointer must be aligned to the TLS segment's alignment, possibly creating alignment padding. * Variant 2. This format predates variant 1 and is also documented in Drepper's TLS spec. It allocates the executable's TLS segment before the thread pointer, apparently for backwards-compatibility. It's used on x86 and SPARC. Factor out an lld:🧝:getTlsTpOffset() function for use in a follow-up patch for Android. The TcbSize/TlsTpOffset fields are only used in getTlsTpOffset, so replace them with a switch on Config->EMachine. Reviewers: espindola, ruiu, PkmX, jrtc27 Reviewed By: ruiu, PkmX, jrtc27 Subscribers: jyknight, emaste, sdardis, nemanjai, javed.absar, arichardson, kristof.beyls, kbarton, fedor.sergeev, atanasyan, PkmX, jsji, llvm-commits Differential Revision: https://reviews.llvm.org/D53905 llvm-svn: 345775
This commit is contained in:
parent
3ad0636e0a
commit
e7cb0225a0
|
@ -72,9 +72,6 @@ AArch64::AArch64() {
|
||||||
// FreeBSD automatically promotes 2 MiB-aligned allocations.
|
// FreeBSD automatically promotes 2 MiB-aligned allocations.
|
||||||
DefaultImageBase = 0x200000;
|
DefaultImageBase = 0x200000;
|
||||||
|
|
||||||
// It doesn't seem to be documented anywhere, but tls on aarch64 uses variant
|
|
||||||
// 1 of the tls structures and the tcb size is 16.
|
|
||||||
TcbSize = 16;
|
|
||||||
NeedsThunks = true;
|
NeedsThunks = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,8 +62,6 @@ ARM::ARM() {
|
||||||
PltEntrySize = 16;
|
PltEntrySize = 16;
|
||||||
PltHeaderSize = 32;
|
PltHeaderSize = 32;
|
||||||
TrapInstr = 0xd4d4d4d4;
|
TrapInstr = 0xd4d4d4d4;
|
||||||
// ARM uses Variant 1 TLS
|
|
||||||
TcbSize = 8;
|
|
||||||
NeedsThunks = true;
|
NeedsThunks = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -207,8 +207,6 @@ PPC64::PPC64() {
|
||||||
GotPltHeaderEntriesNum = 2;
|
GotPltHeaderEntriesNum = 2;
|
||||||
PltHeaderSize = 60;
|
PltHeaderSize = 60;
|
||||||
NeedsThunks = true;
|
NeedsThunks = true;
|
||||||
TcbSize = 8;
|
|
||||||
TlsTpOffset = 0x7000;
|
|
||||||
|
|
||||||
TlsModuleIndexRel = R_PPC64_DTPMOD64;
|
TlsModuleIndexRel = R_PPC64_DTPMOD64;
|
||||||
TlsOffsetRel = R_PPC64_DTPREL64;
|
TlsOffsetRel = R_PPC64_DTPREL64;
|
||||||
|
|
|
@ -566,6 +566,31 @@ Relocation *lld::elf::getRISCVPCRelHi20(const Symbol *Sym, uint64_t Addend) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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() {
|
||||||
|
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);
|
||||||
|
case EM_386:
|
||||||
|
case EM_X86_64:
|
||||||
|
// Variant 2. The TLS segment is located just before the thread pointer.
|
||||||
|
return -Out::TlsPhdr->p_memsz;
|
||||||
|
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;
|
||||||
|
default:
|
||||||
|
llvm_unreachable("unhandled Config->EMachine");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
|
static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
|
||||||
uint64_t P, const Symbol &Sym, RelExpr Expr) {
|
uint64_t P, const Symbol &Sym, RelExpr Expr) {
|
||||||
switch (Expr) {
|
switch (Expr) {
|
||||||
|
@ -711,24 +736,7 @@ static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
|
||||||
// statically to zero.
|
// statically to zero.
|
||||||
if (Sym.isTls() && Sym.isUndefWeak())
|
if (Sym.isTls() && Sym.isUndefWeak())
|
||||||
return 0;
|
return 0;
|
||||||
|
return Sym.getVA(A) + getTlsTpOffset();
|
||||||
// For TLS variant 1 the TCB is a fixed size, whereas for TLS variant 2 the
|
|
||||||
// TCB is on unspecified size and content. Targets that implement variant 1
|
|
||||||
// should set TcbSize.
|
|
||||||
if (Target->TcbSize) {
|
|
||||||
// PPC64 V2 ABI has the thread pointer offset into the middle of the TLS
|
|
||||||
// storage area by TlsTpOffset for efficient addressing TCB and up to
|
|
||||||
// 4KB – 8 B of other thread library information (placed before the TCB).
|
|
||||||
// Subtracting this offset will get the address of the first TLS block.
|
|
||||||
if (Target->TlsTpOffset)
|
|
||||||
return Sym.getVA(A) - Target->TlsTpOffset;
|
|
||||||
|
|
||||||
// If thread pointer is not offset into the middle, the first thing in the
|
|
||||||
// TLS storage area is the TCB. Add the TcbSize to get the address of the
|
|
||||||
// first TLS block.
|
|
||||||
return Sym.getVA(A) + alignTo(Target->TcbSize, Out::TlsPhdr->p_align);
|
|
||||||
}
|
|
||||||
return Sym.getVA(A) - Out::TlsPhdr->p_memsz;
|
|
||||||
case R_RELAX_TLS_GD_TO_LE_NEG:
|
case R_RELAX_TLS_GD_TO_LE_NEG:
|
||||||
case R_NEG_TLS:
|
case R_NEG_TLS:
|
||||||
return Out::TlsPhdr->p_memsz - Sym.getVA(A);
|
return Out::TlsPhdr->p_memsz - Sym.getVA(A);
|
||||||
|
|
|
@ -117,15 +117,6 @@ public:
|
||||||
// On PPC ELF V2 abi, the first entry in the .got is the .TOC.
|
// On PPC ELF V2 abi, the first entry in the .got is the .TOC.
|
||||||
unsigned GotHeaderEntriesNum = 0;
|
unsigned GotHeaderEntriesNum = 0;
|
||||||
|
|
||||||
// For TLS variant 1, the TCB is a fixed size specified by the Target.
|
|
||||||
// For variant 2, the TCB is an unspecified size.
|
|
||||||
// Set to 0 for variant 2.
|
|
||||||
unsigned TcbSize = 0;
|
|
||||||
|
|
||||||
// Set to the offset (in bytes) that the thread pointer is initialized to
|
|
||||||
// point to, relative to the start of the thread local storage.
|
|
||||||
unsigned TlsTpOffset = 0;
|
|
||||||
|
|
||||||
bool NeedsThunks = false;
|
bool NeedsThunks = false;
|
||||||
|
|
||||||
// A 4-byte field corresponding to one or more trap instructions, used to pad
|
// A 4-byte field corresponding to one or more trap instructions, used to pad
|
||||||
|
|
Loading…
Reference in New Issue