Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -177,6 +177,8 @@ uint64_t SA) const override; bool refersToGotEntry(uint32_t Type, const SymbolBody &) const override; + size_t relaxTlsGdToIe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, + uint64_t P, uint64_t SA) const override; size_t relaxTlsGdToLe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, uint64_t SA) const override; size_t relaxTlsIeToLe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, @@ -1406,6 +1408,8 @@ } bool AArch64TargetInfo::needsGot(uint32_t Type, const SymbolBody &S) const { + if (isTlsDescRel(Type)) + return S.isPreemptible(); return refersToGotEntry(Type, S) || needsPlt(Type, S); } @@ -1598,6 +1602,54 @@ return 0; } +// Global-Dynamic relocations can be relaxed to Initial-Exec if both binary is +// an executable and target is not final (can be preempted). +size_t AArch64TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint8_t *BufEnd, + uint32_t Type, uint64_t P, + uint64_t SA) 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 [R_AARCH64_TLSDESC_ADD_LO12_NC] + // .tlsdesccall [R_AARCH64_TLSDESC_CALL] + // And it can optimized to: + // adrp x0, :tlsie:v + // ldr x0, [x0, :tlsie_lo12:v] + // nop + // nop + + // For Initial-Exec from Global-Dynamic TLS relax the idea is to emit + // a R_AARCH64_TLS_TPREL64 dynamic relocation and thus adjust the + // tlsdesc call to access the GOT slot adjusted by dynamic linker. + checkUInt<32>(SA, Type); + + switch (Type) { + case R_AARCH64_TLSDESC_ADD_LO12_NC: + case R_AARCH64_TLSDESC_CALL: + // nop + write32le(Loc, 0xD503201F); + break; + case R_AARCH64_TLSDESC_ADR_PAGE21: { + // adrp + uint64_t X = getAArch64Page(SA) - getAArch64Page(P); + updateAArch64Addr(Loc, (X >> 12) & 0x1FFFFF); // X[32:12] + return 0; + } + case R_AARCH64_TLSDESC_LD64_LO12_NC: { + // ldr with target register being 'x0' + uint32_t NewInst = read32le(Loc) & 0xFFFFFFE0; + NewInst |= (SA & 0xFF8) << 7; + write32le(Loc, NewInst); + break; + } + default: + llvm_unreachable("unsupported relocation for TLS GD to IE relaxation"); + } + return 0; +} + +// Initial-Exec relocations can be relaxed to Local-Exec if symbol is final +// (can not be preempted). size_t AArch64TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, uint64_t SA) const { Index: test/ELF/Inputs/aarch64-tls-ie.s =================================================================== --- test/ELF/Inputs/aarch64-tls-ie.s +++ test/ELF/Inputs/aarch64-tls-ie.s @@ -1,4 +1,3 @@ -.text .global foo .section .tdata,"awT",%progbits .align 2 @@ -8,7 +7,6 @@ .word 5 .text -.text .global bar .section .tdata,"awT",%progbits .align 2 Index: test/ELF/aarch64-tls-gdie.s =================================================================== --- /dev/null +++ test/ELF/aarch64-tls-gdie.s @@ -0,0 +1,30 @@ +# REQUIRES: aarch64 +# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %p/Inputs/aarch64-tls-ie.s -o %ttlsie.o +# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %s -o %tmain.o +# RUN: ld.lld -shared %ttlsie.o -o %t.so +# RUN: ld.lld %tmain.o -o %tout %t.so +# RUN: llvm-objdump -d %tout | FileCheck %s +# RUN: llvm-readobj -s -r %tout | FileCheck -check-prefix=RELOC %s + +# Global-Dynamic to Initial-Exec relax creates a R_AARCH64_TPREL64 +# RELOC: Relocations [ +# RELOC-NEXT: Section ({{.*}}) .rela.dyn { +# RELOC-NEXT: {{.*}} R_AARCH64_TLS_TPREL64 foo 0x0 +# RELOC-NEXT: } +# RELOC-NEXT: ] + +# CHECK: Disassembly of section .text: +# CHECK: _start: +# CHECK-NEXT: 11000: 00 00 00 b0 adrp x0, #4096 +# CHECK-NEXT: 11004: 00 58 40 f9 ldr x0, [x0, #176] +# CHECK-NEXT: 11008: 1f 20 03 d5 nop +# CHECK-NEXT: 1100c: 1f 20 03 d5 nop + +.text +.globl _start +_start: + adrp x0, :tlsdesc:foo + ldr x1, [x0, :tlsdesc_lo12:foo] + add x0, x0, :tlsdesc_lo12:foo + .tlsdesccall foo + blr x1