Skip to content

Commit

Permalink
[ELF] Add support for static TLS to ARM
Browse files Browse the repository at this point in the history
The module index dynamic relocation R_ARM_DTPMOD32 is always 1 for an
executable. When static linking and when we know that we are not a shared
object we can resolve the module index relocation statically.
    
The logic in handleNoRelaxTlsRelocation remains the same for Mips as it
has its own custom GOT writing code. For ARM we add the module index
relocation to the GOT when it can be resolved statically.
    
In addition the type of the RelExpr for the static resolution of TlsGotRel
should be R_TLS and not R_ABS as we need to include the size of
the thread control block in the calculation.
    
Addresses the TLS part of PR30218.

Differential revision: https://reviews.llvm.org/D27213

llvm-svn: 288153
  • Loading branch information
smithp35 committed Nov 29, 2016
1 parent df1cb52 commit de3e738
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 23 deletions.
34 changes: 22 additions & 12 deletions lld/ELF/Relocations.cpp
Expand Up @@ -90,28 +90,36 @@ static bool isPreemptible(const SymbolBody &Body, uint32_t Type) {
// support any relaxations for TLS relocations so by factoring out ARM and MIPS
// handling in to the separate function we can simplify the code and do not
// pollute `handleTlsRelocation` by ARM and MIPS `ifs` statements.
// FIXME: The ARM implementation always adds the module index dynamic
// relocation even for non-preemptible symbols in applications. For static
// linking support we must either resolve the module index relocation at static
// link time, or hard code the module index (1) for the application in the GOT.
template <class ELFT, class GOT>
static unsigned handleNoRelaxTlsRelocation(
GOT *Got, uint32_t Type, SymbolBody &Body, InputSectionBase<ELFT> &C,
typename ELFT::uint Offset, typename ELFT::uint Addend, RelExpr Expr) {
typedef typename ELFT::uint uintX_t;
auto addModuleReloc = [](SymbolBody &Body, GOT *Got, uintX_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<ELFT>::RelaDyn->addReloc(
{Target->TlsModuleIndexRel, Got, Off, false, Dest, 0});
}
};
if (Expr == R_MIPS_TLSLD || Expr == R_TLSLD_PC) {
if (Got->addTlsIndex() && (Config->Pic || Config->EMachine == EM_ARM))
In<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, Got,
Got->getTlsIndexOff(), false, nullptr, 0});
addModuleReloc(Body, Got, Got->getTlsIndexOff(), true);
C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
return 1;
}
typedef typename ELFT::uint uintX_t;
if (Target->isTlsGlobalDynamicRel(Type)) {
if (Got->addDynTlsEntry(Body) &&
(Body.isPreemptible() || Config->EMachine == EM_ARM)) {
uintX_t Off = Got->getGlobalDynOffset(Body);
In<ELFT>::RelaDyn->addReloc(
{Target->TlsModuleIndexRel, Got, Off, false, &Body, 0});
addModuleReloc(Body, Got, Off, false);
if (Body.isPreemptible())
In<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, Got,
Off + (uintX_t)sizeof(uintX_t), false,
Expand Down Expand Up @@ -746,17 +754,19 @@ static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
In<ELFT>::Got->addEntry(Body);
uintX_t Off = Body.getGotOffset<ELFT>();
uint32_t DynType;
if (Body.isTls())
RelExpr GotRE = R_ABS;
if (Body.isTls()) {
DynType = Target->TlsGotRel;
else if (!Preemptible && Config->Pic && !isAbsolute<ELFT>(Body))
GotRE = R_TLS;
} else if (!Preemptible && Config->Pic && !isAbsolute<ELFT>(Body))
DynType = Target->RelativeRel;
else
DynType = Target->GotRel;

if (Preemptible || (Config->Pic && !isAbsolute<ELFT>(Body)))
AddDyn({DynType, In<ELFT>::Got, Off, !Preemptible, &Body, 0});
else
In<ELFT>::Got->Relocations.push_back({R_ABS, DynType, Off, 0, &Body});
In<ELFT>::Got->Relocations.push_back({GotRE, DynType, Off, 0, &Body});
continue;
}
}
Expand Down
3 changes: 3 additions & 0 deletions lld/ELF/Target.cpp
Expand Up @@ -1711,6 +1711,9 @@ void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
case R_ARM_TLS_TPOFF32:
write32le(Loc, Val);
break;
case R_ARM_TLS_DTPMOD32:
write32le(Loc, 1);
break;
case R_ARM_PREL31:
checkInt<31>(Loc, Val, Type);
write32le(Loc, (read32le(Loc) & 0x80000000) | (Val & ~0x80000000));
Expand Down
8 changes: 4 additions & 4 deletions lld/test/ELF/arm-tls-norelax-gd-le.s
Expand Up @@ -2,7 +2,7 @@
// RUN: ld.lld %t1 --shared -o %t1.so
// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi
// RUN: ld.lld %t1.so %t.o -o %t
// RUN: llvm-readobj -s -dyn-relocations %t | FileCheck %s
// RUN: llvm-objdump -s %t | FileCheck %s
// REQUIRES: arm

// This tls global-dynamic sequence is with respect to a non-preemptible
Expand Down Expand Up @@ -31,7 +31,7 @@ x:
.space 4
.type x, %object

// CHECK: Dynamic Relocations {
// CHECK-NEXT: 0x12078 R_ARM_TLS_DTPMOD32
// CHECK-NEXT: 0x1300C R_ARM_JUMP_SLOT __tls_get_addr
// CHECK: Contents of section .got:
// Module index is always 1 for executable
// CHECK-NEXT: 12060 01000000 00000000

6 changes: 3 additions & 3 deletions lld/test/ELF/arm-tls-norelax-ie-le.s
Expand Up @@ -2,7 +2,7 @@
// RUN: ld.lld %t1 --shared -o %t1.so
// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi
// RUN: ld.lld %t1.so %t.o -o %t
// RUN: llvm-objdump -s -triple=armv7a-linux-gnueabi %t
// RUN: llvm-objdump -s -triple=armv7a-linux-gnueabi %t | FileCheck %s
// REQUIRES: arm

// This tls Initial Exec sequence is with respect to a non-preemptible symbol
Expand Down Expand Up @@ -37,5 +37,5 @@ x2:
.type x2, %object

// CHECK: Contents of section .got
// x1 at offset 0 from TP, x2 at offset 4 from TP
// 12064 00000000 04000000
// x1 at offset 8 from TP, x2 at offset c from TP. Offsets include TCB size of 8
// CHECK-NEXT: 12064 08000000 0c000000
7 changes: 3 additions & 4 deletions lld/test/ELF/arm-tls-norelax-ld-le.s
Expand Up @@ -2,7 +2,7 @@
// RUN: ld.lld %t1 --shared -o %t1.so
// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi
// RUN: ld.lld %t1.so %t.o -o %t
// RUN: llvm-readobj -s -dyn-relocations %t | FileCheck %s
// RUN: llvm-objdump -s %t | FileCheck %s
// REQUIRES: arm

.global __tls_get_addr
Expand Down Expand Up @@ -31,6 +31,5 @@ y:
x:
.word 10

// CHECK: Dynamic Relocations {
// CHECK-NEXT: 0x1207C R_ARM_TLS_DTPMOD32 - 0x0
// CHECK-NEXT: 0x1300C R_ARM_JUMP_SLOT __tls_get_addr 0x0
// CHECK: Contents of section .got:
// CHECK-NEXT: 12064 01000000 00000000

0 comments on commit de3e738

Please sign in to comment.