aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRafael Espindola <rafael.espindola@gmail.com>2016-06-04 23:33:31 +0000
committerRafael Espindola <rafael.espindola@gmail.com>2016-06-04 23:33:31 +0000
commit812fef1ded963b81ec6fa9dd96953df1adc814dc (patch)
tree0464c7f279a6f7a43c33a85d0bf38ca1d3d6dfe3
parentf7fa63f9963ea4a83b26318dfa7bea6de7b0e02c (diff)
Implement gd to ie relaxation for aarch64.
git-svn-id: https://llvm.org/svn/llvm-project/lld/trunk@271815 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--ELF/InputSection.cpp4
-rw-r--r--ELF/Relocations.cpp2
-rw-r--r--ELF/Relocations.h2
-rw-r--r--ELF/Target.cpp46
-rw-r--r--test/ELF/Inputs/aarch64-tls-gdie.s4
-rw-r--r--test/ELF/aarch64-tls-gdie.s34
6 files changed, 91 insertions, 1 deletions
diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp
index a90b3098a..713933c11 100644
--- a/ELF/InputSection.cpp
+++ b/ELF/InputSection.cpp
@@ -183,8 +183,10 @@ getSymVA(uint32_t Type, typename ELFT::uint A, typename ELFT::uint P,
case R_GOT_FROM_END:
return Body.getGotOffset<ELFT>() + A -
Out<ELFT>::Got->getNumEntries() * sizeof(uintX_t);
+ case R_RELAX_TLS_GD_TO_IE_ABS:
case R_GOT:
return Body.getGotVA<ELFT>() + A;
+ case R_RELAX_TLS_GD_TO_IE_PAGE_PC:
case R_GOT_PAGE_PC:
return getAArch64Page(Body.getGotVA<ELFT>() + A) - getAArch64Page(P);
case R_RELAX_TLS_GD_TO_IE:
@@ -324,6 +326,8 @@ void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd) {
Target->relaxTlsGdToLe(BufLoc, Type, SymVA);
break;
case R_RELAX_TLS_GD_TO_IE:
+ case R_RELAX_TLS_GD_TO_IE_ABS:
+ case R_RELAX_TLS_GD_TO_IE_PAGE_PC:
case R_RELAX_TLS_GD_TO_IE_END:
Target->relaxTlsGdToIe(BufLoc, Type, SymVA);
break;
diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp
index 736e44748..3e59a0e2c 100644
--- a/ELF/Relocations.cpp
+++ b/ELF/Relocations.cpp
@@ -156,7 +156,7 @@ static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
Body.getGotOffset<ELFT>(), false, &Body,
0});
}
- return 2;
+ return Target->TlsGdRelaxSkip;
}
C.Relocations.push_back(
{Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_LE), Type,
diff --git a/ELF/Relocations.h b/ELF/Relocations.h
index 8f6a5ce75..346122009 100644
--- a/ELF/Relocations.h
+++ b/ELF/Relocations.h
@@ -43,6 +43,8 @@ enum RelExpr {
R_RELAX_GOT_PC_NOPIC,
R_RELAX_TLS_GD_TO_IE,
R_RELAX_TLS_GD_TO_IE_END,
+ R_RELAX_TLS_GD_TO_IE_ABS,
+ R_RELAX_TLS_GD_TO_IE_PAGE_PC,
R_RELAX_TLS_GD_TO_LE,
R_RELAX_TLS_GD_TO_LE_NEG,
R_RELAX_TLS_IE_TO_LE,
diff --git a/ELF/Target.cpp b/ELF/Target.cpp
index 073e613b3..529abacae 100644
--- a/ELF/Target.cpp
+++ b/ELF/Target.cpp
@@ -156,7 +156,10 @@ public:
int32_t Index, unsigned RelOff) const override;
bool usesOnlyLowPageBits(uint32_t Type) const override;
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+ RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
+ RelExpr Expr) const override;
void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+ void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
};
@@ -1141,6 +1144,16 @@ RelExpr AArch64TargetInfo::getRelExpr(uint32_t Type,
}
}
+RelExpr AArch64TargetInfo::adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
+ RelExpr Expr) const {
+ if (Expr == R_RELAX_TLS_GD_TO_IE) {
+ if (Type == R_AARCH64_TLSDESC_ADR_PAGE21)
+ return R_RELAX_TLS_GD_TO_IE_PAGE_PC;
+ return R_RELAX_TLS_GD_TO_IE_ABS;
+ }
+ return Expr;
+}
+
bool AArch64TargetInfo::usesOnlyLowPageBits(uint32_t Type) const {
switch (Type) {
default:
@@ -1320,6 +1333,7 @@ void AArch64TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type,
// ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12_NC]
// add x0, x0, :tlsdesc_los:v [_AARCH64_TLSDESC_ADD_LO12_NC]
// .tlsdesccall [R_AARCH64_TLSDESC_CALL]
+ // blr x1
// And it can optimized to:
// movz x0, #0x0, lsl #16
// movk x0, #0x10
@@ -1348,6 +1362,38 @@ void AArch64TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type,
write32le(Loc, NewInst);
}
+void AArch64TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type,
+ uint64_t Val) const {
+ // TLSDESC Global-Dynamic relocation are in the form:
+ // adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21]
+ // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12_NC]
+ // add x0, x0, :tlsdesc_los:v [_AARCH64_TLSDESC_ADD_LO12_NC]
+ // .tlsdesccall [R_AARCH64_TLSDESC_CALL]
+ // blr x1
+ // And it can optimized to:
+ // adrp x0, :gottprel:v
+ // ldr x0, [x0, :gottprel_lo12:v]
+ // nop
+ // nop
+
+ switch (Type) {
+ case R_AARCH64_TLSDESC_ADD_LO12_NC:
+ case R_AARCH64_TLSDESC_CALL:
+ write32le(Loc, 0xd503201f); // nop
+ break;
+ case R_AARCH64_TLSDESC_ADR_PAGE21:
+ write32le(Loc, 0x90000000); // adrp
+ relocateOne(Loc, R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21, Val);
+ break;
+ case R_AARCH64_TLSDESC_LD64_LO12_NC:
+ write32le(Loc, 0xf9400000); // ldr
+ relocateOne(Loc, R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC, Val);
+ break;
+ default:
+ llvm_unreachable("unsupported Relocation for TLS GD to LE relax");
+ }
+}
+
void AArch64TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type,
uint64_t Val) const {
checkUInt<32>(Val, Type);
diff --git a/test/ELF/Inputs/aarch64-tls-gdie.s b/test/ELF/Inputs/aarch64-tls-gdie.s
new file mode 100644
index 000000000..289cae523
--- /dev/null
+++ b/test/ELF/Inputs/aarch64-tls-gdie.s
@@ -0,0 +1,4 @@
+ .section .tdata,"awT",@progbits
+ .globl a
+a:
+ .word 42
diff --git a/test/ELF/aarch64-tls-gdie.s b/test/ELF/aarch64-tls-gdie.s
new file mode 100644
index 000000000..709cc53a8
--- /dev/null
+++ b/test/ELF/aarch64-tls-gdie.s
@@ -0,0 +1,34 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=aarch64-pc-linux
+// RUN: llvm-mc %p/Inputs/aarch64-tls-gdie.s -o %t2.o -filetype=obj -triple=aarch64-pc-linux
+// RUN: ld.lld %t2.o -o %t2.so -shared
+// RUN: ld.lld %t.o %t2.so -o %t
+// RUN: llvm-readobj -s %t | FileCheck --check-prefix=SEC %s
+// RUN: llvm-objdump -d %t | FileCheck %s
+
+ .globl _start
+_start:
+ nop
+ adrp x0, :tlsdesc:a
+ ldr x1, [x0, :tlsdesc_lo12:a]
+ add x0, x0, :tlsdesc_lo12:a
+ .tlsdesccall a
+ blr x1
+
+// SEC: Name: .got
+// SEC-NEXT: Type: SHT_PROGBITS
+// SEC-NEXT: Flags [
+// SEC-NEXT: SHF_ALLOC
+// SEC-NEXT: SHF_WRITE
+// SEC-NEXT: ]
+// SEC-NEXT: Address: 0x120B0
+
+// page(0x120B0) - page(0x11004) = 4096
+// 0x0B0 = 176
+
+// CHECK: _start:
+// CHECK-NEXT: 11000: {{.*}} nop
+// CHECK-NEXT: 11004: {{.*}} adrp x0, #4096
+// CHECK-NEXT: 11008: {{.*}} ldr x0, [x0, #176]
+// CHECK-NEXT: 1100c: {{.*}} nop
+// CHECK-NEXT: 11010: {{.*}} nop