diff --git a/lib/Target/AArch64/AArch64Relocator.cpp b/lib/Target/AArch64/AArch64Relocator.cpp index cc9d26147..a8149e0ca 100644 --- a/lib/Target/AArch64/AArch64Relocator.cpp +++ b/lib/Target/AArch64/AArch64Relocator.cpp @@ -4,7 +4,6 @@ // SPDX-License-Identifier: BSD-3-Clause //===----------------------------------------------------------------------===// - #include "AArch64Relocator.h" #include "AArch64InsnHelpers.h" #include "AArch64PLT.h" @@ -52,8 +51,7 @@ static uint64_t getSigningSchema(const Relocation &pReloc) { /// helper_DynRel - Get an relocation entry in .rela.dyn Relocation *helper_DynRel_init(ELFObjectFile *Obj, Relocation *R, ResolveInfo *pSym, Fragment *F, uint32_t pOffset, - Relocator::Type pType, - AArch64LDBackend &B) { + Relocator::Type pType, AArch64LDBackend &B) { Relocation *rela_entry = nullptr; if (pType == R_AARCH64_TLSDESC) @@ -190,9 +188,8 @@ bool AArch64Relocator::relocNeedsDynRel(Relocation &pReloc) const { pReloc.type() == llvm::ELF::R_AARCH64_ABS32 || pReloc.type() == llvm::ELF::R_AARCH64_ABS16 || pReloc.type() == llvm::ELF::R_AARCH64_AUTH_ABS64; - return getTarget().symbolNeedsDynRel( - *rsym, (rsym->reserved() & ReservePLT), - isAbsReloc); + return getTarget().symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT), + isAbsReloc); } Relocator::Result AArch64Relocator::applyRelocation(Relocation &pRelocation) { @@ -252,12 +249,10 @@ void AArch64Relocator::scanLocalReloc(InputFile &pInput, Relocation &pReloc, rsym->setReserved(rsym->reserved() | ReserveRel); getTarget().checkAndSetHasTextRel(pSection); // set up the dyn rel directly - Relocation::Type relType = - isAuthAbs ? llvm::ELF::R_AARCH64_AUTH_RELATIVE - : llvm::ELF::R_AARCH64_RELATIVE; + Relocation::Type relType = isAuthAbs ? llvm::ELF::R_AARCH64_AUTH_RELATIVE + : llvm::ELF::R_AARCH64_RELATIVE; helper_DynRel_init(Obj, &pReloc, rsym, pReloc.targetRef()->frag(), - pReloc.targetRef()->offset(), relType, - m_Target); + pReloc.targetRef()->offset(), relType, m_Target); } } return; @@ -330,6 +325,14 @@ void AArch64Relocator::scanLocalReloc(InputFile &pInput, Relocation &pReloc, G->setValueType(GOT::TLSStaticSymbolValue); return; } + if (config().options().isPIE()) { + // PIE executable: relax TLSDESC to IE + AArch64GOT *G = m_Target.createGOT(GOT::TLS_IE, Obj, rsym); + helper_DynRel_init(Obj, &pReloc, rsym, G, 0x0, + llvm::ELF::R_AARCH64_TLS_TPREL64, m_Target); + rsym->setReserved(rsym->reserved() | ReserveGOT); + return; + } AArch64GOT *G = m_Target.createGOT(GOT::TLS_DESC, Obj, rsym); helper_DynRel_init(Obj, &pReloc, rsym, G->getFirst(), 0x0, llvm::ELF::R_AARCH64_TLSDESC, m_Target); @@ -382,8 +385,8 @@ void AArch64Relocator::scanGlobalReloc(InputFile &pInput, Relocation &pReloc, // for signed pointers" if (isAuthAbs) { config().raise(Diag::non_pic_relocation) - << getName(pReloc.type()) << pReloc.symInfo()->name() - << pReloc.getSourcePath(config().options()); + << getName(pReloc.type()) << pReloc.symInfo()->name() + << pReloc.getSourcePath(config().options()); m_Target.getModule().setFailure(true); return; } @@ -409,10 +412,8 @@ void AArch64Relocator::scanGlobalReloc(InputFile &pInput, Relocation &pReloc, relType = isAuthAbs ? llvm::ELF::R_AARCH64_AUTH_RELATIVE : llvm::ELF::R_AARCH64_RELATIVE; } - helper_DynRel_init( - Obj, &pReloc, rsym, pReloc.targetRef()->frag(), - pReloc.targetRef()->offset(), - relType, m_Target); + helper_DynRel_init(Obj, &pReloc, rsym, pReloc.targetRef()->frag(), + pReloc.targetRef()->offset(), relType, m_Target); } } } @@ -562,6 +563,14 @@ void AArch64Relocator::scanGlobalReloc(InputFile &pInput, Relocation &pReloc, G->setValueType(GOT::TLSStaticSymbolValue); return; } + if (config().options().isPIE()) { + // PIE executable: relax TLSDESC to IE + AArch64GOT *G = m_Target.createGOT(GOT::TLS_IE, Obj, rsym); + helper_DynRel_init(Obj, &pReloc, rsym, G, 0x0, + llvm::ELF::R_AARCH64_TLS_TPREL64, m_Target); + rsym->setReserved(rsym->reserved() | ReserveGOT); + return; + } AArch64GOT *G = m_Target.createGOT(GOT::TLS_DESC, Obj, rsym); helper_DynRel_init(Obj, &pReloc, rsym, G->getFirst(), 0x0, llvm::ELF::R_AARCH64_TLSDESC, m_Target); @@ -1023,7 +1032,8 @@ Relocator::Result ld64_got_lo12(Relocation &pReloc, AArch64Relocator &pParent) { } // R_AARCH64_LD64_GOTPAGE_LO15: G(GDAT(S)) - Page(GOT) -Relocator::Result ld64_gotpage_lo15(Relocation &pReloc, AArch64Relocator &pParent) { +Relocator::Result ld64_gotpage_lo15(Relocation &pReloc, + AArch64Relocator &pParent) { if (!(pReloc.symInfo()->reserved() & Relocator::ReserveGOT)) { return Relocator::BadReloc; } @@ -1148,7 +1158,8 @@ Relocator::Result tls_gottprel_page(Relocation &pReloc, DiagnosticEngine *DiagEngine = pParent.config().getDiagEngine(); Relocator::DWord A = pReloc.addend(); - if (!(pReloc.symInfo()->reserved() & Relocator::ReserveGOT)) { + if (!(pReloc.symInfo()->reserved() & Relocator::ReserveGOT) || + pParent.config().isCodeStatic()) { Relocator::DWord X = pParent.getSymValue(&pReloc) + AArch64LDBackend::getStaticTCBSize(); // Convert to movz @@ -1173,7 +1184,8 @@ Relocator::Result tls_gottprel_lo(Relocation &pReloc, AArch64Relocator &pParent) { Relocator::DWord A = pReloc.addend(); - if (!(pReloc.symInfo()->reserved() & Relocator::ReserveGOT)) { + if (!(pReloc.symInfo()->reserved() & Relocator::ReserveGOT) || + pParent.config().isCodeStatic()) { Relocator::DWord X = pParent.getSymValue(&pReloc) + AArch64LDBackend::getStaticTCBSize(); // Convert to movk @@ -1216,7 +1228,8 @@ Relocator::Result tls_tlsdesc_page(Relocation &pReloc, AArch64Relocator &pParent) { Relocator::DWord A = pReloc.addend(); - if (!(pReloc.symInfo()->reserved() & Relocator::ReserveGOT)) { + if (!(pReloc.symInfo()->reserved() & Relocator::ReserveGOT) || + pParent.config().isCodeStatic()) { Relocator::DWord X = pParent.getSymValue(&pReloc) + AArch64LDBackend::getStaticTCBSize(); // Convert to movz @@ -1241,26 +1254,28 @@ Relocator::Result tls_tlsdesc_page(Relocation &pReloc, Relocator::Result tls_tlsdesc_lo(Relocation &pReloc, AArch64Relocator &pParent) { Relocator::DWord A = pReloc.addend(); - - if (!(pReloc.symInfo()->reserved() & Relocator::ReserveGOT)) { + if (!(pReloc.symInfo()->reserved() & Relocator::ReserveGOT) || + pParent.config().isCodeStatic()) { Relocator::DWord X = pParent.getSymValue(&pReloc) + AArch64LDBackend::getStaticTCBSize(); - // Convert to movk, save to x0 uint32_t movk = 0xF2800000; pReloc.target() = helper_reencode_movzk_imm(movk, X); return Relocator::OK; } - + if (pParent.config().options().isPIE()) { + uint32_t insn = 0xF9400000; // ldr x0, [x0, #0] + Relocator::Address GOT_S = pParent.getTarget() + .findEntryInGOT(pReloc.symInfo()) + ->getAddr(pParent.config().getDiagEngine()); + Relocator::DWord GX = helper_get_page_offset(GOT_S + A); + pReloc.target() = helper_reencode_ldst_pos_imm(insn, GX >> 3); + return Relocator::OK; + } Relocator::Address GOT_S = pParent.getTarget() .findEntryInGOT(pReloc.symInfo()) ->getAddr(pParent.config().getDiagEngine()); Relocator::DWord GX = helper_get_page_offset(GOT_S + A); pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), GX >> 3); - - // Convert Rt to X0 if static - if (pParent.config().isCodeStatic()) - pReloc.target() = pReloc.target() & ~0x1F; - return Relocator::OK; } @@ -1268,7 +1283,7 @@ Relocator::Result tls_tlsdesc_lo(Relocation &pReloc, Relocator::Result tls_tlsdesc_add(Relocation &pReloc, AArch64Relocator &pParent) { Relocator::DWord A = pReloc.addend(); - if (pParent.config().isCodeStatic()) { + if (pParent.config().isCodeStatic() || pParent.config().options().isPIE()) { // Convert to nop pReloc.target() = 0xD503201F; return Relocator::OK; @@ -1285,7 +1300,7 @@ Relocator::Result tls_tlsdesc_add(Relocation &pReloc, // R_AARCH64_TLSDESC_CALL Relocator::Result tls_call(Relocation &pReloc, AArch64Relocator &pParent) { - if (pParent.config().isCodeStatic()) { + if (pParent.config().isCodeStatic() || pParent.config().options().isPIE()) { // Convert to nop pReloc.target() = 0xD503201F; return Relocator::OK; diff --git a/test/AArch64/standalone/TLS_DESC/DESC.test b/test/AArch64/standalone/TLS_DESC/DESC.test index 6adac0826..e02a8ee71 100644 --- a/test/AArch64/standalone/TLS_DESC/DESC.test +++ b/test/AArch64/standalone/TLS_DESC/DESC.test @@ -1,10 +1,14 @@ RUN: %clangas %clangasopts -filetype obj -target-cpu generic -target-feature +neon -mrelax-all %p/Inputs/t.s -o %t.o -RUN: %link %linkopts -march aarch64 -static %t.o -z max-page-size=0x1000 -o %t.out +RUN: %link %linkopts -march aarch64 -static -z max-page-size=0x1000 %t.o -o %t.out RUN: llvm-objdump -d %t.out | %filecheck %s -#CHECK: {{.*}} <_test_tls_desc>: -#CHECK: {{.*}} adrp x0, 0x1000 -#CHECK: {{.*}} ldr x0, [x0] -#CHECK: {{.*}} <_test_tls_desc_local>: -#CHECK: {{.*}} adrp x0, 0x1000 -#CHECK: {{.*}} ldr x0, [x0, #0x8] +CHECK: _test_tls_desc +CHECK: d2a00000 movz +CHECK: f2800200 movk +CHECK: d503201f nop +CHECK: d503201f nop +CHECK: _test_tls_desc_local +CHECK: d2a00000 movz +CHECK: f2800280 movk +CHECK: d503201f nop +CHECK: d503201f nop \ No newline at end of file diff --git a/test/AArch64/standalone/TLS_DESC/TLS_DESC.test b/test/AArch64/standalone/TLS_DESC/TLS_DESC.test new file mode 100644 index 000000000..f5096958b --- /dev/null +++ b/test/AArch64/standalone/TLS_DESC/TLS_DESC.test @@ -0,0 +1,14 @@ +RUN: %clangas %clangasopts -filetype obj -target-cpu generic -target-feature +neon -mrelax-all %p/Inputs/t.s -o %t.o +RUN: %link %linkopts -march aarch64 -static -z max-page-size=0x1000 %t.o -o %t.out +RUN: llvm-objdump -d %t.out | %filecheck %s + +CHECK: _test_tls_desc +CHECK: d2a00000 movz +CHECK: f2800200 movk +CHECK: d503201f nop +CHECK: d503201f nop +CHECK: _test_tls_desc_local +CHECK: d2a00000 movz +CHECK: f2800280 movk +CHECK: d503201f nop +CHECK: d503201f nop diff --git a/test/AArch64/standalone/TLS_DESC/TLS_DESC_PIE.test b/test/AArch64/standalone/TLS_DESC/TLS_DESC_PIE.test new file mode 100644 index 000000000..1fa4ae261 --- /dev/null +++ b/test/AArch64/standalone/TLS_DESC/TLS_DESC_PIE.test @@ -0,0 +1,14 @@ +RUN: %clangas %clangasopts -filetype obj -target-cpu generic -target-feature +neon -mrelax-all %p/Inputs/t.s -o %t.o +RUN: %link %linkopts -march aarch64 -pie -z max-page-size=0x1000 %t.o -o %t.out +RUN: llvm-objdump -d %t.out | %filecheck %s + +CHECK: _test_tls_desc +CHECK: b0000000 adrp +CHECK: f9408000 ldr +CHECK: d503201f nop +CHECK: d503201f nop +CHECK: _test_tls_desc_local +CHECK: b0000000 adrp +CHECK: f9408400 ldr +CHECK: d503201f nop +CHECK: d503201f nop diff --git a/test/AArch64/standalone/TLS_IE/IE.test b/test/AArch64/standalone/TLS_IE/IE.test index e5b0050ef..600ccedf9 100644 --- a/test/AArch64/standalone/TLS_IE/IE.test +++ b/test/AArch64/standalone/TLS_IE/IE.test @@ -8,8 +8,8 @@ RUN: %clang %clangopts -target aarch64 %p/Inputs/f.c -c -o %t3.o RUN: %link %linkopts -static -march aarch64 %t2.o %t3.o -z max-page-size=0x1000 -o %t2.out CHECK: _test_tls_IE -CHECK: b0000000 adrp -CHECK: f9400000 ldr +CHECK: d2a00000 movz +CHECK: f2800200 movk CHECK: _test_tls_IE_local CHECK: d2a00000 movz CHECK: f2800280 movk diff --git a/test/AArch64/standalone/TLS_IE_PIE/IE_PIE.test b/test/AArch64/standalone/TLS_IE_PIE/IE_PIE.test new file mode 100644 index 000000000..4d19529c5 --- /dev/null +++ b/test/AArch64/standalone/TLS_IE_PIE/IE_PIE.test @@ -0,0 +1,12 @@ +# Verify that IE TLS relocations remain as GOT-indirect adrp+ldr +# in PIE executables (IE stays as IE, no relaxation to LE). +RUN: %clangas %clangasopts -filetype obj -target-cpu generic -target-feature +neon -mrelax-all %p/Inputs/ie.s -o %t.o +RUN: %link %linkopts -march aarch64 -pie -z max-page-size=0x1000 %t.o -o %t.out +RUN: llvm-objdump -d %t.out | %filecheck %s + +CHECK: _test_tls_IE +CHECK: b0000000 adrp +CHECK: f9408000 ldr +CHECK: _test_tls_IE_local +CHECK: b0000000 adrp +CHECK: f9408400 ldr diff --git a/test/AArch64/standalone/TLS_IE_PIE/Inputs/ie.s b/test/AArch64/standalone/TLS_IE_PIE/Inputs/ie.s new file mode 100644 index 000000000..e647b896d --- /dev/null +++ b/test/AArch64/standalone/TLS_IE_PIE/Inputs/ie.s @@ -0,0 +1,29 @@ + .global tlsievar + .section .tbss,"awT",%nobits + .align 2 + .type tlsievar, %object + .size tlsievar, 4 +tlsievar: + .zero 4 + + .align 2 + .type l_tlsievar, %object + .size l_tlsievar, 4 +l_tlsievar: + .zero 4 + +.text +_test_tls_IE: + + // R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 tlsievar + adrp x0, :gottprel:tlsievar + // R_AARCH64_TLSIE_GOTTPREL_LO12_NC tlsievar + ldr x0, [x0, :gottprel_lo12:tlsievar] + +_test_tls_IE_local: + + // R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 l_tlsievar + adrp x0, :gottprel:l_tlsievar + // R_AARCH64_TLSIE_GOTTPREL_LO12_NC l_tlsievar + ldr x0, [x0, :gottprel_lo12:l_tlsievar] + diff --git a/test/AArch64/standalone/TLS_Relaxation_Verify/Inputs/tls_test.c b/test/AArch64/standalone/TLS_Relaxation_Verify/Inputs/tls_test.c new file mode 100644 index 000000000..1bd9ed945 --- /dev/null +++ b/test/AArch64/standalone/TLS_Relaxation_Verify/Inputs/tls_test.c @@ -0,0 +1,10 @@ +/* Verify TLS relaxations for AArch64. + * Global-dynamic (TLSDESC) should be relaxed to: + * - Local Exec (movz+movk) for static executables + * - Initial Exec (adrp+ldr) for PIE executables + */ +__thread int tls_global = 42; +static __thread int tls_local = 100; + +int get_global() { return tls_global; } +int get_local() { return tls_local; } diff --git a/test/AArch64/standalone/TLS_Relaxation_Verify/TLS_Relaxation_Verify.test b/test/AArch64/standalone/TLS_Relaxation_Verify/TLS_Relaxation_Verify.test new file mode 100644 index 000000000..2897debca --- /dev/null +++ b/test/AArch64/standalone/TLS_Relaxation_Verify/TLS_Relaxation_Verify.test @@ -0,0 +1,34 @@ +RUN: %clang %clangopts -target aarch64-unknown-none-elf \ +RUN: -ftls-model=global-dynamic -fPIC \ +RUN: -c %p/Inputs/tls_test.c -o %t.o +RUN: %link %linkopts -march aarch64 -static \ +RUN: -z max-page-size=0x1000 %t.o -o %t.static.out +RUN: llvm-objdump -d %t.static.out | %filecheck %s --check-prefix=STATIC +RUN: %link %linkopts -march aarch64 -pie \ +RUN: -z max-page-size=0x1000 %t.o -o %t.pie.out +RUN: llvm-objdump -d %t.pie.out | %filecheck %s --check-prefix=PIE +RUN: %readelf -r %t.pie.out | %filecheck %s --check-prefix=PIE-RELOC + +STATIC: : +STATIC: d2a00000 movz +STATIC: f2800200 movk +STATIC: d503201f nop +STATIC: d503201f nop +STATIC: : +STATIC: d2a00000 movz +STATIC: f2800280 movk +STATIC: d503201f nop +STATIC: d503201f nop + +PIE: : +PIE: b0000000 adrp +PIE: f9408400 ldr +PIE: d503201f nop +PIE: d503201f nop +PIE: : +PIE: b0000000 adrp +PIE: f9408800 ldr +PIE: d503201f nop +PIE: d503201f nop + +PIE-RELOC: R_AARCH64_TLS_TPREL64