https://github.com/atrosinenko updated https://github.com/llvm/llvm-project/pull/169699
>From 521c50a4dbc7536c57b996e3b50a482db6ae64d5 Mon Sep 17 00:00:00 2001 From: Anatoly Trosinenko <[email protected]> Date: Thu, 25 Sep 2025 22:28:14 +0300 Subject: [PATCH] [AArch64][PAC] Rework the expansion of AUT/AUTPAC pseudos Refactor `AArch64AsmPrinter::emitPtrauthAuthResign` to improve readability and fix the conditions when `emitPtrauthDiscriminator` is allowed to clobber AddrDisc. * do not clobber `AUTAddrDisc` when computing `AUTDiscReg` on resigning if `AUTAddrDisc == PACAddrDisc`, as it would prevent passing raw, 64-bit value as the new discriminator * move the code computing `ShouldCheck` and `ShouldTrap` conditions to a separate function --- llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 103 +++++++++++------- ...trauth-intrinsic-auth-resign-with-blend.ll | 77 +++++++++++-- 2 files changed, 129 insertions(+), 51 deletions(-) diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index 57867fc8afb7d..d75b3de0ec8e2 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -2235,21 +2235,9 @@ AArch64AsmPrinter::PtrAuthSchema::PtrAuthSchema( : Key(Key), IntDisc(IntDisc), AddrDisc(AddrDiscOp.getReg()), AddrDiscIsKilled(AddrDiscOp.isKill()) {} -void AArch64AsmPrinter::emitPtrauthAuthResign( - Register Pointer, Register Scratch, PtrAuthSchema AuthSchema, - std::optional<PtrAuthSchema> SignSchema, Value *DS) { - const bool IsResign = SignSchema.has_value(); - - // We expand AUT/AUTPAC into a sequence of the form - // - // ; authenticate x16 - // ; check pointer in x16 - // Lsuccess: - // ; sign x16 (if AUTPAC) - // Lend: ; if not trapping on failure - // - // with the checking sequence chosen depending on whether/how we should check - // the pointer and whether we should trap on failure. +static std::pair<bool, bool> getCheckAndTrapMode(const MachineFunction *MF, + bool IsResign) { + const AArch64Subtarget &STI = MF->getSubtarget<AArch64Subtarget>(); // By default, auth/resign sequences check for auth failures. bool ShouldCheck = true; @@ -2258,7 +2246,7 @@ void AArch64AsmPrinter::emitPtrauthAuthResign( // On an FPAC CPU, you get traps whether you want them or not: there's // no point in emitting checks or traps. - if (STI->hasFPAC()) + if (STI.hasFPAC()) ShouldCheck = ShouldTrap = false; // However, command-line flags can override this, for experimentation. @@ -2277,43 +2265,76 @@ void AArch64AsmPrinter::emitPtrauthAuthResign( break; } - // Compute aut discriminator - Register AUTDiscReg = - emitPtrauthDiscriminator(AuthSchema.IntDisc, AuthSchema.AddrDisc, Scratch, - AuthSchema.AddrDiscIsKilled); + // Checked-but-not-trapping mode ("poison") only applies to resigning, + // replace with "unchecked" for standalone AUT. + if (!IsResign && ShouldCheck && !ShouldTrap) + ShouldCheck = ShouldTrap = false; - if (!emitDeactivationSymbolRelocation(DS)) - emitAUT(AuthSchema.Key, Pointer, AUTDiscReg); + return std::make_pair(ShouldCheck, ShouldTrap); +} - // Unchecked or checked-but-non-trapping AUT is just an "AUT": we're done. - if (!IsResign && (!ShouldCheck || !ShouldTrap)) - return; +// We expand AUTx16x17/AUTxMxN into a sequence of the form +// +// ; authenticate Pointer +// ; check that Pointer is valid (optional, traps on failure) +// +// We expand AUTPAC into a sequence of the form +// +// ; authenticate Pointer +// ; check that Pointer is valid (optional, traps on failure) +// ; sign Pointer +// +// or +// +// ; authenticate Pointer +// ; check that Pointer is valid (skips re-sign on failure) +// ; sign Pointer +// Lon_failure: +// +void AArch64AsmPrinter::emitPtrauthAuthResign( + Register Pointer, Register Scratch, PtrAuthSchema AuthSchema, + std::optional<PtrAuthSchema> SignSchema, Value *DS) { + const bool IsResign = SignSchema.has_value(); + + const auto [ShouldCheck, ShouldTrap] = getCheckAndTrapMode(MF, IsResign); + const bool ShouldSkipSignOnAuthFailure = ShouldCheck && !ShouldTrap; + assert((ShouldCheck || !ShouldTrap) && "ShouldTrap implies ShouldCheck"); + + // It is hardly meaningful to authenticate or sign a pointer using its own + // value, thus we only have to take care not to early-clobber + // AuthSchema.AddrDisc that is aliased with SignSchema->AddrDisc. + assert(Pointer != AuthSchema.AddrDisc); + assert(!SignSchema || Pointer != SignSchema->AddrDisc); + bool IsResignWithAliasedAddrDiscs = + IsResign && AuthSchema.AddrDisc == SignSchema->AddrDisc; + bool MayReuseAUTAddrDisc = + !IsResignWithAliasedAddrDiscs && AuthSchema.AddrDiscIsKilled; + Register AUTDiscReg = emitPtrauthDiscriminator( + AuthSchema.IntDisc, AuthSchema.AddrDisc, Scratch, MayReuseAUTAddrDisc); - MCSymbol *EndSym = nullptr; + if (!emitDeactivationSymbolRelocation(DS)) + emitAUT(AuthSchema.Key, Pointer, AUTDiscReg); - if (ShouldCheck) { - if (IsResign && !ShouldTrap) - EndSym = createTempSymbol("resign_end_"); + MCSymbol *OnFailure = + ShouldSkipSignOnAuthFailure ? createTempSymbol("resign_end_") : nullptr; + if (ShouldCheck) emitPtrauthCheckAuthenticatedValue(Pointer, Scratch, AuthSchema.Key, AArch64PAuth::AuthCheckMethod::XPAC, - EndSym); - } + OnFailure); - // We already emitted unchecked and checked-but-non-trapping AUTs. - // That left us with trapping AUTs, and AUTPACs. - // Trapping AUTs don't need PAC: we're done. - if (!IsResign) + if (!IsResign) { + assert(!OnFailure && "Poison mode only applies to resigning"); return; + } - // Compute pac discriminator - Register PACDiscReg = emitPtrauthDiscriminator(SignSchema->IntDisc, - SignSchema->AddrDisc, Scratch); + Register PACDiscReg = + emitPtrauthDiscriminator(SignSchema->IntDisc, SignSchema->AddrDisc, + Scratch, SignSchema->AddrDiscIsKilled); emitPAC(SignSchema->Key, Pointer, PACDiscReg); - // Lend: - if (EndSym) - OutStreamer->emitLabel(EndSym); + if (OnFailure) + OutStreamer->emitLabel(OnFailure); } void AArch64AsmPrinter::emitPtrauthSign(const MachineInstr *MI) { diff --git a/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign-with-blend.ll b/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign-with-blend.ll index e2aea6df78250..ae5fa509d439b 100644 --- a/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign-with-blend.ll +++ b/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign-with-blend.ll @@ -1,4 +1,3 @@ -; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel=0 -verify-machineinstrs \ ; RUN: -aarch64-ptrauth-auth-checks=none | FileCheck %s -DL="L" --check-prefixes=UNCHECKED,UNCHECKED-DARWIN ; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel -global-isel-abort=1 -verify-machineinstrs \ @@ -84,12 +83,14 @@ define i64 @test_resign_blend(i64 %arg, i64 %arg1, i64 %arg2) { ; UNCHECKED-NEXT: mov x16, x0 ; UNCHECKED-ELF-NEXT: movk x1, #12345, lsl #48 ; UNCHECKED-ELF-NEXT: autda x16, x1 +; UNCHECKED-ELF-NEXT: movk x2, #56789, lsl #48 +; UNCHECKED-ELF-NEXT: pacdb x16, x2 ; UNCHECKED-DARWIN-NEXT: mov x17, x1 ; UNCHECKED-DARWIN-NEXT: movk x17, #12345, lsl #48 ; UNCHECKED-DARWIN-NEXT: autda x16, x17 -; UNCHECKED-NEXT: mov x17, x2 -; UNCHECKED-NEXT: movk x17, #56789, lsl #48 -; UNCHECKED-NEXT: pacdb x16, x17 +; UNCHECKED-DARWIN-NEXT: mov x17, x2 +; UNCHECKED-DARWIN-NEXT: movk x17, #56789, lsl #48 +; UNCHECKED-DARWIN-NEXT: pacdb x16, x17 ; UNCHECKED-NEXT: mov x0, x16 ; UNCHECKED-NEXT: ret ; @@ -108,9 +109,11 @@ define i64 @test_resign_blend(i64 %arg, i64 %arg1, i64 %arg2) { ; CHECKED-NEXT: mov x16, x17 ; CHECKED-NEXT: b [[L]]resign_end_0 ; CHECKED-NEXT: Lauth_success_0: -; CHECKED-NEXT: mov x17, x2 -; CHECKED-NEXT: movk x17, #56789, lsl #48 -; CHECKED-NEXT: pacdb x16, x17 +; CHECKED-ELF-NEXT: movk x2, #56789, lsl #48 +; CHECKED-ELF-NEXT: pacdb x16, x2 +; CHECKED-DARWIN-NEXT: mov x17, x2 +; CHECKED-DARWIN-NEXT: movk x17, #56789, lsl #48 +; CHECKED-DARWIN-NEXT: pacdb x16, x17 ; CHECKED-NEXT: Lresign_end_0: ; CHECKED-NEXT: mov x0, x16 ; CHECKED-NEXT: ret @@ -129,9 +132,11 @@ define i64 @test_resign_blend(i64 %arg, i64 %arg1, i64 %arg2) { ; TRAP-NEXT: b.eq [[L]]auth_success_1 ; TRAP-NEXT: brk #0xc472 ; TRAP-NEXT: Lauth_success_1: -; TRAP-NEXT: mov x17, x2 -; TRAP-NEXT: movk x17, #56789, lsl #48 -; TRAP-NEXT: pacdb x16, x17 +; TRAP-ELF-NEXT: movk x2, #56789, lsl #48 +; TRAP-ELF-NEXT: pacdb x16, x2 +; TRAP-DARWIN-NEXT: mov x17, x2 +; TRAP-DARWIN-NEXT: movk x17, #56789, lsl #48 +; TRAP-DARWIN-NEXT: pacdb x16, x17 ; TRAP-NEXT: mov x0, x16 ; TRAP-NEXT: ret %tmp0 = call i64 @llvm.ptrauth.blend(i64 %arg1, i64 12345) @@ -299,6 +304,58 @@ define i64 @test_auth_too_large_discriminator(i64 %arg, i64 %arg1) { ret i64 %tmp1 } +; As long as we support raw, non-blended 64-bit discriminators (which might be +; useful for low-level code such as dynamic loaders), the "auth" part of resign +; must not clobber %arg, if its upper bits are later used by the "sign" part. +define i64 @test_resign_aliased_discs_raw_sign_disc(i64 %p, i64 %arg) { +; UNCHECKED-LABEL: test_resign_aliased_discs_raw_sign_disc: +; UNCHECKED: %bb.0: +; UNCHECKED-NEXT: mov x16, x0 +; UNCHECKED-NEXT: mov x17, x1 +; UNCHECKED-NEXT: movk x17, #12345, lsl #48 +; UNCHECKED-NEXT: autda x16, x17 +; UNCHECKED-NEXT: pacdb x16, x1 +; UNCHECKED-NEXT: mov x0, x16 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_resign_aliased_discs_raw_sign_disc: +; CHECKED: %bb.0: +; CHECKED-NEXT: mov x16, x0 +; CHECKED-NEXT: mov x17, x1 +; CHECKED-NEXT: movk x17, #12345, lsl #48 +; CHECKED-NEXT: autda x16, x17 +; CHECKED-NEXT: mov x17, x16 +; CHECKED-NEXT: xpacd x17 +; CHECKED-NEXT: cmp x16, x17 +; CHECKED-NEXT: b.eq [[L]]auth_success_3 +; CHECKED-NEXT: mov x16, x17 +; CHECKED-NEXT: b [[L]]resign_end_3 +; CHECKED-NEXT: Lauth_success_3: +; CHECKED-NEXT: pacdb x16, x1 +; CHECKED-NEXT: Lresign_end_3: +; CHECKED-NEXT: mov x0, x16 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_resign_aliased_discs_raw_sign_disc: +; TRAP: %bb.0: +; TRAP-NEXT: mov x16, x0 +; TRAP-NEXT: mov x17, x1 +; TRAP-NEXT: movk x17, #12345, lsl #48 +; TRAP-NEXT: autda x16, x17 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpacd x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq [[L]]auth_success_5 +; TRAP-NEXT: brk #0xc472 +; TRAP-NEXT: Lauth_success_5: +; TRAP-NEXT: pacdb x16, x1 +; TRAP-NEXT: mov x0, x16 +; TRAP-NEXT: ret + %auth.disc = call i64 @llvm.ptrauth.blend(i64 %arg, i64 12345) + %res = call i64 @llvm.ptrauth.resign(i64 %p, i32 2, i64 %auth.disc, i32 3, i64 %arg) + ret i64 %res +} + declare i64 @llvm.ptrauth.auth(i64, i32, i64) declare i64 @llvm.ptrauth.resign(i64, i32, i64, i32, i64) declare i64 @llvm.ptrauth.blend(i64, i64) _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
