Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -178,6 +178,8 @@ 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 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, @@ -1491,6 +1493,8 @@ GotPltEntrySize = 4; PltEntrySize = 16; PltHeaderSize = 20; + // ARM uses Variant 1 TLS + TcbSize = 8; } RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const { @@ -1514,8 +1518,13 @@ // 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) + - 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 @@ -1613,6 +1622,9 @@ case R_ARM_GOT_BREL: case R_ARM_GOT_PREL: case R_ARM_REL32: + case R_ARM_TLS_GD32: + case R_ARM_TLS_IE32: + case R_ARM_TLS_LE32: write32le(Loc, Val); break; case R_ARM_PREL31: @@ -1736,6 +1748,9 @@ case R_ARM_GOT_BREL: case R_ARM_GOT_PREL: case R_ARM_REL32: + case R_ARM_TLS_GD32: + case R_ARM_TLS_IE32: + case R_ARM_TLS_LE32: return SignExtend64<32>(read32le(Buf)); case R_ARM_PREL31: return SignExtend64<31>(read32le(Buf)); @@ -1793,6 +1808,14 @@ } } +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 MipsTargetInfo::MipsTargetInfo() { GotPltHeaderEntriesNum = 2; PageSize = 65536; Index: test/ELF/arm-tls-gd32.s =================================================================== --- /dev/null +++ test/ELF/arm-tls-gd32.s @@ -0,0 +1,160 @@ +// 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 +// 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 +// 0x1088 + 8 + 0x1f7c = 0x300c = __tls_get_addr +// 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 Index: test/ELF/arm-tls-ie32.s =================================================================== --- /dev/null +++ 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