Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -200,6 +200,8 @@ private: void relocateTlsGdToLe(uint32_t Type, uint8_t *Loc, uint8_t *BufEnd, uint64_t P, uint64_t SA) const; + void relocateTlsGdToIe(uint32_t Type, uint8_t *Loc, uint8_t *BufEnd, + uint64_t P, uint64_t SA) const; void relocateTlsIeToLe(uint32_t Type, uint8_t *Loc, uint8_t *BufEnd, uint64_t P, uint64_t SA) const; @@ -1362,6 +1364,8 @@ if (Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC || Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) return true; + if (isTlsDescRel(Type, S)) + return canBePreempted(&S); return refersToGotEntry(Type) || needsPlt(Type, S); } @@ -1517,13 +1521,12 @@ case R_AARCH64_TLSDESC_ADR_PAGE21: case R_AARCH64_TLSDESC_LD64_LO12_NC: case R_AARCH64_TLSDESC_ADD_LO12_NC: - case R_AARCH64_TLSDESC_CALL: { + case R_AARCH64_TLSDESC_CALL: if (canBePreempted(S)) - fatal("Unsupported TLS optimization"); - uint64_t X = S ? S->getVA() : SA; - relocateTlsGdToLe(Type, Loc, BufEnd, P, X); + relocateTlsGdToIe(Type, Loc, BufEnd, P, SA); + else + relocateTlsGdToLe(Type, Loc, BufEnd, P, SA); return 0; - } case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: relocateTlsIeToLe(Type, Loc, BufEnd, P, S->getVA()); @@ -1576,6 +1579,51 @@ write32le(Loc, NewInst); } +// Global-Dynamic relocations can be relaxed to Initial-Exec if both binary is +// an executable and target is not final (can be preempted). +void AArch64TargetInfo::relocateTlsGdToIe(uint32_t Type, uint8_t *Loc, + uint8_t *BufEnd, 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; + } + 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"); + } +} + // Initial-Exec relocations can be relaxed to Local-Exec if symbol is final // (can not be preempted). void AArch64TargetInfo::relocateTlsIeToLe(uint32_t Type, uint8_t *Loc, 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: 11000: 00 00 00 b0 adrp x0, #4096 +# CHECK: 11004: 00 58 40 f9 ldr x0, [x0, #176] +# CHECK: 11008: 1f 20 03 d5 nop +# CHECK: 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