Index: ELF/Relocations.cpp =================================================================== --- ELF/Relocations.cpp +++ ELF/Relocations.cpp @@ -102,42 +102,28 @@ return Body.isPreemptible(); } -// This function is similar to the `handleTlsRelocation`. ARM and MIPS do not -// support any relaxations for TLS relocations so by factoring out ARM and MIPS +// This function is similar to the `handleTlsRelocation`. MIPS does not +// support any relaxations for TLS relocations so by factoring out MIPS // handling in to the separate function we can simplify the code and do not -// pollute `handleTlsRelocation` by ARM and MIPS `ifs` statements. -template -static unsigned handleNoRelaxTlsRelocation(GOT *Got, uint32_t Type, - SymbolBody &Body, - InputSectionBase &C, uint64_t Offset, - int64_t Addend, RelExpr Expr) { - auto addModuleReloc = [&](uint64_t Off, bool LD) { - // The Dynamic TLS Module Index Relocation can be statically resolved to 1 - // if we know that we are linking an executable. For ARM we resolve the - // relocation when writing the Got. MIPS has a custom Got implementation - // that writes the Module index in directly. - if (!Body.isPreemptible() && !Config->Pic && Config->EMachine == EM_ARM) - Got->Relocations.push_back( - {R_ABS, Target->TlsModuleIndexRel, Off, 0, &Body}); - else { - SymbolBody *Dest = LD ? nullptr : &Body; - In::RelaDyn->addReloc( - {Target->TlsModuleIndexRel, Got, Off, false, Dest, 0}); - } - }; - +// pollute other `handleTlsRelocation` by MIPS `ifs` statements. +template +static unsigned handleMipsTlsRelocation(MipsGotSection *Got, uint32_t Type, + SymbolBody &Body, InputSectionBase &C, + uint64_t Offset, int64_t Addend, + RelExpr Expr) { if (isRelExprOneOf(Expr)) { - if (Got->addTlsIndex() && (Config->Pic || Config->EMachine == EM_ARM)) - addModuleReloc(Got->getTlsIndexOff(), true); + if (Got->addTlsIndex() && Config->Pic) + In::RelaDyn->addReloc({Target->TlsModuleIndexRel, Got, + Got->getTlsIndexOff(), false, nullptr, 0}); C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); return 1; } if (Target->isTlsGlobalDynamicRel(Type)) { - if (Got->addDynTlsEntry(Body) && - (Body.isPreemptible() || Config->EMachine == EM_ARM)) { + if (Got->addDynTlsEntry(Body) && Body.isPreemptible()) { uint64_t Off = Got->getGlobalDynOffset(Body); - addModuleReloc(Off, false); + In::RelaDyn->addReloc( + {Target->TlsModuleIndexRel, Got, Off, false, &Body, 0}); if (Body.isPreemptible()) In::RelaDyn->addReloc({Target->TlsOffsetRel, Got, Off + Config->Wordsize, false, &Body, 0}); @@ -145,7 +131,52 @@ C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); return 1; } + return 0; +} + +// This function is similar to the `handleTlsRelocation`. ARM does not +// support any relaxations for TLS relocations so by factoring out ARM +// handling in to the separate function we can simplify the code and do not +// pollute other `handleTlsRelocation` by MIPS `ifs` statements. +// ARM is logically similar to MIPS but differs enough in the details to make +// a combination of the two functions difficult to understand. +template +static unsigned handleARMTlsRelocation(GotSection *Got, uint32_t Type, + SymbolBody &Body, InputSectionBase &C, + uint64_t Offset, int64_t Addend, + RelExpr Expr) { + // The Dynamic TLS Module Index Relocation for a symbol defined in an + // executable is always 1. If the target Symbol is not preemtible then + // we know the offset into the TLS block at static link time. + bool NeedDynId = Body.isPreemptible() || Config->Pic; + bool NeedDynOff = Body.isPreemptible(); + + auto AddTlsReloc = [&](uint64_t Off, uint32_t Type, SymbolBody *Dest, + bool Dyn) { + if (Dyn) + In::RelaDyn->addReloc({Type, Got, Off, false, Dest, 0}); + else + Got->Relocations.push_back({R_ABS, Type, Off, 0, Dest}); + }; + + if (Expr == R_TLSLD_PC) { + if (Got->addTlsIndex()) + AddTlsReloc(Got->getTlsIndexOff(), Target->TlsModuleIndexRel, + NeedDynId ? nullptr : &Body, NeedDynId); + C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); + return 1; + } + if (Target->isTlsGlobalDynamicRel(Type)) { + if (Got->addDynTlsEntry(Body)) { + uint64_t Off = Got->getGlobalDynOffset(Body); + AddTlsReloc(Off, Target->TlsModuleIndexRel, &Body, NeedDynId); + AddTlsReloc(Off + Config->Wordsize, Target->TlsOffsetRel, &Body, + NeedDynOff); + } + C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); + return 1; + } return 0; } @@ -161,11 +192,11 @@ return 0; if (Config->EMachine == EM_ARM) - return handleNoRelaxTlsRelocation(In::Got, Type, Body, C, - Offset, Addend, Expr); + return handleARMTlsRelocation(In::Got, Type, Body, C, Offset, + Addend, Expr); if (Config->EMachine == EM_MIPS) - return handleNoRelaxTlsRelocation(In::MipsGot, Type, Body, C, - Offset, Addend, Expr); + return handleMipsTlsRelocation(In::MipsGot, Type, Body, C, + Offset, Addend, Expr); bool IsPreemptible = isPreemptible(Body, Type); if (isRelExprOneOf(Expr) && Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -1842,6 +1842,7 @@ case R_ARM_TLS_LDO32: case R_ARM_TLS_LE32: case R_ARM_TLS_TPOFF32: + case R_ARM_TLS_DTPOFF32: write32le(Loc, Val); break; case R_ARM_TLS_DTPMOD32: Index: arm-tls-gd-nonpreemptible.s =================================================================== --- /dev/null +++ arm-tls-gd-nonpreemptible.s @@ -0,0 +1,72 @@ +// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t +// RUN: ld.lld %t -o %t2 +// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi +// RUN: llvm-objdump -s %t2 | FileCheck %s +// RUN: ld.lld %t --shared -o %t3.so +// RUN: llvm-objdump -s %t3.so | FileCheck -check-prefix=CHECK-SHARED %s +// REQUIRES: arm + +// For an executable, we write the module index 1 and the offset into the TLS +// directly into the GOT. For a shared library we can only write the offset +// into the TLS directly if the symbol is non-preemptible + + .text + .syntax unified + .globl __tls_get_addr + .type __tls_get_addr,%function +__tls_get_addr: + bx lr + + .globl _start + .p2align 2 + .type _start,%function +func: +.L0: + nop +.L1: + nop +.L2: + nop +.L3: + nop + .p2align 2 +// Generate R_ARM_TLS_GD32 relocations +// These can be resolved at static link time for executables as 1 is always the +// module index and the offset into tls is known at static link time +.Lt0: .word x1(TLSGD) + (. - .L0 - 8) +.Lt1: .word x2(TLSGD) + (. - .L1 - 8) +.Lt2: .word x3(TLSGD) + (. - .L2 - 8) +.Lt3: .word x4(TLSGD) + (. - .L3 - 8) + .hidden x1 + .globl x1 + .hidden x2 + .globl x2 + .globl x3 + .globl x4 + + .section .tdata,"awT",%progbits + .p2align 2 +.TLSSTART: + .type x1, %object +x1: + .word 10 + .type x2, %object +x2: + .word 20 + + .section .tbss,"awT",%nobits + .p2align 2 + .type x3, %object +x3: + .space 4 + .type x4, %object +x4: + .space 4 + +// CHECK: Contents of section .got: +// CHECK-NEXT: 12008 01000000 00000000 01000000 04000000 +// CHECK-NEXT: 12018 01000000 08000000 01000000 0c000000 + +// CHECK-SHARED: Contents of section .got: +// CHECK-SHARED-NEXT: 2050 00000000 00000000 00000000 04000000 +// CHECK-SHARED-NEXT: 2060 00000000 00000000 00000000 00000000