[ARM] ARM TLS shouldn't use relaxations
authorPeter Smith <peter.smith@linaro.org>
Fri, 23 Sep 2016 13:54:48 +0000 (13:54 +0000)
committerPeter Smith <peter.smith@linaro.org>
Fri, 23 Sep 2016 13:54:48 +0000 (13:54 +0000)
The ARM TLS relocations are placed on literal data and not the
code-sequence, it is therefore not possible to implement the relaxTls*
functions. This change updates handleMipsTlsRelocation() to
handleNoRelaxTlsRelocation() and incorporates ARM as well as Mips.

The ARM support in handleNoRelaxTlsRelocation() currently needs to ouput
the module index dynamic relocation in all cases as it is relying on the
dynamic linker to set the module index in the got.

Should address PR30218

Differential Revision: https://reviews.llvm.org/D24827

llvm-svn: 282250

lld/ELF/Relocations.cpp
lld/test/ELF/Inputs/arm-tls-get-addr.s [new file with mode: 0644]
lld/test/ELF/arm-tls-norelax-gd-ie.s [new file with mode: 0644]
lld/test/ELF/arm-tls-norelax-gd-le.s [new file with mode: 0644]
lld/test/ELF/arm-tls-norelax-ie-le.s [new file with mode: 0644]
lld/test/ELF/arm-tls-norelax-ld-le.s [new file with mode: 0644]

index 2dce30a..61fb1dd 100644 (file)
@@ -83,32 +83,40 @@ static bool isPreemptible(const SymbolBody &Body, uint32_t Type) {
   return Body.isPreemptible();
 }
 
-// This function is similar to the `handleTlsRelocation`. MIPS does not support
-// any relaxations for TLS relocations so by factoring out MIPS handling into
-// the separate function we can simplify the code and does not pollute
-// `handleTlsRelocation` by MIPS `ifs` statements.
+// 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
+// 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>
-static unsigned
-handleMipsTlsRelocation(uint32_t Type, SymbolBody &Body,
-                        InputSectionBase<ELFT> &C, typename ELFT::uint Offset,
-                        typename ELFT::uint Addend, RelExpr Expr) {
-  if (Expr == R_MIPS_TLSLD) {
-    if (Out<ELFT>::Got->addTlsIndex() && Config->Pic)
+static unsigned handleNoRelaxTlsRelocation(uint32_t Type, SymbolBody &Body,
+                                           InputSectionBase<ELFT> &C,
+                                           typename ELFT::uint Offset,
+                                           typename ELFT::uint Addend,
+                                           RelExpr Expr) {
+  if (Expr == R_MIPS_TLSLD || Expr == R_TLSLD_PC) {
+    if (Out<ELFT>::Got->addTlsIndex() &&
+        (Config->Pic || Config->EMachine == EM_ARM))
       Out<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, Out<ELFT>::Got,
                                     Out<ELFT>::Got->getTlsIndexOff(), false,
                                     nullptr, 0});
     C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
     return 1;
   }
+  typedef typename ELFT::uint uintX_t;
   if (Target->isTlsGlobalDynamicRel(Type)) {
-    if (Out<ELFT>::Got->addDynTlsEntry(Body) && Body.isPreemptible()) {
-      typedef typename ELFT::uint uintX_t;
+    if (Out<ELFT>::Got->addDynTlsEntry(Body) &&
+        (Body.isPreemptible() || Config->EMachine == EM_ARM)) {
       uintX_t Off = Out<ELFT>::Got->getGlobalDynOffset(Body);
       Out<ELFT>::RelaDyn->addReloc(
           {Target->TlsModuleIndexRel, Out<ELFT>::Got, Off, false, &Body, 0});
-      Out<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, Out<ELFT>::Got,
-                                    Off + (uintX_t)sizeof(uintX_t), false,
-                                    &Body, 0});
+      if (Body.isPreemptible())
+        Out<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, Out<ELFT>::Got,
+                                      Off + (uintX_t)sizeof(uintX_t), false,
+                                      &Body, 0});
     }
     C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
     return 1;
@@ -130,8 +138,9 @@ static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
 
   typedef typename ELFT::uint uintX_t;
 
