Index: lld/trunk/ELF/Relocations.cpp =================================================================== --- lld/trunk/ELF/Relocations.cpp +++ lld/trunk/ELF/Relocations.cpp @@ -83,32 +83,40 @@ 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 -static unsigned -handleMipsTlsRelocation(uint32_t Type, SymbolBody &Body, - InputSectionBase &C, typename ELFT::uint Offset, - typename ELFT::uint Addend, RelExpr Expr) { - if (Expr == R_MIPS_TLSLD) { - if (Out::Got->addTlsIndex() && Config->Pic) +static unsigned handleNoRelaxTlsRelocation(uint32_t Type, SymbolBody &Body, + InputSectionBase &C, + typename ELFT::uint Offset, + typename ELFT::uint Addend, + RelExpr Expr) { + if (Expr == R_MIPS_TLSLD || Expr == R_TLSLD_PC) { + if (Out::Got->addTlsIndex() && + (Config->Pic || Config->EMachine == EM_ARM)) Out::RelaDyn->addReloc({Target->TlsModuleIndexRel, Out::Got, Out::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::Got->addDynTlsEntry(Body) && Body.isPreemptible()) { - typedef typename ELFT::uint uintX_t; + if (Out::Got->addDynTlsEntry(Body) && + (Body.isPreemptible() || Config->EMachine == EM_ARM)) { uintX_t Off = Out::Got->getGlobalDynOffset(Body); Out::RelaDyn->addReloc( {Target->TlsModuleIndexRel, Out::Got, Off, false, &Body, 0}); - Out::RelaDyn->addReloc({Target->TlsOffsetRel, Out::Got, - Off + (uintX_t)sizeof(uintX_t), false, - &Body, 0}); + if (Body.isPreemptible()) + Out::RelaDyn->addReloc({Target->TlsOffsetRel, Out::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 @@ typedef typename ELFT::uint uintX_t; - if (Config->EMachine == EM_MIPS) - return handleMipsTlsRelocation(Type, Body, C, Offset, Addend, Expr); + if (Config->EMachine == EM_MIPS || Config->EMachine == EM_ARM) + return handleNoRelaxTlsRelocation(Type, Body, C, Offset, Addend, + Expr); if ((Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE || Expr == R_HINT) && Config->Shared) { Index: lld/trunk/test/ELF/Inputs/arm-tls-get-addr.s =================================================================== --- lld/trunk/test/ELF/Inputs/arm-tls-get-addr.s +++ lld/trunk/test/ELF/Inputs/arm-tls-get-addr.s @@ -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 Index: lld/trunk/test/ELF/arm-tls-norelax-gd-ie.s =================================================================== --- lld/trunk/test/ELF/arm-tls-norelax-gd-ie.s +++ lld/trunk/test/ELF/arm-tls-norelax-gd-ie.s @@ -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 Index: lld/trunk/test/ELF/arm-tls-norelax-gd-le.s =================================================================== --- lld/trunk/test/ELF/arm-tls-norelax-gd-le.s +++ lld/trunk/test/ELF/arm-tls-norelax-gd-le.s @@ -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 + Index: lld/trunk/test/ELF/arm-tls-norelax-ie-le.s =================================================================== --- lld/trunk/test/ELF/arm-tls-norelax-ie-le.s +++ lld/trunk/test/ELF/arm-tls-norelax-ie-le.s @@ -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 Index: lld/trunk/test/ELF/arm-tls-norelax-ld-le.s =================================================================== --- lld/trunk/test/ELF/arm-tls-norelax-ld-le.s +++ lld/trunk/test/ELF/arm-tls-norelax-ld-le.s @@ -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