aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Smith <peter.smith@arm.com>2016-07-06 10:41:22 +0100
committerPeter Smith <peter.smith@arm.com>2016-07-08 18:29:55 +0100
commit2913fd92133a4d9cef4ea1b0f2eaaccd2ec4a92f (patch)
treed5eda9464f6fe2f5174d4ed146172bbb2d88eca2
parent287b1799bcf6d2d7b63acd30752cb44216849a5c (diff)
Support for standard model ARM TLSlinaro-local/tls
Add relocations and identification functions for the TLS model defined in Addenda to, and Errata in, the ABI for the ARM Architecture. ARM uses variant 1 of the thread local storage data structures as defined in ELF Handling for Thread-Local Storage. The "experimental" descriptor based model that can be selected in gcc, but not clang with -mtls-dialect=gnu2 is not supported. The relocations R_ARM_TLS_LE12 and R_ARM_TLS_IE12GP are not supported, I know of no ARM Toolchain that supports these relocations as they limit the size of the TLS block. Change-Id: Ia3d380414d88437ca5b973c8542491811a97e6df
-rw-r--r--ELF/Target.cpp34
-rw-r--r--test/ELF/arm-tls-gd32.s159
-rw-r--r--test/ELF/arm-tls-ie32.s163
-rw-r--r--test/ELF/arm-tls-ldm32.s60
4 files changed, 415 insertions, 1 deletions
diff --git a/ELF/Target.cpp b/ELF/Target.cpp
index 51d18c370..df0d24535 100644
--- a/ELF/Target.cpp
+++ b/ELF/Target.cpp
@@ -178,6 +178,9 @@ public:
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
uint32_t getDynRel(uint32_t Type) const override;
uint64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override;
+ bool isTlsLocalDynamicRel(uint32_t Type) const override;
+ bool isTlsGlobalDynamicRel(uint32_t Type) const override;
+ bool isTlsInitialExecRel(uint32_t Type) const override;
void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
void writePltHeader(uint8_t *Buf) const override;
void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
@@ -1459,6 +1462,8 @@ ARMTargetInfo::ARMTargetInfo() {
TlsOffsetRel = R_ARM_TLS_DTPOFF32;
PltEntrySize = 16;
PltHeaderSize = 20;
+ // ARM uses Variant 1 TLS
+ TcbSize = 8;
}
RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
@@ -1482,8 +1487,13 @@ RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
// GOT(S) + A - GOT_ORG
return R_GOT_OFF;
case R_ARM_GOT_PREL:
- // GOT(S) + - GOT_ORG
+ case R_ARM_TLS_IE32:
+ // GOT(S) + A - P
return R_GOT_PC;
+ case R_ARM_TLS_GD32:
+ return R_TLSGD_PC;
+ case R_ARM_TLS_LDM32:
+ return R_TLSLD_PC;
case R_ARM_BASE_PREL:
// B(S) + A - P
// FIXME: currently B(S) assumed to be .got, this may not hold for all
@@ -1496,6 +1506,8 @@ RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
case R_ARM_THM_MOVW_PREL_NC:
case R_ARM_THM_MOVT_PREL:
return R_PC;
+ case R_ARM_TLS_LE32:
+ return R_TLS;
}
}
@@ -1581,6 +1593,11 @@ void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
case R_ARM_GOT_BREL:
case R_ARM_GOT_PREL:
case R_ARM_REL32:
+ case R_ARM_TLS_GD32:
+ case R_ARM_TLS_LDM32:
+ case R_ARM_TLS_LDO32:
+ case R_ARM_TLS_IE32:
+ case R_ARM_TLS_LE32:
write32le(Loc, Val);
break;
case R_ARM_PREL31:
@@ -1704,6 +1721,11 @@ uint64_t ARMTargetInfo::getImplicitAddend(const uint8_t *Buf,
case R_ARM_GOT_BREL:
case R_ARM_GOT_PREL:
case R_ARM_REL32:
+ case R_ARM_TLS_GD32:
+ case R_ARM_TLS_LDM32:
+ case R_ARM_TLS_LDO32:
+ case R_ARM_TLS_IE32:
+ case R_ARM_TLS_LE32:
return SignExtend64<32>(read32le(Buf));
case R_ARM_PREL31:
return SignExtend64<31>(read32le(Buf));
@@ -1761,6 +1783,16 @@ uint64_t ARMTargetInfo::getImplicitAddend(const uint8_t *Buf,
}
}
+bool ARMTargetInfo::isTlsLocalDynamicRel(uint32_t Type) const {
+ return Type == R_ARM_TLS_LDO32 || Type == R_ARM_TLS_LDM32;
+}
+bool ARMTargetInfo::isTlsGlobalDynamicRel(uint32_t Type) const {
+ return Type == R_ARM_TLS_GD32;
+}
+bool ARMTargetInfo::isTlsInitialExecRel(uint32_t Type) const {
+ return Type == R_ARM_TLS_IE32;
+}
+
template <class ELFT> MipsTargetInfo<ELFT>::MipsTargetInfo() {
GotPltHeaderEntriesNum = 2;
PageSize = 65536;
diff --git a/test/ELF/arm-tls-gd32.s b/test/ELF/arm-tls-gd32.s
new file mode 100644
index 000000000..f22cf92b2
--- /dev/null
+++ b/test/ELF/arm-tls-gd32.s
@@ -0,0 +1,159 @@
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -s -dyn-relocations %t.so | FileCheck --check-prefix=SEC %s
+// RUN: llvm-objdump -d -triple=armv7a-linux-gnueabi %t.so | FileCheck %s
+// REQUIRES: arm
+
+// Test the handling of the global-dynamic TLS model. Dynamic Loader finds
+// module index R_ARM_TLS_DTPMOD32 and the offset within the module
+// R_ARM_TLS_DTPOFF32. One of the variables is hidden which permits relaxation
+// to local dynamic
+
+ .text
+ .syntax unified
+ .globl func
+ .p2align 2
+ .type func,%function
+func:
+ push {r4, r5, r11, lr}
+ add r11, sp, #8
+ ldr r0, .LCPI0_0
+.LPC0_2:
+ add r0, pc, r0
+ bl __tls_get_addr
+ ldr r1, [r0]
+ ldr r2, .LCPI0_1
+ add r4, r1, #1
+ str r4, [r0]
+.LPC0_1:
+ add r0, pc, r2
+ bl __tls_get_addr
+ ldr r1, [r0]
+ ldr r2, .LCPI0_2
+ add r5, r1, #1
+ str r5, [r0]
+.LPC0_0:
+ add r0, pc, r2
+ bl __tls_get_addr
+ ldr r1, [r0]
+ add r1, r1, #1
+ str r1, [r0]
+ add r0, r1, r5
+ add r0, r0, r4
+ pop {r4, r5, r11, pc}
+ .p2align 2
+.LCPI0_0:
+ .word x(TLSGD) + (. - .LPC0_2 - 8)
+.LCPI0_1:
+ .word y(TLSGD) + (. - .LPC0_1 - 8)
+.LCPI0_2:
+ .word z(TLSGD) + (. - .LPC0_0 - 8)
+.Lfunc_end0:
+
+ .type x,%object @ @x
+ .section .tdata,"awT",%progbits
+ .globl x
+ .p2align 2
+x:
+ .word 10 @ 0xa
+
+ .type y,%object @ @y
+ .section .tbss,"awT",%nobits
+ .globl y
+ .p2align 2
+y:
+ .word 0
+
+ .hidden z
+ .type z,%object
+ .globl z
+
+z:
+ .word 0
+
+// SEC: Name: .tdata
+// SEC-NEXT: Type: SHT_PROGBITS (0x1)
+// SEC-NEXT: Flags [
+// SEC-NEXT: SHF_ALLOC
+// SEC-NEXT: SHF_TLS
+// SEC-NEXT: SHF_WRITE
+// SEC-NEXT: ]
+// SEC-NEXT: Address: 0x2000
+// SEC: Size: 4
+// SEC: Name: .tbss
+// SEC-NEXT: Type: SHT_NOBITS
+// SEC-NEXT: Flags [
+// SEC-NEXT: SHF_ALLOC
+// SEC-NEXT: SHF_TLS
+// SEC-NEXT: SHF_WRITE
+// SEC-NEXT: ]
+// SEC-NEXT: Address: 0x2004
+// SEC: Size: 8
+
+// SEC: Name: .got (74)
+// SEC-NEXT: Type: SHT_PROGBITS (0x1)
+// SEC-NEXT: Flags [
+// SEC-NEXT: SHF_ALLOC
+// SEC-NEXT: SHF_WRITE
+// SEC-NEXT: ]
+// SEC-NEXT: Address: 0x206C
+// SEC: Size: 24
+
+// SEC: Dynamic Relocations {
+// SEC-NEXT: 0x207C R_ARM_TLS_DTPMOD32 -
+// SEC-NEXT: 0x206C R_ARM_TLS_DTPMOD32 x
+// SEC-NEXT: 0x2070 R_ARM_TLS_DTPOFF32 x
+// SEC-NEXT: 0x2074 R_ARM_TLS_DTPMOD32 y
+// SEC-NEXT: 0x2078 R_ARM_TLS_DTPOFF32 y
+// SEC-NEXT: 0x300C R_ARM_JUMP_SLOT __tls_get_addr
+
+// CHECK: Disassembly
+// CHECK-NEXT: func:
+// CHECK-NEXT: 1000: 30 48 2d e9 push {r4, r5, r11, lr}
+// CHECK-NEXT: 1004: 08 b0 8d e2 add r11, sp, #8
+// CHECK-NEXT: 1008: 4c 00 9f e5 ldr r0, [pc, #76]
+// .LPC0_2:
+// CHECK-NEXT: 100c: 00 00 8f e0 add r0, pc, r0
+// 0x1010 + 8 + 0x6c = 0x1084 = __tls_get_addr(PLT)
+// CHECK-NEXT: 1010: 1b 00 00 eb bl #108
+// CHECK-NEXT: 1014: 00 10 90 e5 ldr r1, [r0]
+// CHECK-NEXT: 1018: 40 20 9f e5 ldr r2, [pc, #64]
+// CHECK-NEXT: 101c: 01 40 81 e2 add r4, r1, #1
+// CHECK-NEXT: 1020: 00 40 80 e5 str r4, [r0]
+// .LPC0_1:
+// CHECK-NEXT: 1024: 02 00 8f e0 add r0, pc, r2
+// 0x1028 + 8 + 0x54 = 0x1084 = __tls_get_addr(PLT)
+// CHECK-NEXT: 1028: 15 00 00 eb bl #84
+// CHECK-NEXT: 102c: 00 10 90 e5 ldr r1, [r0]
+// CHECK-NEXT: 1030: 2c 20 9f e5 ldr r2, [pc, #44]
+// CHECK-NEXT: 1034: 01 50 81 e2 add r5, r1, #1
+// CHECK-NEXT: 1038: 00 50 80 e5 str r5, [r0]
+// .LPC0_0:
+// CHECK-NEXT: 103c: 02 00 8f e0 add r0, pc, r2
+// 0x1040 + 8 + 0x3c = 0x1084 = __tls_get_addr(PLT)
+// CHECK-NEXT: 1040: 0f 00 00 eb bl #60
+// CHECK-NEXT: 1044: 00 10 90 e5 ldr r1, [r0]
+// CHECK-NEXT: 1048: 01 10 81 e2 add r1, r1, #1
+// CHECK-NEXT: 104c: 00 10 80 e5 str r1, [r0]
+// CHECK-NEXT: 1050: 05 00 81 e0 add r0, r1, r5
+// CHECK-NEXT: 1054: 04 00 80 e0 add r0, r0, r4
+// CHECK-NEXT: 1058: 30 88 bd e8 pop {r4, r5, r11, pc}
+
+// (0x206c - 0x105c) - (0x105c - 0x100c - 8) = 0x1058
+// CHECK: 105c: 58 10 00 00
+// (0x2074 - 0x1060) - (0x1060 - 0x1024 - 8) = 0x1048
+// CHECK-NEXT: 1060: 48 10 00 00
+// (0x207c - 0x1064) - (0x1064 - 0x103c - 8) = 0x1038
+// CHECK-NEXT: 1064: 38 10 00 00
+
+// CHECK: Disassembly of section .plt:
+// CHECK-NEXT: .plt:
+// CHECK-NEXT: 1070: 04 e0 2d e5 str lr, [sp, #-4]!
+// CHECK-NEXT: 1074: 04 e0 9f e5 ldr lr, [pc, #4]
+// CHECK-NEXT: 1078: 0e e0 8f e0 add lr, pc, lr
+// CHECK-NEXT: 107c: 08 f0 be e5 ldr pc, [lr, #8]!
+// CHECK-NEXT: 1080: 80 1f 00 00
+// CHECK-NEXT: 1084: 04 c0 9f e5 ldr r12, [pc, #4]
+// CHECK-NEXT: 1088: 0f c0 8c e0 add r12, r12, pc
+// CHECK-NEXT: 108c: 00 f0 9c e5 ldr pc, [r12]
+// CHECK-NEXT: 1090: 7c 1f 00 00
diff --git a/test/ELF/arm-tls-ie32.s b/test/ELF/arm-tls-ie32.s
new file mode 100644
index 000000000..e2a01e5e0
--- /dev/null
+++ b/test/ELF/arm-tls-ie32.s
@@ -0,0 +1,163 @@
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=thumbv7a-linux-gnueabi
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -s -dyn-relocations %t.so | FileCheck --check-prefix=SEC %s
+// RUN: llvm-objdump -d -triple=thumbv7a-linux-gnueabi %t.so | FileCheck %s
+// REQUIRES: arm
+
+// Test the handling of the initial-exec TLS model. Relative location within
+// static TLS is a run-time constant computed by dynamic loader as a result
+// of the R_ARM_TLS_TPOFF32 relocation.
+
+ .syntax unified
+ .thumb
+ .globl func
+ .type func,%function
+ .p2align 2
+func:
+ ldr r1, .L3
+ mrc p15, 0, r3, c13, c0, 3 // load_tp_hard
+ push {r4, r5, r6}
+ ldr r6, .L3+4
+.LPIC0:
+ add r1, pc
+ ldr r1, [r1]
+ ldr r0, [r3, r1]
+ ldr r5, .L3+8
+.LPIC1:
+ add r6, pc
+ ldr r6, [r6]
+ ldr r2, .L3+12
+ adds r4, r0, #1
+ ldr r1, .L3+16
+ str r4, [r3, r6]
+.LPIC2:
+ add r5, pc
+ ldr r5, [r5]
+ ldr r0, [r3, r5]
+.LPIC3:
+ add r2, pc
+ ldr r2, [r2]
+ adds r0, r0, #1
+ str r0, [r3, r2]
+.LPIC4:
+ add r1, pc
+ ldr r1, [r1]
+ ldr r2, [r3, r1]
+ add r0, r0, r4
+ pop {r4, r5, r6}
+ adds r2, r2, #1
+ add r0, r0, r2
+ str r2, [r3, r1]
+ bx lr
+.L4:
+ .p2align 2
+.L3:
+ .word x(gottpoff) + (. - .LPIC0 - 4)
+ .word x(gottpoff) + (. - .LPIC1 - 4)
+ .word y(gottpoff) + (. - .LPIC2 - 4)
+ .word y(gottpoff) + (. - .LPIC3 - 4)
+ .word .LANCHOR0(gottpoff) + (. - .LPIC4 - 4)
+
+ .hidden z
+ .globl z
+ .globl y
+ .globl x
+
+ .section .tbss,"awT",%nobits
+.p2align 2
+.LANCHOR0 = . + 0
+ .type z, %object
+z:
+ .space 4
+ .type y, %object
+y:
+ .space 4
+ .section .tdata,"awT",%progbits
+ .p2align 2
+ .type x, %object
+x:
+ .word 10
+
+// SEC: Name: .tdata
+// SEC-NEXT: Type: SHT_PROGBITS
+// SEC-NEXT: Flags [
+// SEC-NEXT: SHF_ALLOC
+// SEC-NEXT: SHF_TLS
+// SEC-NEXT: SHF_WRITE
+// SEC: Size: 4
+// SEC: Name: .tbss
+// SEC-NEXT: Type: SHT_NOBITS
+// SEC-NEXT: Flags [
+// SEC-NEXT: SHF_ALLOC
+// SEC-NEXT: SHF_TLS
+// SEC-NEXT: SHF_WRITE
+// SEC: Size: 8
+
+// SEC: Name: .got
+// SEC-NEXT: Type: SHT_PROGBITS
+// SEC-NEXT: Flags [
+// SEC-NEXT: SHF_ALLOC
+// SEC-NEXT: SHF_WRITE
+// SEC-NEXT: ]
+// SEC-NEXT: Address: 0x204C
+// SEC: Size: 12
+
+
+// SEC: Dynamic Relocations {
+// SEC-NEXT: 0x2054 R_ARM_TLS_TPOFF32
+// SEC-NEXT: 0x204C R_ARM_TLS_TPOFF32 x
+// SEC-NEXT: 0x2050 R_ARM_TLS_TPOFF32 y
+
+// CHECK: Disassembly
+// CHECK-NEXT: func:
+// CHECK: 1000: 11 49 ldr r1, [pc, #68]
+// CHECK-NEXT: 1002: 1d ee 70 3f mrc p15, #0, r3, c13, c0, #3
+// CHECK-NEXT: 1006: 70 b4 push {r4, r5, r6}
+// CHECK-NEXT: 1008: df f8 40 60 ldr.w r6, [pc, #64]
+// .LPIC0:
+// CHECK-NEXT: 100c: 79 44 add r1, pc
+// CHECK-NEXT: 100e: 09 68 ldr r1, [r1]
+// CHECK-NEXT: 1010: 58 58 ldr r0, [r3, r1]
+// CHECK-NEXT: 1012: df f8 3c 50 ldr.w r5, [pc, #60]
+// .LPIC1:
+// CHECK-NEXT: 1016: 7e 44 add r6, pc
+// CHECK-NEXT: 1018: 36 68 ldr r6, [r6]
+// CHECK-NEXT: 101a: df f8 38 20 ldr.w r2, [pc, #56]
+// CHECK-NEXT: 101e: 44 1c adds r4, r0, #1
+// CHECK-NEXT: 1020: df f8 34 10 ldr.w r1, [pc, #52]
+// CHECK-NEXT: 1024: 9c 51 str r4, [r3, r6]
+// .LPIC2:
+// CHECK-NEXT: 1026: 7d 44 add r5, pc
+// CHECK-NEXT: 1028: 2d 68 ldr r5, [r5]
+// CHECK-NEXT: 102a: 58 59 ldr r0, [r3, r5]
+// .LPIC3:
+// CHECK-NEXT: 102c: 7a 44 add r2, pc
+// CHECK-NEXT: 102e: 12 68 ldr r2, [r2]
+// CHECK-NEXT: 1030: 40 1c adds r0, r0, #1
+// CHECK-NEXT: 1032: 98 50 str r0, [r3, r2]
+// .LPIC4
+// CHECK-NEXT: 1034: 79 44 add r1, pc
+// CHECK-NEXT: 1036: 09 68 ldr r1, [r1]
+// CHECK-NEXT: 1038: 5a 58 ldr r2, [r3, r1]
+// CHECK-NEXT: 103a: 20 44 add r0, r4
+// CHECK-NEXT: 103c: 70 bc pop {r4, r5, r6}
+// CHECK-NEXT: 103e: 52 1c adds r2, r2, #1
+// CHECK-NEXT: 1040: 10 44 add r0, r2
+// CHECK-NEXT: 1042: 5a 50 str r2, [r3, r1]
+// CHECK-NEXT: 1044: 70 47 bx lr
+// CHECK-NEXT: 1046: 00 bf nop
+// (0x204c - 0x1048) + (0x1048 - 0x100c - 4) = 0x103c
+// CHECK: 1048: 3c 10
+// CHECK-NEXT: 104a: 00 00
+// (0x204c - 0x104c) + (0x104c - 0x1016 - 4) = 0x1032
+// CHECK-NEXT: 104c: 32 10
+// CHECK-NEXT: 104e: 00 00
+// (0x2050 - 0x1050) + (0x1050 - 0x1026 - 4) = 0x1026
+// CHECK-NEXT: 1050: 26 10
+// CHECK-NEXT: 1052: 00 00
+// (0x2050 - 0x1054) + (0x1054 - 0x102c -4) = 0x1020
+// CHECK-NEXT: 1054: 20 10
+// CHECK-NEXT: 1056: 00 00
+// (0x2054 - 0x1058) + (0x1058 - 0x1034 -4) = 0x101c
+// CHECK-NEXT: 1058: 1c 10
+// CHECK-NEXT: 105a: 00 00
diff --git a/test/ELF/arm-tls-ldm32.s b/test/ELF/arm-tls-ldm32.s
new file mode 100644
index 000000000..90e35d8d2
--- /dev/null
+++ b/test/ELF/arm-tls-ldm32.s
@@ -0,0 +1,60 @@
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -s -dyn-relocations %t.so | FileCheck --check-prefix=SEC %s
+// RUN: llvm-objdump -d -triple=armv7a-linux-gnueabi %t.so | FileCheck %s
+// REQUIRES: arm
+ .global __tls_get_addr
+ .text
+ .p2align 2
+ .global func
+ .syntax unified
+ .arm
+ .type func, %function
+func:
+ ldr r0, .L3
+ push {r4, lr}
+ ldr r4, .L3+4
+.LPIC0:
+ add r0, pc, r0
+ bl __tls_get_addr
+ ldr lr, .L3+8
+ mov r3, r0
+ ldr ip, .L3+12
+ ldr r0, [r0, r4]
+ ldr r1, [r3, lr]
+ ldr r2, [r3, ip]
+ add r0, r0, #1
+ add r1, r1, #1
+ str r0, [r3, r4]
+ add r2, r2, #1
+ add r0, r0, r1
+ str r1, [r3, lr]
+ add r0, r0, r2
+ str r2, [r3, ip]
+ pop {r4, pc}
+.L4:
+ .p2align 2
+.L3:
+ .word x(tlsldm) + (. - .LPIC0 - 8)
+ .word x(tlsldo)
+ .word y(tlsldo)
+ .word .LANCHOR0(tlsldo)
+ .hidden z
+ .globl z
+ .section .tbss,"awT",%nobits
+ .p2align 2
+.LANCHOR0 = . + 0
+ .type z, %object
+z:
+ .space 4
+ .type y, %object
+y:
+ .space 4
+ .section .tdata,"awT",%progbits
+ .p2align 2
+ .type x, %object
+x:
+ .word 10
+
+// SEC: Name: .tdata
+// CHECK: Disassembly