-  if (Config->EMachine == EM_MIPS)
-    return handleMipsTlsRelocation<ELFT>(Type, Body, C, Offset, Addend, Expr);
+  if (Config->EMachine == EM_MIPS || Config->EMachine == EM_ARM)
+    return handleNoRelaxTlsRelocation<ELFT>(Type, Body, C, Offset, Addend,
+                                            Expr);
 
   if ((Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE || Expr == R_HINT) &&
       Config->Shared) {
diff --git a/lld/test/ELF/Inputs/arm-tls-get-addr.s b/lld/test/ELF/Inputs/arm-tls-get-addr.s
new file mode 100644 (file)
index 0000000..f3212ad
--- /dev/null
@@ -0,0 +1,13 @@
+ .syntax unified
+ .text
+ .globl __tls_get_addr
+ .type __tls_get_addr,%function
+__tls_get_addr:
+ bx lr
+
+.section       .tbss,"awT",%nobits
+ .p2align  2
+y:
+ .space 4
+ .globl y
+ .type  y, %object
diff --git a/lld/test/ELF/arm-tls-norelax-gd-ie.s b/lld/test/ELF/arm-tls-norelax-gd-ie.s
new file mode 100644 (file)
index 0000000..3bd3db0
--- /dev/null
@@ -0,0 +1,30 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %p/Inputs/arm-tls-get-addr.s -o %t1
+// 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
+// REQUIRES: arm
+
+// This tls global-dynamic sequence is with respect to a preemptible symbol but
+// is in an application so a relaxation to Initial Exec would normally be
+// possible. This would result in an assertion failure on ARM as the
+// relaxation functions can't be implemented on ARM. Check that the sequence
+// is handled as global dynamic
+
+ .text
+ .syntax unified
+ .globl  func
+ .p2align        2
+ .type   func,%function
+func:
+.L0:
+ .globl __tls_get_addr
+ bl __tls_get_addr
+ bx lr
+ .p2align 2
+ .Lt0: .word   y(TLSGD) + (. - .L0 - 8)
+
+// CHECK: Dynamic Relocations {
+// CHECK-NEXT:   0x12078 R_ARM_TLS_DTPMOD32 y
+// CHECK-NEXT:   0x1207C R_ARM_TLS_DTPOFF32 y
+// CHECK-NEXT:   0x1300C R_ARM_JUMP_SLOT __tls_get_addr
diff --git a/lld/test/ELF/arm-tls-norelax-gd-le.s b/lld/test/ELF/arm-tls-norelax-gd-le.s
new file mode 100644 (file)
index 0000000..f573990
--- /dev/null
@@ -0,0 +1,37 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %p/Inputs/arm-tls-get-addr.s -o %t1
+// 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
+// REQUIRES: arm
+
+// This tls global-dynamic sequence is with respect to a non-preemptible
+// symbol in an application so a relaxation to Local Exec would normally be
+// possible. This would result in an assertion failure on ARM as the
+// relaxation functions can't be implemented on ARM. Check that the sequence
+// is handled as global dynamic
+
+ .text
+ .syntax unified
+ .globl  func
+ .p2align        2
+ .type   func,%function
+func:
+.L0:
+ .globl __tls_get_addr
+ bl __tls_get_addr
+ bx lr
+ .p2align 2
+ .Lt0: .word   x(TLSGD) + (. - .L0 - 8)
+
+ .globl  x
+.section       .tbss,"awT",%nobits
+ .p2align  2
+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
+
diff --git a/lld/test/ELF/arm-tls-norelax-ie-le.s b/lld/test/ELF/arm-tls-norelax-ie-le.s
new file mode 100644 (file)
index 0000000..2e7fc39
--- /dev/null
@@ -0,0 +1,41 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %p/Inputs/arm-tls-get-addr.s -o %t1
+// 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
+// REQUIRES: arm
+
+// This tls Initial Exec sequence is with respect to a non-preemptible symbol
+// so a relaxation would normally be possible. This would result in an assertion
+// failure on ARM as the relaxation functions can't be implemented on ARM.
+// Check that the sequence is handled as initial exec
+ .text
+ .syntax unified
+ .globl  func
+ .p2align        2
+ .type   func,%function
+func:
+.L0:
+ .globl __tls_get_addr
+ bl __tls_get_addr
+.L1:
+ bx lr
+ .p2align 2
+ .Lt0: .word  x1(gottpoff) + (. - .L0 - 8)
+ .Lt1: .word  x2(gottpoff) + (. - .L1 - 8)
+
+ .globl  x1
+ .section       .trw,"awT",%progbits
+ .p2align  2
+x1:
+ .word 0x1
+ .globl x2
+ .section       .tbss,"awT",%nobits
+ .type  x1, %object
+x2:
+ .space 4
+ .type x2, %object
+
+// CHECK: Contents of section .got
+// x1 at offset 0 from TP, x2 at offset 4 from TP
+// 12064 00000000 04000000
diff --git a/lld/test/ELF/arm-tls-norelax-ld-le.s b/lld/test/ELF/arm-tls-norelax-ld-le.s
new file mode 100644 (file)
index 0000000..61472ac
--- /dev/null
@@ -0,0 +1,36 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %p/Inputs/arm-tls-get-addr.s -o %t1
+// 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
+// REQUIRES: arm
+
+ .global __tls_get_addr
+ .text
+ .p2align  2
+ .global _start
+ .syntax unified
+ .arm
+ .type   _start, %function
+_start:
+.L0:
+ bl __tls_get_addr
+
+ .word   x(tlsldm) + (. - .L0 - 8)
+ .word   x(tlsldo)
+ .word   y(tlsldo)
+
+ .section        .tbss,"awT",%nobits
+ .p2align  2
+ .type   y, %object
+y:
+ .space  4
+ .section        .tdata,"awT",%progbits
+ .p2align  2
+ .type   x, %object
+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