Index: ELF/Arch/AArch64.cpp =================================================================== --- ELF/Arch/AArch64.cpp +++ ELF/Arch/AArch64.cpp @@ -75,7 +75,7 @@ // 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. TlsLayout = TlsLayoutKind::FixedTcbSize; - TcbSize = 16; + TcbSize = Config->AndroidTlsTcb ? *Config->AndroidTlsTcb : 16; NeedsThunks = true; } Index: ELF/Arch/ARM.cpp =================================================================== --- ELF/Arch/ARM.cpp +++ ELF/Arch/ARM.cpp @@ -64,7 +64,7 @@ TrapInstr = 0xd4d4d4d4; // ARM uses Variant 1 TLS TlsLayout = TlsLayoutKind::FixedTcbSize; - TcbSize = 8; + TcbSize = Config->AndroidTlsTcb ? *Config->AndroidTlsTcb : 8; NeedsThunks = true; } Index: ELF/Arch/X86.cpp =================================================================== --- ELF/Arch/X86.cpp +++ ELF/Arch/X86.cpp @@ -61,7 +61,11 @@ PltHeaderSize = 16; TlsGdRelaxSkip = 2; TrapInstr = 0xcccccccc; // 0xcc = INT3 - TlsLayout = TlsLayoutKind::Variant2; + if (Config->AndroidTlsTcb) { + TlsLayout = TlsLayoutKind::FixedTcbSize; + TcbSize = *Config->AndroidTlsTcb; + } else + TlsLayout = TlsLayoutKind::Variant2; // Align to the non-PAE large page size (known as a superpage or huge page). // FreeBSD automatically promotes large, superpage-aligned allocations. Index: ELF/Arch/X86_64.cpp =================================================================== --- ELF/Arch/X86_64.cpp +++ ELF/Arch/X86_64.cpp @@ -68,7 +68,11 @@ PltHeaderSize = 16; TlsGdRelaxSkip = 2; TrapInstr = 0xcccccccc; // 0xcc = INT3 - TlsLayout = TlsLayoutKind::Variant2; + if (Config->AndroidTlsTcb) { + TlsLayout = TlsLayoutKind::FixedTcbSize; + TcbSize = *Config->AndroidTlsTcb; + } else + TlsLayout = TlsLayoutKind::Variant2; // Align to the large page size (known as a superpage or huge page). // FreeBSD automatically promotes large, superpage-aligned allocations. Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -121,6 +121,7 @@ CallGraphProfile; bool AllowMultipleDefinition; bool AndroidPackDynRelocs; + llvm::Optional AndroidTlsTcb; bool ARMHasBlx = false; bool ARMHasMovtMovw = false; bool ARMJ1J2BranchEncoding = false; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -451,6 +451,12 @@ } } +static llvm::Optional getAndroidTlsTcb(opt::InputArgList &Args) { + if (!Args.hasFlag(OPT_android_tls_tcb, OPT_no_android_tls, false)) + return None; + return args::getInteger(Args, OPT_android_tls_tcb, 0); +} + static std::string getRpath(opt::InputArgList &Args) { std::vector V = args::getStrings(Args, OPT_rpath); return llvm::join(V.begin(), V.end(), ":"); @@ -759,6 +765,7 @@ Args.hasFlag(OPT_allow_multiple_definition, OPT_no_allow_multiple_definition, false) || hasZOption(Args, "muldefs"); + Config->AndroidTlsTcb = getAndroidTlsTcb(Args); Config->AuxiliaryList = args::getStrings(Args, OPT_auxiliary); Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic); Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions); Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -63,6 +63,9 @@ "Allow multiple definitions", "Do not allow multiple definitions (default)">; +defm android_tls_tcb: Eq<"android-tls-tcb", + "Set the TLS TCB size and emit PT_ANDROID_TLS_TPOFF">, MetaVarName<"">; + defm apply_dynamic_relocs: B<"apply-dynamic-relocs", "Apply link-time values for dynamic relocations", "Do not apply link-time values for dynamic relocations (default)">; @@ -217,6 +220,9 @@ def nostdlib: F<"nostdlib">, HelpText<"Only search directories specified on the command line">; +def no_android_tls: F<"no-android-tls">, + HelpText<"Use the ordinary TLS layout for the target (default)">; + def no_color_diagnostics: F<"no-color-diagnostics">, HelpText<"Do not use colors in diagnostics">; Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1915,9 +1915,16 @@ for (OutputSection *Sec : OutputSections) if (Sec->Flags & SHF_TLS) TlsHdr->add(Sec); - if (TlsHdr->FirstSec) + if (TlsHdr->FirstSec) { Ret.push_back(TlsHdr); + // Create a PT_ANDROID_TLS_TPOFF segment to record the TP-to-TLS offset + // used to resolve an executable's TLS LE relocations. The Bionic linker + // uses this segment to verify that a binary was linked correctly. + if (Config->AndroidTlsTcb && !Config->Shared) + AddHdr(PT_ANDROID_TLS_TPOFF, 0); + } + // Add an entry for .dynamic. if (In.DynSymTab) AddHdr(PT_DYNAMIC, In.Dynamic->getParent()->getPhdrFlags()) @@ -2170,6 +2177,14 @@ if (P->p_type == PT_TLS && P->p_memsz) P->p_memsz = alignTo(P->p_memsz, P->p_align); } + + // Initialize PT_ANDROID_TLS_TPOFF in a second pass because, while Android + // uses a variant 1 layout, TLS offsets can't generally be calculated until + // the PT_TLS segment's p_memsz field is finalized. + for (PhdrEntry *P : Phdrs) { + if (P->p_type == PT_ANDROID_TLS_TPOFF) + P->p_vaddr = getTlsTpOffset(); + } } // A helper struct for checkSectionOverlap. Index: test/ELF/aarch64-android-tls-tcb.s =================================================================== --- /dev/null +++ test/ELF/aarch64-android-tls-tcb.s @@ -0,0 +1,30 @@ +# REQUIRES: aarch64 +# RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-android %s -o %tmain.o +# RUN: ld.lld --android-tls-tcb=17185 %tmain.o -o %tout +# RUN: llvm-objdump -d %tout | FileCheck %s +# RUN: llvm-readelf -l %tout | FileCheck -check-prefix=PHDR %s + +# The TLS segment starts at 17185 aligned by 16 (0x4321 rounded to 0x4330). + +#CHECK: Disassembly of section .text: +#CHECK: _start: +#CHECK: 210000: 40 d0 3b d5 mrs x0, TPIDR_EL0 +#CHECK: 210004: 00 10 40 91 add x0, x0, #4, lsl #12 +#CHECK: 210008: 00 c0 0c 91 add x0, x0, #816 + +#PHDR: TLS {{.*}} 0x000000 0x000010 R 0x10 +#PHDR-NEXT: ANDROID_TLS_TPOFF 0x000000 0x0000000000004330 0x0000000000000000 0x000000 0x000000 0x0 + + .globl _start +_start: + mrs x0, TPIDR_EL0 + add x0, x0, :tprel_hi12:v1 + add x0, x0, :tprel_lo12_nc:v1 + + .section .tbss,"awT",@nobits + .type v1,@object + .globl v1 + .p2align 4 +v1: + .space 16 + .size v1, 16