https://github.com/kovdan01 updated https://github.com/llvm/llvm-project/pull/198327
>From 51e74d6bdcdd9c70aa7a87f5ce5174797b3af880 Mon Sep 17 00:00:00 2001 From: Daniil Kovalev <[email protected]> Date: Mon, 18 May 2026 18:41:23 +0300 Subject: [PATCH 1/2] [PAC][ELF] Support R_AARCH64_AUTH_TLSDESC_CALL relocation The R_AARCH64_AUTH_TLSDESC_CALL is introduced to allow linker relaxation of AUTH TLSDESC call sequences for non-preemptible undefined weak symbols. The lld patch introducing the relaxation: #194636 Corresponding ARM docs PR: https://github.com/ARM-software/abi-aa/pull/395 --- llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 15 ++++++++++++--- llvm/lib/Target/AArch64/AArch64InstrInfo.td | 8 ++++++++ .../AArch64/AsmParser/AArch64AsmParser.cpp | 17 +++++++++++------ .../MCTargetDesc/AArch64MCCodeEmitter.cpp | 9 +++++++++ .../AArch64/ptrauth-arm64-tls-dynamics.ll | 15 ++++++++++----- .../MC/AArch64/directives-case_insensitive.s | 3 +++ 6 files changed, 53 insertions(+), 14 deletions(-) diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index 4eb475ef606de..35eac377779f7 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -3438,13 +3438,15 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) { /// adrp x0, :tlsdesc_auth:var /// ldr x16, [x0, #:tlsdesc_auth_lo12:var] /// add x0, x0, #:tlsdesc_auth_lo12:var + /// .tlsdescauthcall var /// blraa x16, x0 /// (TPIDR_EL0 offset now in x0) const MachineOperand &MO_Sym = MI->getOperand(0); MachineOperand MO_TLSDESC_LO12(MO_Sym), MO_TLSDESC(MO_Sym); - MCOperand SymTLSDescLo12, SymTLSDesc; + MCOperand Sym, SymTLSDescLo12, SymTLSDesc; MO_TLSDESC_LO12.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGEOFF); MO_TLSDESC.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGE); + MCInstLowering.lowerOperand(MO_Sym, Sym); MCInstLowering.lowerOperand(MO_TLSDESC_LO12, SymTLSDescLo12); MCInstLowering.lowerOperand(MO_TLSDESC, SymTLSDesc); @@ -3470,8 +3472,15 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) { Add.addOperand(MCOperand::createImm(AArch64_AM::getShiftValue(0))); EmitToStreamer(*OutStreamer, Add); - // Authenticated TLSDESC accesses are not relaxed. - // Thus, do not emit .tlsdesccall for AUTH TLSDESC. + // Emit a relocation-annotation. This expands to no code, but requests + // the following instruction gets an R_AARCH64_AUTH_TLSDESC_CALL. + MCInst TLSDescAuthCall; + TLSDescAuthCall.setOpcode(AArch64::TLSDESCAUTHCALL); + TLSDescAuthCall.addOperand(Sym); + EmitToStreamer(*OutStreamer, TLSDescAuthCall); +#ifndef NDEBUG + --InstsEmitted; // no code emitted +#endif MCInst Blraa; Blraa.setOpcode(AArch64::BLRAA); diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index 9db82fa86348e..64584d4d44e60 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -3676,6 +3676,14 @@ def TLSDESCCALL : Pseudo<(outs), (ins i64imm:$sym), []>, Sched<[]> { let AsmString = ".tlsdesccall $sym"; } +// This is a directive-like pseudo-instruction. The purpose is to insert an +// R_AARCH64_AUTH_TLSDESC_CALL relocation at the offset of the following instruction +// (which in the usual case is a BLRAA). +let hasSideEffects = 1 in +def TLSDESCAUTHCALL : Pseudo<(outs), (ins i64imm:$sym), []>, Sched<[]> { + let AsmString = ".tlsdescauthcall $sym"; +} + // Pseudo instruction to tell the streamer to emit a 'B' character into the // augmentation string. def EMITBKEY : Pseudo<(outs), (ins), []>, Sched<[]> {} diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp index 6a6b73b8a4c88..f33d84db7ccec 100644 --- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -191,7 +191,7 @@ class AArch64AsmParser : public MCTargetAsmParser { bool parseDirectiveCPU(SMLoc L); bool parseDirectiveInst(SMLoc L); - bool parseDirectiveTLSDescCall(SMLoc L); + bool parseDirectiveTLSDescCall(SMLoc L, bool IsAuth); bool parseDirectiveLOH(StringRef LOH, SMLoc L); bool parseDirectiveLtorg(SMLoc L); @@ -7271,7 +7271,9 @@ bool AArch64AsmParser::ParseDirective(AsmToken DirectiveID) { else if (IDVal == ".cpu") parseDirectiveCPU(Loc); else if (IDVal == ".tlsdesccall") - parseDirectiveTLSDescCall(Loc); + parseDirectiveTLSDescCall(Loc, /*IsAuth=*/false); + else if (IDVal == ".tlsdescauthcall") + parseDirectiveTLSDescCall(Loc, /*IsAuth=*/true); else if (IDVal == ".ltorg" || IDVal == ".pool") parseDirectiveLtorg(Loc); else if (IDVal == ".unreq") @@ -7594,8 +7596,9 @@ bool AArch64AsmParser::parseDirectiveInst(SMLoc Loc) { } // parseDirectiveTLSDescCall: -// ::= .tlsdesccall symbol -bool AArch64AsmParser::parseDirectiveTLSDescCall(SMLoc L) { +// ::= .tlsdesccall symbol (if IsAuth is false) +// ::= .tlsdescauthcall symbol (if IsAuth is true) +bool AArch64AsmParser::parseDirectiveTLSDescCall(SMLoc L, bool IsAuth) { StringRef Name; if (check(getParser().parseIdentifier(Name), L, "expected symbol") || parseToken(AsmToken::EndOfStatement)) @@ -7603,10 +7606,12 @@ bool AArch64AsmParser::parseDirectiveTLSDescCall(SMLoc L) { MCSymbol *Sym = getContext().getOrCreateSymbol(Name); const MCExpr *Expr = MCSymbolRefExpr::create(Sym, getContext()); - Expr = MCSpecifierExpr::create(Expr, AArch64::S_TLSDESC, getContext()); + Expr = MCSpecifierExpr::create( + Expr, IsAuth ? AArch64::S_TLSDESC_AUTH : AArch64::S_TLSDESC, + getContext()); MCInst Inst; - Inst.setOpcode(AArch64::TLSDESCCALL); + Inst.setOpcode(IsAuth ? AArch64::TLSDESCAUTHCALL : AArch64::TLSDESCCALL); Inst.addOperand(MCOperand::createExpr(Expr)); getParser().getStreamer().emitInstruction(Inst, getSTI()); diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp index 21ff55e9d9a7f..0183b826c1cb0 100644 --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp @@ -738,6 +738,15 @@ void AArch64MCCodeEmitter::encodeInstruction(const MCInst &MI, return; } + if (MI.getOpcode() == AArch64::TLSDESCAUTHCALL) { + // This is a directive which applies an R_AARCH64_AUTH_TLSDESC_CALL to the + // following (BLRAA) instruction. It doesn't emit any code itself so it + // doesn't go through the normal TableGenerated channels. + addFixup(Fixups, 0, MI.getOperand(0).getExpr(), + ELF::R_AARCH64_AUTH_TLSDESC_CALL); + return; + } + if (MI.getOpcode() == AArch64::SPACE) { // SPACE just increases basic block size, in both cases no actual code. return; diff --git a/llvm/test/CodeGen/AArch64/ptrauth-arm64-tls-dynamics.ll b/llvm/test/CodeGen/AArch64/ptrauth-arm64-tls-dynamics.ll index 2d8085cf489b9..d6cbe9d50c2ba 100644 --- a/llvm/test/CodeGen/AArch64/ptrauth-arm64-tls-dynamics.ll +++ b/llvm/test/CodeGen/AArch64/ptrauth-arm64-tls-dynamics.ll @@ -16,6 +16,7 @@ define i32 @test_generaldynamic() { ; CHECK: adrp x[[TLSDESC_HI:[0-9]+]], :tlsdesc_auth:general_dynamic_var ; CHECK-NEXT: ldr x16, [x[[TLSDESC_HI]], :tlsdesc_auth_lo12:general_dynamic_var] ; CHECK-NEXT: add x0, x[[TLSDESC_HI]], :tlsdesc_auth_lo12:general_dynamic_var +; CHECK-NEXT: .tlsdescauthcall general_dynamic_var ; CHECK-NEXT: blraa x16, x0 ; CHECK-NEXT: mrs x[[TPIDR:[0-9]+]], TPIDR_EL0 ; CHECK-NEXT: ldr w0, [x[[TPIDR]], x0] @@ -23,7 +24,7 @@ define i32 @test_generaldynamic() { ; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_ADR_PAGE21 ; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_LD64_LO12 ; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_ADD_LO12 -; CHECK-OBJ-NOT: R_AARCH64_TLSDESC_CALL +; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_CALL ; CHECK-ERR: LLVM ERROR: cannot select: %1:gpr64sp(p0) = G_GLOBAL_VALUE @general_dynamic_var (in function: test_generaldynamic) } @@ -36,6 +37,7 @@ define ptr @test_generaldynamic_addr() { ; CHECK: adrp x[[TLSDESC_HI:[0-9]+]], :tlsdesc_auth:general_dynamic_var ; CHECK-NEXT: ldr x16, [x[[TLSDESC_HI]], :tlsdesc_auth_lo12:general_dynamic_var] ; CHECK-NEXT: add x0, x[[TLSDESC_HI]], :tlsdesc_auth_lo12:general_dynamic_var +; CHECK-NEXT: .tlsdescauthcall general_dynamic_var ; CHECK-NEXT: blraa x16, x0 ; CHECK-NEXT: mrs [[TP:x[0-9]+]], TPIDR_EL0 ; CHECK-NEXT: add x0, [[TP]], x0 @@ -43,7 +45,7 @@ define ptr @test_generaldynamic_addr() { ; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_ADR_PAGE21 ; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_LD64_LO12 ; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_ADD_LO12 -; CHECK-OBJ-NOT: R_AARCH64_TLSDESC_CALL +; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_CALL } ;; Note: with signed TLSDESC, general dynamic model is always used, @@ -60,6 +62,7 @@ define i32 @test_localdynamic() { ; CHECK: adrp x[[TLSDESC_HI:[0-9]+]], :tlsdesc_auth:local_dynamic_var ; CHECK-NEXT: ldr x16, [x[[TLSDESC_HI]], :tlsdesc_auth_lo12:local_dynamic_var] ; CHECK-NEXT: add x0, x[[TLSDESC_HI]], :tlsdesc_auth_lo12:local_dynamic_var +; CHECK-NEXT: .tlsdescauthcall local_dynamic_var ; CHECK-NEXT: blraa x16, x0 ; CHECK-NEXT: mrs x[[TPIDR:[0-9]+]], TPIDR_EL0 ; CHECK-NEXT: ldr w0, [x[[TPIDR]], x0] @@ -67,7 +70,7 @@ define i32 @test_localdynamic() { ; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_ADR_PAGE21 ; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_LD64_LO12 ; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_ADD_LO12 -; CHECK-OBJ-NOT: R_AARCH64_TLSDESC_CALL +; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_CALL } define ptr @test_localdynamic_addr() { @@ -78,6 +81,7 @@ define ptr @test_localdynamic_addr() { ; CHECK: adrp x[[TLSDESC_HI:[0-9]+]], :tlsdesc_auth:local_dynamic_var ; CHECK-NEXT: ldr x16, [x[[TLSDESC_HI]], :tlsdesc_auth_lo12:local_dynamic_var] ; CHECK-NEXT: add x0, x[[TLSDESC_HI]], :tlsdesc_auth_lo12:local_dynamic_var +; CHECK-NEXT: .tlsdescauthcall local_dynamic_var ; CHECK-NEXT: blraa x16, x0 ; CHECK-NEXT: mrs x[[TPIDR:[0-9]+]], TPIDR_EL0 ; CHECK-NEXT: add x0, x[[TPIDR]], x0 @@ -85,7 +89,7 @@ define ptr @test_localdynamic_addr() { ; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_ADR_PAGE21 ; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_LD64_LO12 ; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_ADD_LO12 -; CHECK-OBJ-NOT: R_AARCH64_TLSDESC_CALL +; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_CALL } @extern_weak_var = extern_weak thread_local global i32 @@ -99,6 +103,7 @@ define i32 @test_extern_weak() { ; CHECK: adrp x[[TLSDESC_HI:[0-9]+]], :tlsdesc_auth:extern_weak_var ; CHECK-NEXT: ldr x16, [x[[TLSDESC_HI]], :tlsdesc_auth_lo12:extern_weak_var] ; CHECK-NEXT: add x0, x[[TLSDESC_HI]], :tlsdesc_auth_lo12:extern_weak_var +; CHECK-NEXT: .tlsdescauthcall extern_weak_var ; CHECK-NEXT: blraa x16, x0 ; CHECK-NEXT: mrs x[[TPIDR:[0-9]+]], TPIDR_EL0 ; CHECK-NEXT: ldr w0, [x[[TPIDR]], x0] @@ -106,7 +111,7 @@ define i32 @test_extern_weak() { ; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_ADR_PAGE21 ; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_LD64_LO12 ; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_ADD_LO12 -; CHECK-OBJ-NOT: R_AARCH64_TLSDESC_CALL +; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_CALL ; CHECK-OBJ: 0000000000000000 0 TLS WEAK DEFAULT UND extern_weak_var } diff --git a/llvm/test/MC/AArch64/directives-case_insensitive.s b/llvm/test/MC/AArch64/directives-case_insensitive.s index c2bdec73e349e..d653d35858d17 100644 --- a/llvm/test/MC/AArch64/directives-case_insensitive.s +++ b/llvm/test/MC/AArch64/directives-case_insensitive.s @@ -44,5 +44,8 @@ fred .REQ x5 .TLSDESCCALL var // CHECK: .tlsdesccall var +.TLSDESCAUTHCALL var +// CHECK: .tlsdescauthcall var + .LTORG .POOL >From 728f4a1d733d4f120d0bef9defaef6e8c6fc7186 Mon Sep 17 00:00:00 2001 From: Daniil Kovalev <[email protected]> Date: Thu, 21 May 2026 13:04:22 +0300 Subject: [PATCH 2/2] Address review comments --- llvm/test/MC/AArch64/tls-auth-relocs.s | 36 ++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 llvm/test/MC/AArch64/tls-auth-relocs.s diff --git a/llvm/test/MC/AArch64/tls-auth-relocs.s b/llvm/test/MC/AArch64/tls-auth-relocs.s new file mode 100644 index 0000000000000..500564661ddef --- /dev/null +++ b/llvm/test/MC/AArch64/tls-auth-relocs.s @@ -0,0 +1,36 @@ +// RUN: llvm-mc -triple=aarch64-none-linux-gnu -mattr=+pauth -show-encoding < %s | FileCheck %s +// RUN: llvm-mc -triple=aarch64-none-linux-gnu -mattr=+pauth -filetype=obj < %s -o - | \ +// RUN: llvm-readobj -r --symbols - | FileCheck --check-prefix=CHECK-ELF %s + + adrp x8, :tlsdesc_auth:var + ldr x7, [x6, :tlsdesc_auth_lo12:var] + add x5, x4, #:tlsdesc_auth_lo12:var + .tlsdescauthcall var + blraa x3, x2 + +// CHECK: adrp x8, :tlsdesc_auth:var // encoding: [0x08'A',A,A,0x90'A'] +// CHECK-NEXT: // fixup A - offset: 0, value: :tlsdesc_auth:var, kind: fixup_aarch64_pcrel_adrp_imm21 +// CHECK: ldr x7, [x6, :tlsdesc_auth_lo12:var] // encoding: [0xc7,0bAAAAAA00,0b01AAAAAA,0xf9] +// CHECK-NEXT: // fixup A - offset: 0, value: :tlsdesc_auth_lo12:var, kind: fixup_aarch64_ldst_imm12_scale8 +// CHECK: add x5, x4, :tlsdesc_auth_lo12:var // encoding: [0x85,0bAAAAAA00,0b00AAAAAA,0x91] +// CHECK-NEXT: // fixup A - offset: 0, value: :tlsdesc_auth_lo12:var, kind: fixup_aarch64_add_imm12 +// CHECK: .tlsdescauthcall var // encoding: [] +// CHECK-NEXT: // fixup A - offset: 0, value: var, relocation type: 598 +// CHECK: blraa x3, x2 // encoding: [0x62,0x08,0x3f,0xd7] + +// CHECK-ELF: Relocations [ +// CHECK-ELF-NEXT: Section {{.*}} .rela.text { +// CHECK-ELF-NEXT: 0x0 R_AARCH64_AUTH_TLSDESC_ADR_PAGE21 [[VARSYM:[^ ]+]] +// CHECK-ELF-NEXT: 0x4 R_AARCH64_AUTH_TLSDESC_LD64_LO12 [[VARSYM]] +// CHECK-ELF-NEXT: 0x8 R_AARCH64_AUTH_TLSDESC_ADD_LO12 [[VARSYM]] +// CHECK-ELF-NEXT: 0xC R_AARCH64_AUTH_TLSDESC_CALL [[VARSYM]] + +// Make sure symbol has type STT_TLS: + +// CHECK-ELF: Symbols [ +// CHECK-ELF: Symbol { +// CHECK-ELF: Name: var +// CHECK-ELF-NEXT: Value: +// CHECK-ELF-NEXT: Size: +// CHECK-ELF-NEXT: Binding: Global +// CHECK-ELF-NEXT: Type: TLS _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
