[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:
Ryan Prichard 2018-10-31 20:53:17 +00:00
parent 3ad0636e0a
commit e7cb0225a0
5 changed files with 26 additions and 34 deletions

View File

@ -72,9 +72,6 @@ AArch64::AArch64() {
// FreeBSD automatically promotes 2 MiB-aligned allocations.
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;
}

View File

@ -62,8 +62,6 @@ ARM::ARM() {
PltEntrySize = 16;
PltHeaderSize = 32;
TrapInstr = 0xd4d4d4d4;
// ARM uses Variant 1 TLS
TcbSize = 8;
NeedsThunks = true;
}

View File

@ -207,8 +207,6 @@ PPC64::PPC64() {
GotPltHeaderEntriesNum = 2;
PltHeaderSize = 60;
NeedsThunks = true;
TcbSize = 8;
TlsTpOffset = 0x7000;
TlsModuleIndexRel = R_PPC64_DTPMOD64;
TlsOffsetRel = R_PPC64_DTPREL64;

View File

@ -566,6 +566,31 @@ Relocation *lld::elf::getRISCVPCRelHi20(const Symbol *Sym, uint64_t Addend) {
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,
uint64_t P, const Symbol &Sym, RelExpr Expr) {
switch (Expr) {
@ -711,24 +736,7 @@ static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
// statically to zero.
if (Sym.isTls() && Sym.isUndefWeak())
return 0;
// 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;
return Sym.getVA(A) + getTlsTpOffset();
case R_RELAX_TLS_GD_TO_LE_NEG:
case R_NEG_TLS:
return Out::TlsPhdr->p_memsz - Sym.getVA(A);

View File

@ -117,15 +117,6 @@ public:
// On PPC ELF V2 abi, the first entry in the .got is the .TOC.
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;
// A 4-byte field corresponding to one or more trap instructions, used to pad