summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael Espindola <rafael.espindola@gmail.com>2016-06-02 19:49:53 +0000
committerRafael Espindola <rafael.espindola@gmail.com>2016-06-02 19:49:53 +0000
commite37d13b9ecc4746db58dd714a9087a1e35efb3ce (patch)
tree538e99c0e6be33e265c9663a30ee2f6a3040aeab
parent1ae44e6a2b8556e638c7c2bc79050573e605988b (diff)
downloadbcm5719-llvm-e37d13b9ecc4746db58dd714a9087a1e35efb3ce.tar.gz
bcm5719-llvm-e37d13b9ecc4746db58dd714a9087a1e35efb3ce.zip
Start adding tlsdesc support for aarch64.
This is mostly extracted from http://reviews.llvm.org/D18960. The general idea for tlsdesc is that the two GD got entries are used for a function pointer and its argument. The dynamic linker sets both. In the non-dlopen case the dynamic linker sets the function to the identity and the argument to the offset in the tls block. All that the static linker has to do in the non-dlopen case is relocate the code to point to the got entries and create a dynamic relocation. The dlopen case is more complicated, but can be implemented in another patch. llvm-svn: 271569
-rw-r--r--lld/ELF/InputSection.cpp5
-rw-r--r--lld/ELF/Relocations.cpp30
-rw-r--r--lld/ELF/Relocations.h2
-rw-r--r--lld/ELF/Target.cpp24
-rw-r--r--lld/ELF/Target.h1
-rw-r--r--lld/test/ELF/aarch64-tlsdesc.s24
6 files changed, 70 insertions, 16 deletions
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 54b6f5e29f5..fe76388ae76 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -193,6 +193,11 @@ getSymVA(uint32_t Type, typename ELFT::uint A, typename ELFT::uint P,
Out<ELFT>::Got->getNumEntries() * sizeof(uintX_t);
case R_TLSGD_PC:
return Out<ELFT>::Got->getGlobalDynAddr(Body) + A - P;
+ case R_TLSDESC:
+ return Out<ELFT>::Got->getGlobalDynAddr(Body) + A;
+ case R_TLSDESC_PAGE:
+ return getAArch64Page(Out<ELFT>::Got->getGlobalDynAddr(Body) + A) -
+ getAArch64Page(P);
case R_PLT:
return Body.getPltVA<ELFT>() + A;
case R_PLT_PC:
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 53149ba3faf..48fb403b50e 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -62,7 +62,7 @@ static bool refersToGotEntry(RelExpr Expr) {
return Expr == R_GOT || Expr == R_GOT_OFF || Expr == R_MIPS_GOT_LOCAL ||
Expr == R_MIPS_GOT_LOCAL_PAGE || Expr == R_GOT_PAGE_PC ||
Expr == R_GOT_PC || Expr == R_GOT_FROM_END || Expr == R_TLSGD ||
- Expr == R_TLSGD_PC;
+ Expr == R_TLSGD_PC || Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE;
}
static bool isPreemptible(const SymbolBody &Body, uint32_t Type) {
@@ -94,6 +94,19 @@ static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
return 0;
typedef typename ELFT::uint uintX_t;
+
+ if ((Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE || Expr == R_HINT) &&
+ Config->Shared) {
+ if (Out<ELFT>::Got->addDynTlsEntry(Body)) {
+ uintX_t Off = Out<ELFT>::Got->getGlobalDynOffset(Body);
+ Out<ELFT>::RelaDyn->addReloc(
+ {Target->TlsDescRel, Out<ELFT>::Got, Off, false, &Body, 0});
+ }
+ if (Expr != R_HINT)
+ C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
+ return 1;
+ }
+
if (Expr == R_TLSLD_PC || Expr == R_TLSLD) {
// Local-Dynamic relocs can be relaxed to Local-Exec.
if (!Config->Shared) {
@@ -116,7 +129,8 @@ static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
return 1;
}
- if (Target->isTlsGlobalDynamicRel(Type)) {
+ if (Expr == R_TLSDESC_PAGE || Expr == R_TLSDESC || Expr == R_HINT ||
+ Target->isTlsGlobalDynamicRel(Type)) {
if (Config->Shared) {
if (Out<ELFT>::Got->addDynTlsEntry(Body)) {
uintX_t Off = Out<ELFT>::Got->getGlobalDynOffset(Body);
@@ -254,12 +268,12 @@ static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type,
if (E == R_SIZE || E == R_GOT_FROM_END || E == R_GOT_OFF ||
E == R_MIPS_GOT_LOCAL || E == R_MIPS_GOT_LOCAL_PAGE ||
E == R_GOT_PAGE_PC || E == R_GOT_PC || E == R_PLT_PC || E == R_TLSGD_PC ||
- E == R_TLSGD || E == R_PPC_PLT_OPD)
+ E == R_TLSGD || E == R_PPC_PLT_OPD || E == R_TLSDESC_PAGE || E == R_HINT)
return true;
// These never do, except if the entire file is position dependent or if
// only the low bits are used.
- if (E == R_GOT || E == R_PLT)
+ if (E == R_GOT || E == R_PLT || E == R_TLSDESC)
return Target->usesOnlyLowPageBits(Type) || !Config->Pic;
if (isPreemptible(Body, Type))
@@ -493,10 +507,6 @@ static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
uint32_t Type = RI.getType(Config->Mips64EL);
RelExpr Expr = Target->getRelExpr(Type, Body);
- // Ignore "hint" relocation because it is for optional code optimization.
- if (Expr == R_HINT)
- continue;
-
uintX_t Offset = C.getOffset(RI.r_offset);
if (Offset == (uintX_t)-1)
continue;
@@ -519,6 +529,10 @@ static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
continue;
}
+ // Ignore "hint" relocation because it is for optional code optimization.
+ if (Expr == R_HINT)
+ continue;
+
if (needsPlt(Expr) || Expr == R_THUNK || refersToGotEntry(Expr) ||
!isPreemptible(Body, Type)) {
// If the relocation points to something in the file, we can process it.
diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h
index e682c579c86..57f0318359d 100644
--- a/lld/ELF/Relocations.h
+++ b/lld/ELF/Relocations.h
@@ -47,6 +47,8 @@ enum RelExpr {
R_SIZE,
R_THUNK,
R_TLS,
+ R_TLSDESC,
+ R_TLSDESC_PAGE,
R_TLSGD,
R_TLSGD_PC,
R_TLSLD,
diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp
index 4891f04b0a9..c18e45b615c 100644
--- a/lld/ELF/Target.cpp
+++ b/lld/ELF/Target.cpp
@@ -147,7 +147,6 @@ public:
AArch64TargetInfo();
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
uint32_t getDynRel(uint32_t Type) const override;
- bool isTlsGlobalDynamicRel(uint32_t Type) const override;
bool isTlsInitialExecRel(uint32_t Type) const override;
void writeGotPlt(uint8_t *Buf, uint64_t Plt) const override;
void writePltZero(uint8_t *Buf) const override;
@@ -1076,6 +1075,7 @@ AArch64TargetInfo::AArch64TargetInfo() {
IRelativeRel = R_AARCH64_IRELATIVE;
GotRel = R_AARCH64_GLOB_DAT;
PltRel = R_AARCH64_JUMP_SLOT;
+ TlsDescRel = R_AARCH64_TLSDESC;
TlsGotRel = R_AARCH64_TLS_TPREL64;
PltEntrySize = 16;
PltZeroSize = 32;
@@ -1091,6 +1091,16 @@ RelExpr AArch64TargetInfo::getRelExpr(uint32_t Type,
default:
return R_ABS;
+ case R_AARCH64_TLSDESC_ADR_PAGE21:
+ return R_TLSDESC_PAGE;
+
+ case R_AARCH64_TLSDESC_LD64_LO12_NC:
+ case R_AARCH64_TLSDESC_ADD_LO12_NC:
+ return R_TLSDESC;
+
+ case R_AARCH64_TLSDESC_CALL:
+ return R_HINT;
+
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
return R_TLS;
@@ -1128,18 +1138,13 @@ bool AArch64TargetInfo::usesOnlyLowPageBits(uint32_t Type) const {
case R_AARCH64_LDST32_ABS_LO12_NC:
case R_AARCH64_LDST64_ABS_LO12_NC:
case R_AARCH64_LDST8_ABS_LO12_NC:
+ case R_AARCH64_TLSDESC_ADD_LO12_NC:
+ case R_AARCH64_TLSDESC_LD64_LO12_NC:
case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
return true;
}
}
-bool AArch64TargetInfo::isTlsGlobalDynamicRel(uint32_t Type) const {
- return Type == R_AARCH64_TLSDESC_ADR_PAGE21 ||
- Type == R_AARCH64_TLSDESC_LD64_LO12_NC ||
- Type == R_AARCH64_TLSDESC_ADD_LO12_NC ||
- Type == R_AARCH64_TLSDESC_CALL;
-}
-
bool AArch64TargetInfo::isTlsInitialExecRel(uint32_t Type) const {
return Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 ||
Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC;
@@ -1239,6 +1244,7 @@ void AArch64TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
case R_AARCH64_ADR_GOT_PAGE:
case R_AARCH64_ADR_PREL_PG_HI21:
case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+ case R_AARCH64_TLSDESC_ADR_PAGE21:
checkInt<33>(Val, Type);
updateAArch64Addr(Loc, Val >> 12);
break;
@@ -1257,6 +1263,7 @@ void AArch64TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
break;
case R_AARCH64_LD64_GOT_LO12_NC:
case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+ case R_AARCH64_TLSDESC_LD64_LO12_NC:
checkAlignment<8>(Val, Type);
or32le(Loc, (Val & 0xFF8) << 7);
break;
@@ -1284,6 +1291,7 @@ void AArch64TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
updateAArch64Add(Loc, Val >> 12);
break;
case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
+ case R_AARCH64_TLSDESC_ADD_LO12_NC:
updateAArch64Add(Loc, Val);
break;
default:
diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h
index f572c73685e..5fa1181f54f 100644
--- a/lld/ELF/Target.h
+++ b/lld/ELF/Target.h
@@ -73,6 +73,7 @@ public:
uint32_t PltRel;
uint32_t RelativeRel;
uint32_t IRelativeRel;
+ uint32_t TlsDescRel;
uint32_t TlsGotRel = 0;
uint32_t TlsModuleIndexRel;
uint32_t TlsOffsetRel;
diff --git a/lld/test/ELF/aarch64-tlsdesc.s b/lld/test/ELF/aarch64-tlsdesc.s
new file mode 100644
index 00000000000..f8c73aff243
--- /dev/null
+++ b/lld/test/ELF/aarch64-tlsdesc.s
@@ -0,0 +1,24 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t.so
+// RUN: llvm-objdump -d %t.so | FileCheck %s
+// RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=REL %s
+
+ adrp x0, :tlsdesc:a
+ ldr x1, [x0, :tlsdesc_lo12:a]
+ add x0, x0, :tlsdesc_lo12:a
+ .tlsdesccall a
+ blr x1
+
+// CHECK: 1000: {{.*}} adrp x0, #4096
+// CHECK-NEXT: 1004: {{.*}} ldr x1, [x0, #144]
+// CHECK-NEXT: 1008: {{.*}} add x0, x0, #144
+// CHECK-NEXT: 100c: {{.*}} blr x1
+
+// 0x1000 + 4096 + 144 = 0x2090
+
+// REL: Relocations [
+// REL-NEXT: Section (4) .rela.dyn {
+// REL-NEXT: 0x2090 R_AARCH64_TLSDESC a 0x0
+// REL-NEXT: }
+// REL-NEXT: ]
OpenPOWER on IntegriCloud