Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -197,7 +197,8 @@ continue; } - if (Target->isTlsGlobalDynamicRel(Type) && + if ((Target->isTlsGlobalDescDynamicRel(Type) || + Target->isTlsGlobalDynamicRel(Type)) && !Target->canRelaxTls(Type, Body)) { Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, Out::Got->getGlobalDynAddr(*Body) + Index: ELF/Target.h =================================================================== --- ELF/Target.h +++ ELF/Target.h @@ -24,6 +24,7 @@ uint64_t getVAStart() const; virtual bool isTlsLocalDynamicRel(unsigned Type) const; virtual bool isTlsGlobalDynamicRel(unsigned Type) const; + virtual bool isTlsGlobalDescDynamicRel(unsigned Type) const; virtual unsigned getDynRel(unsigned Type) const { return Type; } virtual bool isTlsDynRel(unsigned Type, const SymbolBody &S) const; virtual unsigned getTlsGotRel(unsigned Type) const { return TlsGotRel; } @@ -87,6 +88,7 @@ unsigned TlsGotRel = 0; unsigned TlsModuleIndexRel; unsigned TlsOffsetRel; + unsigned TlsDescRel = 0; unsigned PltEntrySize = 8; unsigned PltZeroSize = 0; unsigned GotHeaderEntriesNum = 0; Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -175,7 +175,7 @@ public: AArch64TargetInfo(); unsigned getDynRel(unsigned Type) const override; - bool isTlsGlobalDynamicRel(unsigned Type) const override; + bool isTlsGlobalDescDynamicRel(unsigned Type) const override; void writeGotPlt(uint8_t *Buf, uint64_t Plt) const override; void writePltZero(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr, @@ -298,6 +298,10 @@ return false; } +bool TargetInfo::isTlsGlobalDescDynamicRel(unsigned Type) const { + return false; +} + unsigned TargetInfo::relaxTls(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, uint64_t SA, const SymbolBody *S) const { @@ -1209,12 +1213,13 @@ TlsGotRel = R_AARCH64_TLS_TPREL64; TlsModuleIndexRel = R_AARCH64_TLS_DTPMOD64; TlsOffsetRel = R_AARCH64_TLS_DTPREL64; + TlsDescRel = R_AARCH64_TLSDESC; UseLazyBinding = true; PltEntrySize = 16; PltZeroSize = 32; } -bool AArch64TargetInfo::isTlsGlobalDynamicRel(unsigned Type) const { +bool AArch64TargetInfo::isTlsGlobalDescDynamicRel(unsigned Type) const { return Type == R_AARCH64_TLSDESC_ADR_PAGE21 || Type == R_AARCH64_TLSDESC_LD64_LO12_NC || Type == R_AARCH64_TLSDESC_ADD_LO12_NC || @@ -1283,12 +1288,10 @@ } bool AArch64TargetInfo::isTlsDynRel(unsigned Type, const SymbolBody &S) const { - return Type == R_AARCH64_TLSDESC_ADR_PAGE21 || - Type == R_AARCH64_TLSDESC_LD64_LO12_NC || - Type == R_AARCH64_TLSDESC_ADD_LO12_NC || - Type == R_AARCH64_TLSDESC_CALL || - Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 || - Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC; + if (Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 || + Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC) + return canBePreempted(&S, true); + return false; } bool AArch64TargetInfo::needsDynRelative(unsigned Type) const { @@ -1324,6 +1327,9 @@ case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: case R_AARCH64_ADR_GOT_PAGE: case R_AARCH64_LD64_GOT_LO12_NC: + case R_AARCH64_TLSDESC_ADR_PAGE21: + case R_AARCH64_TLSDESC_LD64_LO12_NC: + case R_AARCH64_TLSDESC_ADD_LO12_NC: return true; default: return needsPlt(Type, S); @@ -1344,6 +1350,10 @@ if (canBePreempted(&S, true)) return Plt_Explicit; return Plt_No; + case R_AARCH64_TLSDESC_ADR_PAGE21: + case R_AARCH64_TLSDESC_LD64_LO12_NC: + case R_AARCH64_TLSDESC_ADD_LO12_NC: + return Plt_Explicit; } } @@ -1381,6 +1391,7 @@ write64le(Loc, SA); break; case R_AARCH64_ADD_ABS_LO12_NC: + case R_AARCH64_TLSDESC_ADD_LO12_NC: // This relocation stores 12 bits and there's no instruction // to do it. Instead, we do a 32 bits store of the value // of r_addend bitwise-or'ed Loc. This assumes that the addend @@ -1400,7 +1411,8 @@ break; } case R_AARCH64_ADR_PREL_PG_HI21: - case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: { + case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: + case R_AARCH64_TLSDESC_ADR_PAGE21: { uint64_t X = getAArch64Page(SA) - getAArch64Page(P); checkInt<33>(X, Type); updateAArch64Addr(Loc, (X >> 12) & 0x1FFFFF); // X[32:12] @@ -1421,6 +1433,7 @@ } case R_AARCH64_LD64_GOT_LO12_NC: case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: + case R_AARCH64_TLSDESC_LD64_LO12_NC: checkAlignment<8>(SA, Type); or32le(Loc, (SA & 0xFF8) << 7); break; @@ -1467,6 +1480,8 @@ updateAArch64Add(Loc, V & 0xFFF); break; } + case R_AARCH64_TLSDESC_CALL: + break; default: fatal("unrecognized reloc " + Twine(Type)); } @@ -1479,7 +1494,7 @@ // Global-Dynamic relocs can be relaxed to Initial-Exec if the target is // an executable. And if the target is local it can also be fully relaxed to // Local-Exec. - if (isTlsGlobalDynamicRel(Type)) + if (isTlsGlobalDescDynamicRel(Type)) return !canBePreempted(S, true); // Initial-Exec relocs can be relaxed to Local-Exec if the target is a local Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -252,7 +252,16 @@ if (!Body || !Body->isTls()) return false; - if (Target->isTlsGlobalDynamicRel(Type)) { + if (Target->isTlsGlobalDescDynamicRel(Type)) { + if (!Target->canRelaxTls(Type, Body) && + Out::Got->addDynTlsEntry(Body)) { + Out::RelaDyn->addReloc( + {Target->TlsDescRel, DynamicReloc::Off_GTlsIndex, Body}); + return true; + } + if (!canBePreempted(Body, true)) + return true; + } else if (Target->isTlsGlobalDynamicRel(Type)) { if (!Target->canRelaxTls(Type, Body) && Out::Got->addDynTlsEntry(Body)) { Out::RelaDyn->addReloc( @@ -264,6 +273,7 @@ if (!canBePreempted(Body, true)) return true; } + return !Target->isTlsDynRel(Type, *Body); } Index: test/ELF/aarch64-tls-tlsdesc.s =================================================================== --- /dev/null +++ test/ELF/aarch64-tls-tlsdesc.s @@ -0,0 +1,36 @@ +# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %s -o %t.o +# RUN: ld.lld -shared %t.o -o %tout.so +# RUN: llvm-objdump -d %tout.so | FileCheck %s +# RUN: llvm-readobj -s -r %tout.so | FileCheck -check-prefix=RELOC %s +# REQUIRES: aarch64 + +# It references to an external __thread variable in PIC mode so +# no relax is possible. Linker should create a dynamic R_AARCH64_TLSDESC +# relocation against t1. + +#RELOC: Relocations [ +#RELOC-NEXT: {{.*}} .rela.dyn { +#RELOC-NEXT: {{.*}} R_AARCH64_TLSDESC t1 + +#CHECK: 1000: fd 7b bf a9 stp x29, x30, [sp, #-16]! +#CHECK: 1004: fd 03 00 91 mov x29, sp +#CHECK: 1008: 00 00 00 b0 adrp x0, #4096 +#CHECK: 100c: 01 48 40 f9 ldr x1, [x0, #144] +#CHECK: 1010: 00 40 02 91 add x0, x0, #144 +#CHECK: 1014: 20 00 3f d6 blr x1 + + +.global f1 +.type f1, %function +f1: + stp x29, x30, [sp, -16]! + add x29, sp, 0 + adrp x0, :tlsdesc:t1 + ldr x1, [x0, #:tlsdesc_lo12:t1] + add x0, x0, :tlsdesc_lo12:t1 + .tlsdesccall t1 + blr x1 + mrs x1, tpidr_el0 + ldr w0, [x1,x0] + ldp x29, x30, [sp], 16 + ret