https://github.com/jroelofs updated https://github.com/llvm/llvm-project/pull/202742
>From 638e90e5ecbe3c96071b8431a51ab1f712177461 Mon Sep 17 00:00:00 2001 From: Jon Roelofs <[email protected]> Date: Tue, 9 Jun 2026 12:01:23 -0700 Subject: [PATCH 1/7] [arm64e] Add a builtin + intrinsic for arm64e PAuth_LR: __builtin_ptrauth_auth_with_pc_and_resign The new builtin behaves like __builtin_ptrauth_auth_and_resign, but incorporates the address of the signing instruction (i.e. the `pacibsppc`/`paciasppc`) when performing the auth side, and subsequently re-signs using a different scheme. Authenticating the re-signed value will fail if and only if authenticating the original value with the incorporated pc would have failed. --- clang/docs/PointerAuthentication.rst | 16 ++++ clang/include/clang/Basic/Builtins.td | 6 ++ .../clang/Basic/DiagnosticSemaKinds.td | 4 +- clang/lib/CodeGen/CGBuiltin.cpp | 13 +++ clang/lib/Headers/ptrauth.h | 36 +++++++ clang/lib/Sema/SemaChecking.cpp | 41 +++++++- clang/test/CodeGen/ptrauth-intrinsics.c | 14 +++ clang/test/Sema/ptrauth-intrinsics-macro.c | 5 + clang/test/Sema/ptrauth.c | 27 ++++++ llvm/include/llvm/IR/Intrinsics.td | 13 +++ llvm/lib/IR/Verifier.cpp | 8 ++ .../Target/AArch64/AArch64ISelDAGToDAG.cpp | 44 +++++++++ .../GISel/AArch64InstructionSelector.cpp | 61 ++++++++++++ ...rauth-intrinsic-auth-with-pc-and-resign.ll | 93 +++++++++++++++++++ 14 files changed, 378 insertions(+), 3 deletions(-) create mode 100644 llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-with-pc-and-resign.ll diff --git a/clang/docs/PointerAuthentication.rst b/clang/docs/PointerAuthentication.rst index bf2520b32a3a4..9f0a30caf5343 100644 --- a/clang/docs/PointerAuthentication.rst +++ b/clang/docs/PointerAuthentication.rst @@ -687,6 +687,22 @@ computations may still be attackable. In the future, Clang should be enhanced to guarantee non-attackability if these expressions are :ref:`safely-derived<Safe derivation>`. +``ptrauth_auth_with_pc_and_resign`` + +.. code-block:: c + + ptrauth_auth_with_pc_and_resign(pointer, oldKey, oldDiscriminator, oldPC, newKey, newDiscriminator) + +Similar to :ref:`ptrauth_auth_and_resign`, but additionally requires that the +signature includes the address of the signing instruction (i.e. uses `paciasppc` +/ `pacibsppc` instead of `paciasp` / `pacibsp`). This authenticates ``pointer`` +signed with ``oldKey`` and ``oldDiscriminator`` at ``oldPC``, then resigns the +raw-pointer result with ``newKey`` and ``newDiscriminator``. + +Note: ``oldKey`` must be ``ptrauth_key_asia`` (IA) or ``ptrauth_key_asib`` (IB), +as only these keys support PC-based authentication instructions. Data keys +(``ptrauth_key_asda`` / ``ptrauth_key_asdb``) are not supported. + ``ptrauth_auth_function`` ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index e7fb43be8794e..d8a3215cd8627 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -5013,6 +5013,12 @@ def PtrauthAuthAndResign : Builtin { let Prototype = "void*(void*,int,void*,int,void*)"; } +def PtrauthAuthWithPCAndResign : Builtin { + let Spellings = ["__builtin_ptrauth_auth_with_pc_and_resign"]; + let Attributes = [CustomTypeChecking, NoThrow]; + let Prototype = "void*(void*,int,void*,void*,int,void*)"; +} + def PtrauthAuthLoadRelativeAndSign : Builtin { let Spellings = ["__builtin_ptrauth_auth_load_relative_and_sign"]; let Attributes = [CustomTypeChecking, NoThrow]; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index d3e2d616a8b80..224726d35f294 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1010,7 +1010,7 @@ def err_ptrauth_invalid_key : "the current target">; def err_ptrauth_value_bad_type : Error<"%select{signed value|extra discriminator|blended pointer|blended " - "integer}0 must have %select{pointer|integer|pointer or integer}1 " + "integer|blended pc}0 must have %select{pointer|integer|pointer or integer}1 " "type; type here is %2">; def err_ptrauth_bad_constant_pointer : Error<"argument to ptrauth_sign_constant must refer to a global variable " @@ -1025,6 +1025,8 @@ def warn_ptrauth_sign_null_pointer : def warn_ptrauth_auth_null_pointer : Warning<"authenticating a null pointer will almost certainly trap">, InGroup<PtrAuthNullPointers>; +def err_ptrauth_auth_with_pc_and_resign_invalid_key : + Error<"ptrauth_auth_with_pc_and_resign only supports auth with IA and IB keys, not %0">; def err_ptrauth_string_not_literal : Error< "argument must be a string literal%select{| of char type}0">; def err_ptrauth_type_disc_undiscriminated : Error< diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 682b125890fe1..84103f3d4f6b3 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -6249,6 +6249,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_ptrauth_auth: case Builtin::BI__builtin_ptrauth_auth_and_resign: + case Builtin::BI__builtin_ptrauth_auth_with_pc_and_resign: case Builtin::BI__builtin_ptrauth_auth_load_relative_and_sign: case Builtin::BI__builtin_ptrauth_blend_discriminator: case Builtin::BI__builtin_ptrauth_sign_generic_data: @@ -6265,6 +6266,16 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Args[0] = Builder.CreatePtrToInt(Args[0], IntPtrTy); switch (BuiltinID) { + case Builtin::BI__builtin_ptrauth_auth_with_pc_and_resign: + // Convert oldDiscriminator (arg 2), oldPC (arg 3) and newDiscriminator (arg 5) to intptr_t + if (Args[2]->getType()->isPointerTy()) + Args[2] = Builder.CreatePtrToInt(Args[2], IntPtrTy); + if (Args[3]->getType()->isPointerTy()) + Args[3] = Builder.CreatePtrToInt(Args[3], IntPtrTy); + if (Args[5]->getType()->isPointerTy()) + Args[5] = Builder.CreatePtrToInt(Args[5], IntPtrTy); + break; + case Builtin::BI__builtin_ptrauth_auth_and_resign: case Builtin::BI__builtin_ptrauth_auth_load_relative_and_sign: if (Args[4]->getType()->isPointerTy()) @@ -6294,6 +6305,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, return Intrinsic::ptrauth_auth; case Builtin::BI__builtin_ptrauth_auth_and_resign: return Intrinsic::ptrauth_resign; + case Builtin::BI__builtin_ptrauth_auth_with_pc_and_resign: + return Intrinsic::ptrauth_auth_with_pc_and_resign; case Builtin::BI__builtin_ptrauth_auth_load_relative_and_sign: return Intrinsic::ptrauth_resign_load_relative; case Builtin::BI__builtin_ptrauth_blend_discriminator: diff --git a/clang/lib/Headers/ptrauth.h b/clang/lib/Headers/ptrauth.h index cde1b3c4ebbe2..2b9201d1c8a2b 100644 --- a/clang/lib/Headers/ptrauth.h +++ b/clang/lib/Headers/ptrauth.h @@ -178,6 +178,31 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t; __builtin_ptrauth_auth_and_resign(__value, __old_key, __old_data, __new_key, \ __new_data) +/* Authenticate a pointer using a PC-based signature scheme and resign + it using a different scheme. + + If the result is subsequently authenticated using the new scheme, that + authentication is guaranteed to fail if and only if the initial + authentication failed. + + The value must be an expression of pointer type. + The key must be a constant expression of type ptrauth_key. + The extra data must be an expression of pointer or integer type; + if an integer, it will be coerced to ptrauth_extra_data_t. + The oldpc must be an expression of pointer or integer type representing + the PC value where the original signature was created. + The result will have the same type as the original value. + + This operation is guaranteed to not leave the intermediate value + available for attack before it is re-signed. The authentication is + performed using autia171615/autib171615 instructions which include the + PC value in the signature. + + Do not pass a null pointer to this function. A null pointer + will not successfully authenticate. */ +#define ptrauth_auth_with_pc_and_resign(__value, __old_key, __old_data, __old_pc, __new_key, __new_data) \ + __builtin_ptrauth_auth_with_pc_and_resign(__value, __old_key, __old_data, __old_pc, __new_key, __new_data) + /* Authenticate a pointer using one scheme, load 32bit value at offset addend from the pointer, and add this value to the pointer, sign using specified scheme. @@ -396,6 +421,17 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t; __value; \ }) +#define ptrauth_auth_with_pc_and_resign(__value, __old_key, __old_data, __old_pc, \ + __new_key, __new_data) \ + ({ \ + (void)__old_key; \ + (void)__old_data; \ + (void)__old_pc; \ + (void)__new_key; \ + (void)__new_data; \ + __value; \ + }) + #define ptrauth_auth_load_relative_and_sign(__value, __old_key, __old_data, \ __new_key, __new_data, __offset) \ __extension__({ \ diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index b8a3f48a32f24..1d64f666d347e 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -1550,7 +1550,8 @@ enum PointerAuthOpKind { PAO_SignGeneric, PAO_Discriminator, PAO_BlendPointer, - PAO_BlendInteger + PAO_BlendInteger, + PAO_BlendPC }; } @@ -1676,7 +1677,7 @@ static bool checkPointerAuthValue(Sema &S, Expr *&Arg, PointerAuthOpKind OpKind, }; auto AllowsInteger = [](PointerAuthOpKind OpKind) { return OpKind == PAO_Discriminator || OpKind == PAO_BlendInteger || - OpKind == PAO_SignGeneric; + OpKind == PAO_SignGeneric || OpKind == PAO_BlendPC; }; // Require the value to have the right range of type. @@ -1695,6 +1696,7 @@ static bool checkPointerAuthValue(Sema &S, Expr *&Arg, PointerAuthOpKind OpKind, << unsigned(OpKind == PAO_Discriminator ? 1 : OpKind == PAO_BlendPointer ? 2 : OpKind == PAO_BlendInteger ? 3 + : OpKind == PAO_BlendPC ? 4 : 0) << unsigned(AllowsInteger(OpKind) ? (AllowsPointer(OpKind) ? 2 : 1) : 0) << Arg->getType() << Arg->getSourceRange(); @@ -1861,6 +1863,39 @@ static ExprResult PointerAuthAuthAndResign(Sema &S, CallExpr *Call) { return Call; } +static ExprResult PointerAuthAuthWithPCAndResign(Sema &S, CallExpr *Call) { + if (S.checkArgCount(Call, 6)) + return ExprError(); + if (checkPointerAuthEnabled(S, Call)) + return ExprError(); + if (checkPointerAuthValue(S, Call->getArgs()[0], PAO_Auth) || + checkPointerAuthKey(S, Call->getArgs()[1]) || + checkPointerAuthValue(S, Call->getArgs()[2], PAO_Discriminator) || + checkPointerAuthValue(S, Call->getArgs()[3], PAO_BlendPC) || + checkPointerAuthKey(S, Call->getArgs()[4]) || + checkPointerAuthValue(S, Call->getArgs()[5], PAO_Discriminator)) + return ExprError(); + + // Validate that the oldKey is IA or IB, not DA or DB. + // This enforces the constraint that auth_with_pc_and_resign only supports + // IA/IB keys for authentication, as only those keys support the PC-based + // signing instructions (paciasppc/pacibsppc). + unsigned OldKey = 0; + if (!S.checkConstantPointerAuthKey(Call->getArgs()[1], OldKey)) { + using AK = PointerAuthSchema::ARM8_3Key; + if (OldKey != static_cast<unsigned>(AK::ASIA) && + OldKey != static_cast<unsigned>(AK::ASIB)) { + S.Diag(Call->getArgs()[1]->getExprLoc(), + diag::err_ptrauth_auth_with_pc_and_resign_invalid_key) + << OldKey << Call->getArgs()[1]->getSourceRange(); + return ExprError(); + } + } + + Call->setType(Call->getArgs()[0]->getType()); + return Call; +} + static ExprResult PointerAuthAuthLoadRelativeAndSign(Sema &S, CallExpr *Call) { if (S.checkArgCount(Call, 6)) return ExprError(); @@ -3498,6 +3533,8 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, return PointerAuthSignGenericData(*this, TheCall); case Builtin::BI__builtin_ptrauth_auth_and_resign: return PointerAuthAuthAndResign(*this, TheCall); + case Builtin::BI__builtin_ptrauth_auth_with_pc_and_resign: + return PointerAuthAuthWithPCAndResign(*this, TheCall); case Builtin::BI__builtin_ptrauth_auth_load_relative_and_sign: return PointerAuthAuthLoadRelativeAndSign(*this, TheCall); case Builtin::BI__builtin_ptrauth_string_discriminator: diff --git a/clang/test/CodeGen/ptrauth-intrinsics.c b/clang/test/CodeGen/ptrauth-intrinsics.c index bd348f9b3551a..c98ce60dc9fc9 100644 --- a/clang/test/CodeGen/ptrauth-intrinsics.c +++ b/clang/test/CodeGen/ptrauth-intrinsics.c @@ -67,6 +67,20 @@ void test_auth_load_relative_and_sign() { fnptr = __builtin_ptrauth_auth_load_relative_and_sign(fnptr, 0, ptr_discriminator, 3, 15, 16L); } +// CHECK-LABEL: define {{.*}}void @test_auth_with_pc_and_resign() +void test_auth_with_pc_and_resign() { + // CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr, + // CHECK-NEXT: [[DISC0:%.*]] = load ptr, ptr @ptr_discriminator, + // CHECK-NEXT: [[PC:%.*]] = load ptr, ptr @ptr_discriminator, + // CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[PTR]] to i64 + // CHECK-NEXT: [[DISC:%.*]] = ptrtoint ptr [[DISC0]] to i64 + // CHECK-NEXT: [[PCVAL:%.*]] = ptrtoint ptr [[PC]] to i64 + // CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.auth.with.pc.and.resign(i64 [[T0]], i32 0, i64 [[DISC]], i64 [[PCVAL]], i32 3, i64 15) + // CHECK-NEXT: [[RESULT:%.*]] = inttoptr i64 [[T1]] to ptr + // CHECK-NEXT: store ptr [[RESULT]], ptr @fnptr, + fnptr = __builtin_ptrauth_auth_with_pc_and_resign(fnptr, 0, ptr_discriminator, ptr_discriminator, 3, 15); +} + // CHECK-LABEL: define {{.*}}void @test_blend_discriminator() void test_blend_discriminator() { // CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr, diff --git a/clang/test/Sema/ptrauth-intrinsics-macro.c b/clang/test/Sema/ptrauth-intrinsics-macro.c index adbb71a9d6e50..fbe1149eec786 100644 --- a/clang/test/Sema/ptrauth-intrinsics-macro.c +++ b/clang/test/Sema/ptrauth-intrinsics-macro.c @@ -16,12 +16,17 @@ void test(int *dp, int value) { (void)t0; dp = ptrauth_sign_unauthenticated(dp, VALID_DATA_KEY, 0); dp = ptrauth_auth_and_resign(dp, VALID_DATA_KEY, dp, VALID_DATA_KEY, dp); + dp = ptrauth_auth_with_pc_and_resign(dp, VALID_CODE_KEY, dp, dp, VALID_DATA_KEY, dp); dp = ptrauth_auth_data(dp, VALID_DATA_KEY, 0); int pu0 = 0, pu1 = 0, pu2 = 0, pu3 = 0, pu4 = 0, pu5 = 0, pu6 = 0, pu7 = 0; ptrauth_blend_discriminator(&pu0, value); ptrauth_auth_and_resign(&pu1, VALID_DATA_KEY, dp, VALID_DATA_KEY, dp); ptrauth_auth_and_resign(dp, VALID_DATA_KEY, &pu2, VALID_DATA_KEY, dp); ptrauth_auth_and_resign(dp, VALID_DATA_KEY, dp, VALID_DATA_KEY, &pu3); + ptrauth_auth_with_pc_and_resign(&pu1, VALID_CODE_KEY, dp, dp, VALID_DATA_KEY, dp); + ptrauth_auth_with_pc_and_resign(dp, VALID_CODE_KEY, &pu2, dp, VALID_DATA_KEY, dp); + ptrauth_auth_with_pc_and_resign(dp, VALID_CODE_KEY, dp, &pu3, VALID_DATA_KEY, dp); + ptrauth_auth_with_pc_and_resign(dp, VALID_CODE_KEY, dp, dp, VALID_DATA_KEY, &pu4); ptrauth_sign_generic_data(pu4, dp); ptrauth_sign_generic_data(dp, pu5); ptrauth_auth_data(&pu6, VALID_DATA_KEY, value); diff --git a/clang/test/Sema/ptrauth.c b/clang/test/Sema/ptrauth.c index 59c18a3ef5e40..5aae042f50c96 100644 --- a/clang/test/Sema/ptrauth.c +++ b/clang/test/Sema/ptrauth.c @@ -145,6 +145,33 @@ void test_auth_load_relative_and_sign(int *dp, int (*fp)(int)) { float *mismatch = __builtin_ptrauth_auth_load_relative_and_sign(dp, VALID_DATA_KEY, 0, VALID_DATA_KEY, dp,0); // expected-error {{incompatible pointer types initializing 'float *' with an expression of type 'int *'}} } +void test_auth_with_pc_and_resign(int *dp, int (*fp)(int), void *pc) { + __builtin_ptrauth_auth_with_pc_and_resign(dp, VALID_DATA_KEY, 0, pc, VALID_DATA_KEY); // expected-error {{too few arguments}} + __builtin_ptrauth_auth_with_pc_and_resign(dp, VALID_DATA_KEY, dp, pc, VALID_DATA_KEY, dp, 0); // expected-error {{too many arguments}} + + __builtin_ptrauth_auth_with_pc_and_resign(mismatched_type, VALID_DATA_KEY, 0, pc, VALID_DATA_KEY, dp); // expected-error {{signed value must have pointer type; type here is 'struct A'}} + __builtin_ptrauth_auth_with_pc_and_resign(dp, mismatched_type, 0, pc, VALID_DATA_KEY, dp); // expected-error {{passing 'struct A' to parameter of incompatible type 'int'}} + __builtin_ptrauth_auth_with_pc_and_resign(dp, VALID_DATA_KEY, mismatched_type, pc, VALID_DATA_KEY, dp); // expected-error {{extra discriminator must have pointer or integer type; type here is 'struct A'}} + __builtin_ptrauth_auth_with_pc_and_resign(dp, VALID_DATA_KEY, 0, mismatched_type, VALID_DATA_KEY, dp); // expected-error {{blended pc must have pointer or integer type; type here is 'struct A'}} + __builtin_ptrauth_auth_with_pc_and_resign(dp, VALID_DATA_KEY, 0, pc, mismatched_type, dp); // expected-error {{passing 'struct A' to parameter of incompatible type 'int'}} + __builtin_ptrauth_auth_with_pc_and_resign(dp, VALID_DATA_KEY, 0, pc, VALID_DATA_KEY, mismatched_type); // expected-error {{extra discriminator must have pointer or integer type; type here is 'struct A'}} + + (void) __builtin_ptrauth_auth_with_pc_and_resign(NULL, VALID_DATA_KEY, 0, pc, VALID_DATA_KEY, dp); // expected-error {{ptrauth_auth_with_pc_and_resign only supports auth with IA and IB keys, not 2}} expected-warning {{authenticating a null pointer will almost certainly trap}} + + // Test that data keys (DA/DB) are rejected for oldKey + int *dr = __builtin_ptrauth_auth_with_pc_and_resign(dp, VALID_DATA_KEY, 0, pc, VALID_DATA_KEY, dp); // expected-error {{ptrauth_auth_with_pc_and_resign only supports auth with IA and IB keys, not 2}} + dr = __builtin_ptrauth_auth_with_pc_and_resign(dp, 3, 0, pc, VALID_DATA_KEY, dp); // expected-error {{ptrauth_auth_with_pc_and_resign only supports auth with IA and IB keys, not 3}} + dr = __builtin_ptrauth_auth_with_pc_and_resign(dp, INVALID_KEY, 0, pc, VALID_DATA_KEY, dp); // expected-error {{does not identify a valid pointer authentication key for the current target}} + dr = __builtin_ptrauth_auth_with_pc_and_resign(dp, VALID_CODE_KEY, 0, pc, INVALID_KEY, dp); // expected-error {{does not identify a valid pointer authentication key for the current target}} + + // Test with valid IA/IB keys + int (*fr)(int) = __builtin_ptrauth_auth_with_pc_and_resign(fp, VALID_CODE_KEY, 0, pc, VALID_CODE_KEY, dp); + fr = __builtin_ptrauth_auth_with_pc_and_resign(fp, INVALID_KEY, 0, pc, VALID_CODE_KEY, dp); // expected-error {{does not identify a valid pointer authentication key for the current target}} + fr = __builtin_ptrauth_auth_with_pc_and_resign(fp, VALID_CODE_KEY, 0, pc, INVALID_KEY, dp); // expected-error {{does not identify a valid pointer authentication key for the current target}} + + float *mismatch = __builtin_ptrauth_auth_with_pc_and_resign(dp, VALID_CODE_KEY, 0, pc, VALID_DATA_KEY, dp); // expected-error {{incompatible pointer types initializing 'float *' with an expression of type 'int *'}} +} + void test_sign_generic_data(int *dp) { __builtin_ptrauth_sign_generic_data(dp); // expected-error {{too few arguments}} __builtin_ptrauth_sign_generic_data(dp, 0, 0); // expected-error {{too many arguments}} diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td index b1b2bb2a72c65..b6d41fb543af9 100644 --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -1839,6 +1839,19 @@ def int_experimental_patchpoint : Intrinsic<[llvm_any_ty], ImmArg<ArgIndex<1>>, ImmArg<ArgIndex<3>>]>; +// Authenticate a signed pointer using a PC-based signature and resign it. +// The second (key) and third (discriminator) arguments specify the signing +// schema used for authenticating. +// The fourth argument specifies the signing PC value. +// The fifth and sixth arguments specify the schema used for resigning. +// The signature must be valid. +// This uses autia171615/autib171615 for authentication with PC, then signs normally. +def int_ptrauth_auth_with_pc_and_resign : Intrinsic<[llvm_i64_ty], + [llvm_i64_ty, llvm_i32_ty, llvm_i64_ty, + llvm_i64_ty, llvm_i32_ty, llvm_i64_ty], + [IntrNoMem, ImmArg<ArgIndex<1>>, + ImmArg<ArgIndex<4>>]>; + //===------------------------ Garbage Collection Intrinsics ---------------===// // These are documented in docs/Statepoint.rst diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index f0363b6553440..c30398e905c39 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -7458,6 +7458,14 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) { &Call); break; } + case Intrinsic::ptrauth_auth_with_pc_and_resign: { + // Verify that the auth key is IA (0) or IB (1), not DA (2) or DB (3) + auto *AuthKey = cast<ConstantInt>(Call.getArgOperand(1)); + uint64_t Key = AuthKey->getZExtValue(); + Check(Key == 0 || Key == 1, + "ptrauth.auth.with.pc.and.resign key must be IA (0) or IB (1)", &Call); + break; + } }; // Verify that there aren't any unmediated control transfers between funclets. diff --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp index 43f97dd3b60e3..524e9a8e34879 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp @@ -367,6 +367,7 @@ class AArch64DAGToDAGISel : public SelectionDAGISel { void SelectPtrauthAuth(SDNode *N); void SelectPtrauthResign(SDNode *N); + void SelectPtrauthResignWithPC(SDNode *N); bool trySelectStackSlotTagP(SDNode *N); void SelectTagP(SDNode *N); @@ -1761,6 +1762,45 @@ void AArch64DAGToDAGISel::SelectPtrauthResign(SDNode *N) { } } +void AArch64DAGToDAGISel::SelectPtrauthResignWithPC(SDNode *N) { + SDLoc DL(N); + SDValue Val = N->getOperand(1); + SDValue AUTKey = N->getOperand(2); + SDValue AUTDisc = N->getOperand(3); + SDValue AUTPC = N->getOperand(4); + SDValue PACKey = N->getOperand(5); + SDValue PACDisc = N->getOperand(6); + + unsigned AUTKeyC = cast<ConstantSDNode>(AUTKey)->getZExtValue(); + unsigned PACKeyC = cast<ConstantSDNode>(PACKey)->getZExtValue(); + + AUTKey = CurDAG->getTargetConstant(AUTKeyC, DL, MVT::i64); + PACKey = CurDAG->getTargetConstant(PACKeyC, DL, MVT::i64); + + SDValue AUTAddrDisc, AUTConstDisc; + std::tie(AUTConstDisc, AUTAddrDisc) = + extractPtrauthBlendDiscriminators(AUTDisc, CurDAG); + + SDValue PACAddrDisc, PACConstDisc; + std::tie(PACConstDisc, PACAddrDisc) = + extractPtrauthBlendDiscriminators(PACDisc, CurDAG); + + SDValue X17Copy = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL, + AArch64::X17, Val, SDValue()); + SDValue X16Copy = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL, + AArch64::X16, AUTAddrDisc, X17Copy.getValue(1)); + SDValue X15Copy = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL, + AArch64::X15, AUTPC, X16Copy.getValue(1)); + + unsigned AuthOpc = (AUTKeyC == 0) ? AArch64::AUTIA171615 : AArch64::AUTIB171615; + SDNode *AUTH = CurDAG->getMachineNode(AuthOpc, DL, MVT::i64, X15Copy.getValue(1)); + + SDValue AuthedVal = SDValue(AUTH, 0); + SDValue Ops[] = {AuthedVal, PACKey, PACConstDisc, PACAddrDisc}; + SDNode *PAC = CurDAG->getMachineNode(AArch64::PAC, DL, MVT::i64, Ops); + ReplaceNode(N, PAC); +} + bool AArch64DAGToDAGISel::tryIndexedLoad(SDNode *N) { LoadSDNode *LD = cast<LoadSDNode>(N); if (LD->isUnindexed()) @@ -6034,6 +6074,10 @@ void AArch64DAGToDAGISel::Select(SDNode *Node) { SelectPtrauthResign(Node); return; + case Intrinsic::ptrauth_auth_with_pc_and_resign: + SelectPtrauthResignWithPC(Node); + return; + case Intrinsic::aarch64_neon_tbl2: SelectTable(Node, 2, VT == MVT::v8i8 ? AArch64::TBLv8i8Two : AArch64::TBLv16i8Two, diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp index cf650fd5c4e72..20f066ba71fc2 100644 --- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp +++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp @@ -6694,6 +6694,67 @@ bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &I, I.eraseFromParent(); return true; } + case Intrinsic::ptrauth_auth_with_pc_and_resign: { + // ptrauth.auth.with.pc.and.resign: authenticate with PC, then sign + // Operands: value, authKey, authDisc, authPC, signKey, signDisc + Register DstReg = I.getOperand(0).getReg(); + Register ValReg = I.getOperand(2).getReg(); + uint64_t AUTKey = I.getOperand(3).getImm(); + Register AUTDisc = I.getOperand(4).getReg(); + Register AUTPC = I.getOperand(5).getReg(); + uint64_t PACKey = I.getOperand(6).getImm(); + Register PACDisc = I.getOperand(7).getReg(); + + // Extract discriminators + Register AUTAddrDisc = AUTDisc; + uint16_t AUTConstDiscC = 0; + std::tie(AUTConstDiscC, AUTAddrDisc) = + extractPtrauthBlendDiscriminators(AUTDisc, MRI); + + Register PACAddrDisc = PACDisc; + uint16_t PACConstDiscC = 0; + std::tie(PACConstDiscC, PACAddrDisc) = + extractPtrauthBlendDiscriminators(PACDisc, MRI); + + // Set up autia171615/autib171615: x17=value, x16=disc, x15=pc + MIB.buildCopy({AArch64::X17}, {ValReg}); + + // Handle discriminator - if NoRegister, use XZR + if (AUTAddrDisc == AArch64::NoRegister) + AUTAddrDisc = AArch64::XZR; + MIB.buildCopy({AArch64::X16}, {AUTAddrDisc}); + + MIB.buildCopy({AArch64::X15}, {AUTPC}); + + // Use the appropriate autia/autib instruction based on the key + // Note: Only IA/IB keys supported for 171615 instructions, not DA/DB + assert((AUTKey == 0 || AUTKey == 1) && + "auth_with_pc_and_resign only supports IA and IB keys"); + unsigned AuthOpc = (AUTKey == 0) ? AArch64::AUTIA171615 + : AArch64::AUTIB171615; + MIB.buildInstr(AuthOpc).constrainAllUses(TII, TRI, RBI); + + // Now sign the authenticated value (result is in X17) + // Use the PAC pseudo which handles the signing + Register AuthedReg = MRI.createVirtualRegister(&AArch64::GPR64RegClass); + MIB.buildCopy({AuthedReg}, Register(AArch64::X17)); + + // Handle sign discriminator - if NoRegister, use XZR + if (PACAddrDisc == AArch64::NoRegister) + PACAddrDisc = AArch64::XZR; + + MIB.buildInstr(AArch64::PAC) + .addDef(DstReg) + .addUse(AuthedReg) + .addImm(PACKey) + .addImm(PACConstDiscC) + .addUse(PACAddrDisc) + .constrainAllUses(TII, TRI, RBI); + + RBI.constrainGenericRegister(DstReg, AArch64::GPR64RegClass, MRI); + I.eraseFromParent(); + return true; + } case Intrinsic::ptrauth_auth: { Register DstReg = I.getOperand(0).getReg(); Register ValReg = I.getOperand(2).getReg(); diff --git a/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-with-pc-and-resign.ll b/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-with-pc-and-resign.ll new file mode 100644 index 0000000000000..fed448465a151 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-with-pc-and-resign.ll @@ -0,0 +1,93 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple arm64e-apple-darwin -mattr=+pauth-lr -verify-machineinstrs | FileCheck %s +; RUN: llc < %s -mtriple arm64e-apple-darwin -mattr=+pauth-lr -global-isel -global-isel-abort=1 -verify-machineinstrs | FileCheck %s + +; TODO: The 171615 instructions are always unchecked, so auth-check modes don't change output + +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" + +define i64 @test_resign_with_pc_ia_ia(i64 %arg, i64 %arg1, i64 %arg2, i64 %arg3) { +; CHECK-LABEL: test_resign_with_pc_ia_ia: +; CHECK: ; %bb.0: +; CHECK-NEXT: mov x17, x0 +; CHECK-NEXT: mov x16, x1 +; CHECK-NEXT: mov x15, x2 +; CHECK-NEXT: autia171615 +; CHECK-NEXT: mov x0, x17 +; CHECK-NEXT: pacia x0, x3 +; CHECK-NEXT: ret + %tmp = call i64 @llvm.ptrauth.auth.with.pc.and.resign(i64 %arg, i32 0, i64 %arg1, i64 %arg2, i32 0, i64 %arg3) + ret i64 %tmp +} + +define i64 @test_resign_with_pc_ib_ia(i64 %arg, i64 %arg1, i64 %arg2, i64 %arg3) { +; CHECK-LABEL: test_resign_with_pc_ib_ia: +; CHECK: ; %bb.0: +; CHECK-NEXT: mov x17, x0 +; CHECK-NEXT: mov x16, x1 +; CHECK-NEXT: mov x15, x2 +; CHECK-NEXT: autib171615 +; CHECK-NEXT: mov x0, x17 +; CHECK-NEXT: pacia x0, x3 +; CHECK-NEXT: ret + %tmp = call i64 @llvm.ptrauth.auth.with.pc.and.resign(i64 %arg, i32 1, i64 %arg1, i64 %arg2, i32 0, i64 %arg3) + ret i64 %tmp +} + +define i64 @test_resign_with_pc_ia_ib(i64 %arg, i64 %arg1, i64 %arg2, i64 %arg3) { +; CHECK-LABEL: test_resign_with_pc_ia_ib: +; CHECK: ; %bb.0: +; CHECK-NEXT: mov x17, x0 +; CHECK-NEXT: mov x16, x1 +; CHECK-NEXT: mov x15, x2 +; CHECK-NEXT: autia171615 +; CHECK-NEXT: mov x0, x17 +; CHECK-NEXT: pacib x0, x3 +; CHECK-NEXT: ret + %tmp = call i64 @llvm.ptrauth.auth.with.pc.and.resign(i64 %arg, i32 0, i64 %arg1, i64 %arg2, i32 1, i64 %arg3) + ret i64 %tmp +} + +define i64 @test_resign_with_pc_ib_ib(i64 %arg, i64 %arg1, i64 %arg2, i64 %arg3) { +; CHECK-LABEL: test_resign_with_pc_ib_ib: +; CHECK: ; %bb.0: +; CHECK-NEXT: mov x17, x0 +; CHECK-NEXT: mov x16, x1 +; CHECK-NEXT: mov x15, x2 +; CHECK-NEXT: autib171615 +; CHECK-NEXT: mov x0, x17 +; CHECK-NEXT: pacib x0, x3 +; CHECK-NEXT: ret + %tmp = call i64 @llvm.ptrauth.auth.with.pc.and.resign(i64 %arg, i32 1, i64 %arg1, i64 %arg2, i32 1, i64 %arg3) + ret i64 %tmp +} + +define i64 @test_resign_with_pc_iza_ib(i64 %arg, i64 %arg1, i64 %arg2) { +; CHECK-LABEL: test_resign_with_pc_iza_ib: +; CHECK: ; %bb.0: +; CHECK-NEXT: mov x17, x0 +; CHECK-NEXT: mov x16, #0 ; =0x0 +; CHECK-NEXT: mov x15, x1 +; CHECK-NEXT: autia171615 +; CHECK-NEXT: mov x0, x17 +; CHECK-NEXT: pacib x0, x2 +; CHECK-NEXT: ret + %tmp = call i64 @llvm.ptrauth.auth.with.pc.and.resign(i64 %arg, i32 0, i64 0, i64 %arg1, i32 1, i64 %arg2) + ret i64 %tmp +} + +define i64 @test_resign_with_pc_ia_izb(i64 %arg, i64 %arg1, i64 %arg2) { +; CHECK-LABEL: test_resign_with_pc_ia_izb: +; CHECK: ; %bb.0: +; CHECK-NEXT: mov x17, x0 +; CHECK-NEXT: mov x16, x1 +; CHECK-NEXT: mov x15, x2 +; CHECK-NEXT: autia171615 +; CHECK-NEXT: mov x0, x17 +; CHECK-NEXT: pacizb x0 +; CHECK-NEXT: ret + %tmp = call i64 @llvm.ptrauth.auth.with.pc.and.resign(i64 %arg, i32 0, i64 %arg1, i64 %arg2, i32 1, i64 0) + ret i64 %tmp +} + +declare i64 @llvm.ptrauth.auth.with.pc.and.resign(i64, i32, i64, i64, i32, i64) >From e34e459a8b97ae5ad5042951f279e872c7f70ace Mon Sep 17 00:00:00 2001 From: Jon Roelofs <[email protected]> Date: Tue, 9 Jun 2026 12:04:54 -0700 Subject: [PATCH 2/7] clang-format --- clang/lib/CodeGen/CGBuiltin.cpp | 3 ++- clang/lib/Headers/ptrauth.h | 10 ++++++---- llvm/lib/IR/Verifier.cpp | 3 ++- llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp | 17 ++++++++++------- .../GISel/AArch64InstructionSelector.cpp | 4 ++-- 5 files changed, 22 insertions(+), 15 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 84103f3d4f6b3..5f2ba6412da78 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -6267,7 +6267,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, switch (BuiltinID) { case Builtin::BI__builtin_ptrauth_auth_with_pc_and_resign: - // Convert oldDiscriminator (arg 2), oldPC (arg 3) and newDiscriminator (arg 5) to intptr_t + // Convert oldDiscriminator (arg 2), oldPC (arg 3) and newDiscriminator + // (arg 5) to intptr_t if (Args[2]->getType()->isPointerTy()) Args[2] = Builder.CreatePtrToInt(Args[2], IntPtrTy); if (Args[3]->getType()->isPointerTy()) diff --git a/clang/lib/Headers/ptrauth.h b/clang/lib/Headers/ptrauth.h index 2b9201d1c8a2b..3b34c42b22fb3 100644 --- a/clang/lib/Headers/ptrauth.h +++ b/clang/lib/Headers/ptrauth.h @@ -200,8 +200,10 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t; Do not pass a null pointer to this function. A null pointer will not successfully authenticate. */ -#define ptrauth_auth_with_pc_and_resign(__value, __old_key, __old_data, __old_pc, __new_key, __new_data) \ - __builtin_ptrauth_auth_with_pc_and_resign(__value, __old_key, __old_data, __old_pc, __new_key, __new_data) +#define ptrauth_auth_with_pc_and_resign(__value, __old_key, __old_data, \ + __old_pc, __new_key, __new_data) \ + __builtin_ptrauth_auth_with_pc_and_resign(__value, __old_key, __old_data, \ + __old_pc, __new_key, __new_data) /* Authenticate a pointer using one scheme, load 32bit value at offset addend from the pointer, and add this value to the pointer, sign using specified @@ -421,8 +423,8 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t; __value; \ }) -#define ptrauth_auth_with_pc_and_resign(__value, __old_key, __old_data, __old_pc, \ - __new_key, __new_data) \ +#define ptrauth_auth_with_pc_and_resign(__value, __old_key, __old_data, \ + __old_pc, __new_key, __new_data) \ ({ \ (void)__old_key; \ (void)__old_data; \ diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index c30398e905c39..ca681cb4b572c 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -7463,7 +7463,8 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) { auto *AuthKey = cast<ConstantInt>(Call.getArgOperand(1)); uint64_t Key = AuthKey->getZExtValue(); Check(Key == 0 || Key == 1, - "ptrauth.auth.with.pc.and.resign key must be IA (0) or IB (1)", &Call); + "ptrauth.auth.with.pc.and.resign key must be IA (0) or IB (1)", + &Call); break; } }; diff --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp index 524e9a8e34879..c70bd72617d4a 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp @@ -1787,13 +1787,16 @@ void AArch64DAGToDAGISel::SelectPtrauthResignWithPC(SDNode *N) { SDValue X17Copy = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL, AArch64::X17, Val, SDValue()); - SDValue X16Copy = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL, - AArch64::X16, AUTAddrDisc, X17Copy.getValue(1)); - SDValue X15Copy = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL, - AArch64::X15, AUTPC, X16Copy.getValue(1)); - - unsigned AuthOpc = (AUTKeyC == 0) ? AArch64::AUTIA171615 : AArch64::AUTIB171615; - SDNode *AUTH = CurDAG->getMachineNode(AuthOpc, DL, MVT::i64, X15Copy.getValue(1)); + SDValue X16Copy = + CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL, AArch64::X16, + AUTAddrDisc, X17Copy.getValue(1)); + SDValue X15Copy = CurDAG->getCopyToReg( + CurDAG->getEntryNode(), DL, AArch64::X15, AUTPC, X16Copy.getValue(1)); + + unsigned AuthOpc = + (AUTKeyC == 0) ? AArch64::AUTIA171615 : AArch64::AUTIB171615; + SDNode *AUTH = + CurDAG->getMachineNode(AuthOpc, DL, MVT::i64, X15Copy.getValue(1)); SDValue AuthedVal = SDValue(AUTH, 0); SDValue Ops[] = {AuthedVal, PACKey, PACConstDisc, PACAddrDisc}; diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp index 20f066ba71fc2..0e7b070133105 100644 --- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp +++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp @@ -6730,8 +6730,8 @@ bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &I, // Note: Only IA/IB keys supported for 171615 instructions, not DA/DB assert((AUTKey == 0 || AUTKey == 1) && "auth_with_pc_and_resign only supports IA and IB keys"); - unsigned AuthOpc = (AUTKey == 0) ? AArch64::AUTIA171615 - : AArch64::AUTIB171615; + unsigned AuthOpc = + (AUTKey == 0) ? AArch64::AUTIA171615 : AArch64::AUTIB171615; MIB.buildInstr(AuthOpc).constrainAllUses(TII, TRI, RBI); // Now sign the authenticated value (result is in X17) >From 35cd4ba0ea5b919c72f67e6a8b259af266c65879 Mon Sep 17 00:00:00 2001 From: Jon Roelofs <[email protected]> Date: Thu, 11 Jun 2026 12:09:16 -0700 Subject: [PATCH 3/7] __extension__ --- clang/lib/Headers/ptrauth.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Headers/ptrauth.h b/clang/lib/Headers/ptrauth.h index 3b34c42b22fb3..c521c3efcf0f9 100644 --- a/clang/lib/Headers/ptrauth.h +++ b/clang/lib/Headers/ptrauth.h @@ -425,7 +425,7 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t; #define ptrauth_auth_with_pc_and_resign(__value, __old_key, __old_data, \ __old_pc, __new_key, __new_data) \ - ({ \ + __extension__({ \ (void)__old_key; \ (void)__old_data; \ (void)__old_pc; \ >From 67af0015381fe85ac4e1f0428c3aea59b7899a30 Mon Sep 17 00:00:00 2001 From: Jon Roelofs <[email protected]> Date: Thu, 11 Jun 2026 12:34:39 -0700 Subject: [PATCH 4/7] separate ptr_discriminator/pc_discriminator --- clang/test/CodeGen/ptrauth-intrinsics.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clang/test/CodeGen/ptrauth-intrinsics.c b/clang/test/CodeGen/ptrauth-intrinsics.c index c98ce60dc9fc9..0ecf33c210586 100644 --- a/clang/test/CodeGen/ptrauth-intrinsics.c +++ b/clang/test/CodeGen/ptrauth-intrinsics.c @@ -7,6 +7,7 @@ void (*fnptr)(void); long int_discriminator; void *ptr_discriminator; +void *pc_discriminator; long signature; // CHECK-LABEL: define {{.*}}void @test_auth() @@ -71,14 +72,14 @@ void test_auth_load_relative_and_sign() { void test_auth_with_pc_and_resign() { // CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr, // CHECK-NEXT: [[DISC0:%.*]] = load ptr, ptr @ptr_discriminator, - // CHECK-NEXT: [[PC:%.*]] = load ptr, ptr @ptr_discriminator, + // CHECK-NEXT: [[PC:%.*]] = load ptr, ptr @pc_discriminator, // CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[PTR]] to i64 // CHECK-NEXT: [[DISC:%.*]] = ptrtoint ptr [[DISC0]] to i64 // CHECK-NEXT: [[PCVAL:%.*]] = ptrtoint ptr [[PC]] to i64 // CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.auth.with.pc.and.resign(i64 [[T0]], i32 0, i64 [[DISC]], i64 [[PCVAL]], i32 3, i64 15) // CHECK-NEXT: [[RESULT:%.*]] = inttoptr i64 [[T1]] to ptr // CHECK-NEXT: store ptr [[RESULT]], ptr @fnptr, - fnptr = __builtin_ptrauth_auth_with_pc_and_resign(fnptr, 0, ptr_discriminator, ptr_discriminator, 3, 15); + fnptr = __builtin_ptrauth_auth_with_pc_and_resign(fnptr, 0, ptr_discriminator, pc_discriminator, 3, 15); } // CHECK-LABEL: define {{.*}}void @test_blend_discriminator() >From 66f8132989c6c90017648e578298b19382cfc190 Mon Sep 17 00:00:00 2001 From: Jon Roelofs <[email protected]> Date: Thu, 11 Jun 2026 15:11:03 -0700 Subject: [PATCH 5/7] pseudo --- llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 81 +++- .../Target/AArch64/AArch64ISelDAGToDAG.cpp | 21 +- llvm/lib/Target/AArch64/AArch64InstrInfo.td | 18 + .../GISel/AArch64InstructionSelector.cpp | 43 +- ...rauth-intrinsic-auth-with-pc-and-resign.ll | 381 +++++++++++++++--- 5 files changed, 430 insertions(+), 114 deletions(-) diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index b16c0460adf38..47b57721bb635 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -190,13 +190,19 @@ class AArch64AsmPrinter : public AsmPrinter { void emitPtrauthTailCallHardening(const MachineInstr *TC); struct PtrAuthSchema { + // Standard schema: explicit address-discriminator operand, no PC blending. PtrAuthSchema(AArch64PACKey::ID Key, uint64_t IntDisc, const MachineOperand &AddrDiscOp); + // PC-blending schema (for auti[ab]171615): x16 is the implicit address + // discriminator; PCDisc (typically x15) carries the PC half. + PtrAuthSchema(AArch64PACKey::ID Key, uint64_t IntDisc, Register PCDisc); + AArch64PACKey::ID Key; uint64_t IntDisc; Register AddrDisc; bool AddrDiscIsKilled; + Register PCDisc; }; // Helper for emitting AUTRELLOADPAC: increment Pointer by Addend and then by @@ -209,7 +215,8 @@ class AArch64AsmPrinter : public AsmPrinter { void emitPtrauthApplyIndirectAddend(Register Pointer, Register Scratch, int64_t Addend); - // Emit the sequence for AUT or AUTPAC. Addend if AUTRELLOADPAC + // Emit the sequence for AUT or AUTPAC (or their PC-blending variants). + // Addend is only used for AUTRELLOADPAC. void emitPtrauthAuthResign(Register Pointer, Register Scratch, PtrAuthSchema AuthSchema, std::optional<PtrAuthSchema> SignSchema, @@ -2240,7 +2247,13 @@ bool AArch64AsmPrinter::emitDeactivationSymbolRelocation(Value *DS) { AArch64AsmPrinter::PtrAuthSchema::PtrAuthSchema( AArch64PACKey::ID Key, uint64_t IntDisc, const MachineOperand &AddrDiscOp) : Key(Key), IntDisc(IntDisc), AddrDisc(AddrDiscOp.getReg()), - AddrDiscIsKilled(AddrDiscOp.isKill()) {} + AddrDiscIsKilled(AddrDiscOp.isKill()), PCDisc(AArch64::NoRegister) {} + +AArch64AsmPrinter::PtrAuthSchema::PtrAuthSchema(AArch64PACKey::ID Key, + uint64_t IntDisc, + Register PCDisc) + : Key(Key), IntDisc(IntDisc), AddrDisc(AArch64::X16), + AddrDiscIsKilled(false), PCDisc(PCDisc) {} void AArch64AsmPrinter::emitPtrauthApplyIndirectAddend(Register Pointer, Register Scratch, @@ -2300,12 +2313,14 @@ void AArch64AsmPrinter::emitPtrauthAuthResign( std::optional<PtrAuthSchema> SignSchema, std::optional<int64_t> Addend, Value *DS) { const bool IsResign = SignSchema.has_value(); - // We expand AUT/AUTPAC into a sequence of the form + const bool WithPC = AuthSchema.PCDisc != AArch64::NoRegister; + + // We expand AUT/AUTPAC (and their PC-blending variants) into: // - // ; authenticate x16 - // ; check pointer in x16 + // ; authenticate Pointer + // ; check Pointer // Lsuccess: - // ; sign x16 (if AUTPAC) + // ; sign Pointer (if resign) // Lend: ; if not trapping on failure // // with the checking sequence chosen depending on whether/how we should check @@ -2337,13 +2352,34 @@ void AArch64AsmPrinter::emitPtrauthAuthResign( break; } - // Compute aut discriminator - Register AUTDiscReg = - emitPtrauthDiscriminator(AuthSchema.IntDisc, AuthSchema.AddrDisc, Scratch, - AuthSchema.AddrDiscIsKilled); - - if (!emitDeactivationSymbolRelocation(DS)) - emitAUT(AuthSchema.Key, Pointer, AUTDiscReg); + if (WithPC) { + // auti[ab]171615: pointer is in x17, address discriminator in x16, + // PC discriminator in x15. + assert(Pointer == AArch64::X17 && Scratch == AArch64::X16 && + "AUTPCPAC must use x17/x16 as Pointer/Scratch"); + + // Blend the constant discriminator into x16 in-place. + Register AUTDiscReg = + emitPtrauthDiscriminator(AuthSchema.IntDisc, Scratch, Scratch, + /*MayClobberAddrDisc=*/true); + assert((AUTDiscReg == Scratch || AUTDiscReg == AArch64::XZR) && + "AUT discriminator must be in x16 for auti[ab]171615"); + (void)AUTDiscReg; + + if (!emitDeactivationSymbolRelocation(DS)) { + unsigned AutOpc = (AuthSchema.Key == AArch64PACKey::IB) + ? AArch64::AUTIB171615 + : AArch64::AUTIA171615; + EmitToStreamer(MCInstBuilder(AutOpc)); + } + } else { + // Standard AUT: discriminator computed into Scratch, then auti[ab]. + Register AUTDiscReg = + emitPtrauthDiscriminator(AuthSchema.IntDisc, AuthSchema.AddrDisc, + Scratch, AuthSchema.AddrDiscIsKilled); + if (!emitDeactivationSymbolRelocation(DS)) + emitAUT(AuthSchema.Key, Pointer, AUTDiscReg); + } // Unchecked or checked-but-non-trapping AUT is just an "AUT": we're done. if (!IsResign && (!ShouldCheck || !ShouldTrap)) @@ -2361,7 +2397,7 @@ void AArch64AsmPrinter::emitPtrauthAuthResign( } // We already emitted unchecked and checked-but-non-trapping AUTs. - // That left us with trapping AUTs, and AUTPA/AUTRELLOADPACs. + // That left us with trapping AUTs, and AUTPAC/AUTRELLOADPACs. // Trapping AUTs don't need PAC: we're done. if (!IsResign) return; @@ -2369,7 +2405,7 @@ void AArch64AsmPrinter::emitPtrauthAuthResign( if (Addend.has_value()) emitPtrauthApplyIndirectAddend(Pointer, Scratch, *Addend); - // Compute pac discriminator into x17 + // Compute PAC discriminator into Scratch, then re-sign Pointer. Register PACDiscReg = emitPtrauthDiscriminator(SignSchema->IntDisc, SignSchema->AddrDisc, Scratch); emitPAC(SignSchema->Key, Pointer, PACDiscReg); @@ -3334,6 +3370,21 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) { return; } + case AArch64::AUTPCPAC: { + // x17 = pointer, x16 = AUTAddrDisc, x15 = PC discriminator (all implicit). + PtrAuthSchema AuthSchema((AArch64PACKey::ID)MI->getOperand(0).getImm(), + MI->getOperand(1).getImm(), + /*PCDisc=*/AArch64::X15); + + PtrAuthSchema SignSchema((AArch64PACKey::ID)MI->getOperand(2).getImm(), + MI->getOperand(3).getImm(), MI->getOperand(4)); + + emitPtrauthAuthResign(/*Pointer=*/AArch64::X17, /*Scratch=*/AArch64::X16, + AuthSchema, SignSchema, std::nullopt, + MI->getDeactivationSymbol()); + return; + } + case AArch64::AUTRELLOADPAC: { const Register Pointer = AArch64::X16; const Register Scratch = AArch64::X17; diff --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp index c70bd72617d4a..b2deefd50e9e4 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp @@ -1790,18 +1790,15 @@ void AArch64DAGToDAGISel::SelectPtrauthResignWithPC(SDNode *N) { SDValue X16Copy = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL, AArch64::X16, AUTAddrDisc, X17Copy.getValue(1)); - SDValue X15Copy = CurDAG->getCopyToReg( - CurDAG->getEntryNode(), DL, AArch64::X15, AUTPC, X16Copy.getValue(1)); - - unsigned AuthOpc = - (AUTKeyC == 0) ? AArch64::AUTIA171615 : AArch64::AUTIB171615; - SDNode *AUTH = - CurDAG->getMachineNode(AuthOpc, DL, MVT::i64, X15Copy.getValue(1)); - - SDValue AuthedVal = SDValue(AUTH, 0); - SDValue Ops[] = {AuthedVal, PACKey, PACConstDisc, PACAddrDisc}; - SDNode *PAC = CurDAG->getMachineNode(AArch64::PAC, DL, MVT::i64, Ops); - ReplaceNode(N, PAC); + SDValue X15Copy = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL, + AArch64::X15, AUTPC, + X16Copy.getValue(1)); + + SDValue Ops[] = {AUTKey, AUTConstDisc, PACKey, PACConstDisc, PACAddrDisc, + X15Copy.getValue(1)}; + SDNode *AUTPCPAC = + CurDAG->getMachineNode(AArch64::AUTPCPAC, DL, MVT::i64, Ops); + ReplaceNode(N, AUTPCPAC); } bool AArch64DAGToDAGISel::tryIndexedLoad(SDNode *N) { diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index 200808665c93e..ceb288e1e0e49 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -2277,6 +2277,24 @@ let Predicates = [HasPAuth] in { let Uses = [X16]; } + // AUT and re-PAC a value using different keys/data, with a PC value blended + // into the AUT'd discriminator. + // This directly manupulates x15,x16,x17, which are the only registers that + // certain OSs guarantee are safe to use for sensitive operations. + def AUTPCPAC + : Pseudo<(outs), + (ins i32imm:$AUTKey, i64imm:$AUTDisc, + i32imm:$PACKey, i64imm:$PACDisc, GPR64noip:$PACAddrDisc), + []>, Sched<[WriteI, ReadI]> { + let isCodeGenOnly = 1; + let hasSideEffects = 1; + let mayStore = 0; + let mayLoad = 0; + let Size = 48; + let Defs = [X17,X15,X16,NZCV]; + let Uses = [X15,X16,X17]; + } + // Similiar to AUTPAC, except a 32bit value is loaded at Addend offset from // pointer and this value is added to the pointer before signing. This // directly manipulates x16/x17, which are the only registers the OS diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp index 0e7b070133105..eea2e560aa68e 100644 --- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp +++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp @@ -6695,8 +6695,6 @@ bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &I, return true; } case Intrinsic::ptrauth_auth_with_pc_and_resign: { - // ptrauth.auth.with.pc.and.resign: authenticate with PC, then sign - // Operands: value, authKey, authDisc, authPC, signKey, signDisc Register DstReg = I.getOperand(0).getReg(); Register ValReg = I.getOperand(2).getReg(); uint64_t AUTKey = I.getOperand(3).getImm(); @@ -6705,52 +6703,37 @@ bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &I, uint64_t PACKey = I.getOperand(6).getImm(); Register PACDisc = I.getOperand(7).getReg(); - // Extract discriminators - Register AUTAddrDisc = AUTDisc; + assert((AUTKey == AArch64PACKey::IA || AUTKey == AArch64PACKey::IB) && + "auth_with_pc_and_resign only supports IA and IB keys"); + uint16_t AUTConstDiscC = 0; + Register AUTAddrDisc; std::tie(AUTConstDiscC, AUTAddrDisc) = extractPtrauthBlendDiscriminators(AUTDisc, MRI); - Register PACAddrDisc = PACDisc; uint16_t PACConstDiscC = 0; + Register PACAddrDisc; std::tie(PACConstDiscC, PACAddrDisc) = extractPtrauthBlendDiscriminators(PACDisc, MRI); - // Set up autia171615/autib171615: x17=value, x16=disc, x15=pc - MIB.buildCopy({AArch64::X17}, {ValReg}); - - // Handle discriminator - if NoRegister, use XZR if (AUTAddrDisc == AArch64::NoRegister) AUTAddrDisc = AArch64::XZR; - MIB.buildCopy({AArch64::X16}, {AUTAddrDisc}); - - MIB.buildCopy({AArch64::X15}, {AUTPC}); - - // Use the appropriate autia/autib instruction based on the key - // Note: Only IA/IB keys supported for 171615 instructions, not DA/DB - assert((AUTKey == 0 || AUTKey == 1) && - "auth_with_pc_and_resign only supports IA and IB keys"); - unsigned AuthOpc = - (AUTKey == 0) ? AArch64::AUTIA171615 : AArch64::AUTIB171615; - MIB.buildInstr(AuthOpc).constrainAllUses(TII, TRI, RBI); - - // Now sign the authenticated value (result is in X17) - // Use the PAC pseudo which handles the signing - Register AuthedReg = MRI.createVirtualRegister(&AArch64::GPR64RegClass); - MIB.buildCopy({AuthedReg}, Register(AArch64::X17)); - - // Handle sign discriminator - if NoRegister, use XZR if (PACAddrDisc == AArch64::NoRegister) PACAddrDisc = AArch64::XZR; - MIB.buildInstr(AArch64::PAC) - .addDef(DstReg) - .addUse(AuthedReg) + MIB.buildCopy({AArch64::X17}, {ValReg}); + MIB.buildCopy({AArch64::X16}, {AUTAddrDisc}); + MIB.buildCopy({AArch64::X15}, {AUTPC}); + + MIB.buildInstr(AArch64::AUTPCPAC) + .addImm(AUTKey) + .addImm(AUTConstDiscC) .addImm(PACKey) .addImm(PACConstDiscC) .addUse(PACAddrDisc) .constrainAllUses(TII, TRI, RBI); + MIB.buildCopy({DstReg}, Register(AArch64::X17)); RBI.constrainGenericRegister(DstReg, AArch64::GPR64RegClass, MRI); I.eraseFromParent(); return true; diff --git a/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-with-pc-and-resign.ll b/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-with-pc-and-resign.ll index fed448465a151..8184bb9c03c49 100644 --- a/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-with-pc-and-resign.ll +++ b/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-with-pc-and-resign.ll @@ -1,93 +1,360 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py -; RUN: llc < %s -mtriple arm64e-apple-darwin -mattr=+pauth-lr -verify-machineinstrs | FileCheck %s -; RUN: llc < %s -mtriple arm64e-apple-darwin -mattr=+pauth-lr -global-isel -global-isel-abort=1 -verify-machineinstrs | FileCheck %s +; RUN: llc < %s -mtriple arm64e-apple-darwin -mattr=+pauth-lr -global-isel=0 -verify-machineinstrs \ +; RUN: -aarch64-ptrauth-auth-checks=none | FileCheck %s --check-prefixes=UNCHECKED +; RUN: llc < %s -mtriple arm64e-apple-darwin -mattr=+pauth-lr -global-isel -global-isel-abort=1 -verify-machineinstrs \ +; RUN: -aarch64-ptrauth-auth-checks=none | FileCheck %s --check-prefixes=UNCHECKED -; TODO: The 171615 instructions are always unchecked, so auth-check modes don't change output +; RUN: llc < %s -mtriple arm64e-apple-darwin -mattr=+pauth-lr -global-isel=0 -verify-machineinstrs \ +; RUN: | FileCheck %s --check-prefixes=CHECKED +; RUN: llc < %s -mtriple arm64e-apple-darwin -mattr=+pauth-lr -global-isel -global-isel-abort=1 -verify-machineinstrs \ +; RUN: | FileCheck %s --check-prefixes=CHECKED + +; RUN: llc < %s -mtriple arm64e-apple-darwin -mattr=+pauth-lr -global-isel=0 -verify-machineinstrs \ +; RUN: -aarch64-ptrauth-auth-checks=trap | FileCheck %s --check-prefixes=TRAP +; RUN: llc < %s -mtriple arm64e-apple-darwin -mattr=+pauth-lr -global-isel -global-isel-abort=1 -verify-machineinstrs \ +; RUN: -aarch64-ptrauth-auth-checks=trap | FileCheck %s --check-prefixes=TRAP + +; RUN: llc < %s -mtriple arm64e-apple-darwin -mattr=+pauth-lr,+fpac -global-isel=0 -verify-machineinstrs \ +; RUN: | FileCheck %s --check-prefixes=UNCHECKED +; RUN: llc < %s -mtriple arm64e-apple-darwin -mattr=+pauth-lr,+fpac -global-isel -global-isel-abort=1 -verify-machineinstrs \ +; RUN: | FileCheck %s --check-prefixes=UNCHECKED target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" define i64 @test_resign_with_pc_ia_ia(i64 %arg, i64 %arg1, i64 %arg2, i64 %arg3) { -; CHECK-LABEL: test_resign_with_pc_ia_ia: -; CHECK: ; %bb.0: -; CHECK-NEXT: mov x17, x0 -; CHECK-NEXT: mov x16, x1 -; CHECK-NEXT: mov x15, x2 -; CHECK-NEXT: autia171615 -; CHECK-NEXT: mov x0, x17 -; CHECK-NEXT: pacia x0, x3 -; CHECK-NEXT: ret +; UNCHECKED-LABEL: test_resign_with_pc_ia_ia: +; UNCHECKED: ; %bb.0: +; UNCHECKED-NEXT: mov x17, x0 +; UNCHECKED-NEXT: mov x16, x1 +; UNCHECKED-NEXT: mov x15, x2 +; UNCHECKED-NEXT: autia171615 +; UNCHECKED-NEXT: pacia x17, x3 +; UNCHECKED-NEXT: mov x0, x17 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_resign_with_pc_ia_ia: +; CHECKED: ; %bb.0: +; CHECKED-NEXT: mov x17, x0 +; CHECKED-NEXT: mov x16, x1 +; CHECKED-NEXT: mov x15, x2 +; CHECKED-NEXT: autia171615 +; CHECKED-NEXT: mov x16, x17 +; CHECKED-NEXT: xpaci x16 +; CHECKED-NEXT: cmp x17, x16 +; CHECKED-NEXT: b.eq Lauth_success_0 +; CHECKED-NEXT: mov x17, x16 +; CHECKED-NEXT: b Lresign_end_0 +; CHECKED-NEXT: Lauth_success_0: +; CHECKED-NEXT: pacia x17, x3 +; CHECKED-NEXT: Lresign_end_0: +; CHECKED-NEXT: mov x0, x17 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_resign_with_pc_ia_ia: +; TRAP: ; %bb.0: +; TRAP-NEXT: mov x17, x0 +; TRAP-NEXT: mov x16, x1 +; TRAP-NEXT: mov x15, x2 +; TRAP-NEXT: autia171615 +; TRAP-NEXT: mov x16, x17 +; TRAP-NEXT: xpaci x16 +; TRAP-NEXT: cmp x17, x16 +; TRAP-NEXT: b.eq Lauth_success_0 +; TRAP-NEXT: brk #0xc470 +; TRAP-NEXT: Lauth_success_0: +; TRAP-NEXT: pacia x17, x3 +; TRAP-NEXT: mov x0, x17 +; TRAP-NEXT: ret %tmp = call i64 @llvm.ptrauth.auth.with.pc.and.resign(i64 %arg, i32 0, i64 %arg1, i64 %arg2, i32 0, i64 %arg3) ret i64 %tmp } define i64 @test_resign_with_pc_ib_ia(i64 %arg, i64 %arg1, i64 %arg2, i64 %arg3) { -; CHECK-LABEL: test_resign_with_pc_ib_ia: -; CHECK: ; %bb.0: -; CHECK-NEXT: mov x17, x0 -; CHECK-NEXT: mov x16, x1 -; CHECK-NEXT: mov x15, x2 -; CHECK-NEXT: autib171615 -; CHECK-NEXT: mov x0, x17 -; CHECK-NEXT: pacia x0, x3 -; CHECK-NEXT: ret +; UNCHECKED-LABEL: test_resign_with_pc_ib_ia: +; UNCHECKED: ; %bb.0: +; UNCHECKED-NEXT: mov x17, x0 +; UNCHECKED-NEXT: mov x16, x1 +; UNCHECKED-NEXT: mov x15, x2 +; UNCHECKED-NEXT: autib171615 +; UNCHECKED-NEXT: pacia x17, x3 +; UNCHECKED-NEXT: mov x0, x17 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_resign_with_pc_ib_ia: +; CHECKED: ; %bb.0: +; CHECKED-NEXT: mov x17, x0 +; CHECKED-NEXT: mov x16, x1 +; CHECKED-NEXT: mov x15, x2 +; CHECKED-NEXT: autib171615 +; CHECKED-NEXT: mov x16, x17 +; CHECKED-NEXT: xpaci x16 +; CHECKED-NEXT: cmp x17, x16 +; CHECKED-NEXT: b.eq Lauth_success_1 +; CHECKED-NEXT: mov x17, x16 +; CHECKED-NEXT: b Lresign_end_1 +; CHECKED-NEXT: Lauth_success_1: +; CHECKED-NEXT: pacia x17, x3 +; CHECKED-NEXT: Lresign_end_1: +; CHECKED-NEXT: mov x0, x17 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_resign_with_pc_ib_ia: +; TRAP: ; %bb.0: +; TRAP-NEXT: mov x17, x0 +; TRAP-NEXT: mov x16, x1 +; TRAP-NEXT: mov x15, x2 +; TRAP-NEXT: autib171615 +; TRAP-NEXT: mov x16, x17 +; TRAP-NEXT: xpaci x16 +; TRAP-NEXT: cmp x17, x16 +; TRAP-NEXT: b.eq Lauth_success_1 +; TRAP-NEXT: brk #0xc471 +; TRAP-NEXT: Lauth_success_1: +; TRAP-NEXT: pacia x17, x3 +; TRAP-NEXT: mov x0, x17 +; TRAP-NEXT: ret %tmp = call i64 @llvm.ptrauth.auth.with.pc.and.resign(i64 %arg, i32 1, i64 %arg1, i64 %arg2, i32 0, i64 %arg3) ret i64 %tmp } define i64 @test_resign_with_pc_ia_ib(i64 %arg, i64 %arg1, i64 %arg2, i64 %arg3) { -; CHECK-LABEL: test_resign_with_pc_ia_ib: -; CHECK: ; %bb.0: -; CHECK-NEXT: mov x17, x0 -; CHECK-NEXT: mov x16, x1 -; CHECK-NEXT: mov x15, x2 -; CHECK-NEXT: autia171615 -; CHECK-NEXT: mov x0, x17 -; CHECK-NEXT: pacib x0, x3 -; CHECK-NEXT: ret +; UNCHECKED-LABEL: test_resign_with_pc_ia_ib: +; UNCHECKED: ; %bb.0: +; UNCHECKED-NEXT: mov x17, x0 +; UNCHECKED-NEXT: mov x16, x1 +; UNCHECKED-NEXT: mov x15, x2 +; UNCHECKED-NEXT: autia171615 +; UNCHECKED-NEXT: pacib x17, x3 +; UNCHECKED-NEXT: mov x0, x17 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_resign_with_pc_ia_ib: +; CHECKED: ; %bb.0: +; CHECKED-NEXT: mov x17, x0 +; CHECKED-NEXT: mov x16, x1 +; CHECKED-NEXT: mov x15, x2 +; CHECKED-NEXT: autia171615 +; CHECKED-NEXT: mov x16, x17 +; CHECKED-NEXT: xpaci x16 +; CHECKED-NEXT: cmp x17, x16 +; CHECKED-NEXT: b.eq Lauth_success_2 +; CHECKED-NEXT: mov x17, x16 +; CHECKED-NEXT: b Lresign_end_2 +; CHECKED-NEXT: Lauth_success_2: +; CHECKED-NEXT: pacib x17, x3 +; CHECKED-NEXT: Lresign_end_2: +; CHECKED-NEXT: mov x0, x17 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_resign_with_pc_ia_ib: +; TRAP: ; %bb.0: +; TRAP-NEXT: mov x17, x0 +; TRAP-NEXT: mov x16, x1 +; TRAP-NEXT: mov x15, x2 +; TRAP-NEXT: autia171615 +; TRAP-NEXT: mov x16, x17 +; TRAP-NEXT: xpaci x16 +; TRAP-NEXT: cmp x17, x16 +; TRAP-NEXT: b.eq Lauth_success_2 +; TRAP-NEXT: brk #0xc470 +; TRAP-NEXT: Lauth_success_2: +; TRAP-NEXT: pacib x17, x3 +; TRAP-NEXT: mov x0, x17 +; TRAP-NEXT: ret %tmp = call i64 @llvm.ptrauth.auth.with.pc.and.resign(i64 %arg, i32 0, i64 %arg1, i64 %arg2, i32 1, i64 %arg3) ret i64 %tmp } define i64 @test_resign_with_pc_ib_ib(i64 %arg, i64 %arg1, i64 %arg2, i64 %arg3) { -; CHECK-LABEL: test_resign_with_pc_ib_ib: -; CHECK: ; %bb.0: -; CHECK-NEXT: mov x17, x0 -; CHECK-NEXT: mov x16, x1 -; CHECK-NEXT: mov x15, x2 -; CHECK-NEXT: autib171615 -; CHECK-NEXT: mov x0, x17 -; CHECK-NEXT: pacib x0, x3 -; CHECK-NEXT: ret +; UNCHECKED-LABEL: test_resign_with_pc_ib_ib: +; UNCHECKED: ; %bb.0: +; UNCHECKED-NEXT: mov x17, x0 +; UNCHECKED-NEXT: mov x16, x1 +; UNCHECKED-NEXT: mov x15, x2 +; UNCHECKED-NEXT: autib171615 +; UNCHECKED-NEXT: pacib x17, x3 +; UNCHECKED-NEXT: mov x0, x17 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_resign_with_pc_ib_ib: +; CHECKED: ; %bb.0: +; CHECKED-NEXT: mov x17, x0 +; CHECKED-NEXT: mov x16, x1 +; CHECKED-NEXT: mov x15, x2 +; CHECKED-NEXT: autib171615 +; CHECKED-NEXT: mov x16, x17 +; CHECKED-NEXT: xpaci x16 +; CHECKED-NEXT: cmp x17, x16 +; CHECKED-NEXT: b.eq Lauth_success_3 +; CHECKED-NEXT: mov x17, x16 +; CHECKED-NEXT: b Lresign_end_3 +; CHECKED-NEXT: Lauth_success_3: +; CHECKED-NEXT: pacib x17, x3 +; CHECKED-NEXT: Lresign_end_3: +; CHECKED-NEXT: mov x0, x17 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_resign_with_pc_ib_ib: +; TRAP: ; %bb.0: +; TRAP-NEXT: mov x17, x0 +; TRAP-NEXT: mov x16, x1 +; TRAP-NEXT: mov x15, x2 +; TRAP-NEXT: autib171615 +; TRAP-NEXT: mov x16, x17 +; TRAP-NEXT: xpaci x16 +; TRAP-NEXT: cmp x17, x16 +; TRAP-NEXT: b.eq Lauth_success_3 +; TRAP-NEXT: brk #0xc471 +; TRAP-NEXT: Lauth_success_3: +; TRAP-NEXT: pacib x17, x3 +; TRAP-NEXT: mov x0, x17 +; TRAP-NEXT: ret %tmp = call i64 @llvm.ptrauth.auth.with.pc.and.resign(i64 %arg, i32 1, i64 %arg1, i64 %arg2, i32 1, i64 %arg3) ret i64 %tmp } define i64 @test_resign_with_pc_iza_ib(i64 %arg, i64 %arg1, i64 %arg2) { -; CHECK-LABEL: test_resign_with_pc_iza_ib: -; CHECK: ; %bb.0: -; CHECK-NEXT: mov x17, x0 -; CHECK-NEXT: mov x16, #0 ; =0x0 -; CHECK-NEXT: mov x15, x1 -; CHECK-NEXT: autia171615 -; CHECK-NEXT: mov x0, x17 -; CHECK-NEXT: pacib x0, x2 -; CHECK-NEXT: ret +; UNCHECKED-LABEL: test_resign_with_pc_iza_ib: +; UNCHECKED: ; %bb.0: +; UNCHECKED-NEXT: mov x17, x0 +; UNCHECKED-NEXT: mov x16, #0 ; =0x0 +; UNCHECKED-NEXT: mov x15, x1 +; UNCHECKED-NEXT: autia171615 +; UNCHECKED-NEXT: pacib x17, x2 +; UNCHECKED-NEXT: mov x0, x17 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_resign_with_pc_iza_ib: +; CHECKED: ; %bb.0: +; CHECKED-NEXT: mov x17, x0 +; CHECKED-NEXT: mov x16, #0 ; =0x0 +; CHECKED-NEXT: mov x15, x1 +; CHECKED-NEXT: autia171615 +; CHECKED-NEXT: mov x16, x17 +; CHECKED-NEXT: xpaci x16 +; CHECKED-NEXT: cmp x17, x16 +; CHECKED-NEXT: b.eq Lauth_success_4 +; CHECKED-NEXT: mov x17, x16 +; CHECKED-NEXT: b Lresign_end_4 +; CHECKED-NEXT: Lauth_success_4: +; CHECKED-NEXT: pacib x17, x2 +; CHECKED-NEXT: Lresign_end_4: +; CHECKED-NEXT: mov x0, x17 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_resign_with_pc_iza_ib: +; TRAP: ; %bb.0: +; TRAP-NEXT: mov x17, x0 +; TRAP-NEXT: mov x16, #0 ; =0x0 +; TRAP-NEXT: mov x15, x1 +; TRAP-NEXT: autia171615 +; TRAP-NEXT: mov x16, x17 +; TRAP-NEXT: xpaci x16 +; TRAP-NEXT: cmp x17, x16 +; TRAP-NEXT: b.eq Lauth_success_4 +; TRAP-NEXT: brk #0xc470 +; TRAP-NEXT: Lauth_success_4: +; TRAP-NEXT: pacib x17, x2 +; TRAP-NEXT: mov x0, x17 +; TRAP-NEXT: ret %tmp = call i64 @llvm.ptrauth.auth.with.pc.and.resign(i64 %arg, i32 0, i64 0, i64 %arg1, i32 1, i64 %arg2) ret i64 %tmp } define i64 @test_resign_with_pc_ia_izb(i64 %arg, i64 %arg1, i64 %arg2) { -; CHECK-LABEL: test_resign_with_pc_ia_izb: -; CHECK: ; %bb.0: -; CHECK-NEXT: mov x17, x0 -; CHECK-NEXT: mov x16, x1 -; CHECK-NEXT: mov x15, x2 -; CHECK-NEXT: autia171615 -; CHECK-NEXT: mov x0, x17 -; CHECK-NEXT: pacizb x0 -; CHECK-NEXT: ret +; UNCHECKED-LABEL: test_resign_with_pc_ia_izb: +; UNCHECKED: ; %bb.0: +; UNCHECKED-NEXT: mov x17, x0 +; UNCHECKED-NEXT: mov x16, x1 +; UNCHECKED-NEXT: mov x15, x2 +; UNCHECKED-NEXT: autia171615 +; UNCHECKED-NEXT: pacizb x17 +; UNCHECKED-NEXT: mov x0, x17 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_resign_with_pc_ia_izb: +; CHECKED: ; %bb.0: +; CHECKED-NEXT: mov x17, x0 +; CHECKED-NEXT: mov x16, x1 +; CHECKED-NEXT: mov x15, x2 +; CHECKED-NEXT: autia171615 +; CHECKED-NEXT: mov x16, x17 +; CHECKED-NEXT: xpaci x16 +; CHECKED-NEXT: cmp x17, x16 +; CHECKED-NEXT: b.eq Lauth_success_5 +; CHECKED-NEXT: mov x17, x16 +; CHECKED-NEXT: b Lresign_end_5 +; CHECKED-NEXT: Lauth_success_5: +; CHECKED-NEXT: pacizb x17 +; CHECKED-NEXT: Lresign_end_5: +; CHECKED-NEXT: mov x0, x17 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_resign_with_pc_ia_izb: +; TRAP: ; %bb.0: +; TRAP-NEXT: mov x17, x0 +; TRAP-NEXT: mov x16, x1 +; TRAP-NEXT: mov x15, x2 +; TRAP-NEXT: autia171615 +; TRAP-NEXT: mov x16, x17 +; TRAP-NEXT: xpaci x16 +; TRAP-NEXT: cmp x17, x16 +; TRAP-NEXT: b.eq Lauth_success_5 +; TRAP-NEXT: brk #0xc470 +; TRAP-NEXT: Lauth_success_5: +; TRAP-NEXT: pacizb x17 +; TRAP-NEXT: mov x0, x17 +; TRAP-NEXT: ret %tmp = call i64 @llvm.ptrauth.auth.with.pc.and.resign(i64 %arg, i32 0, i64 %arg1, i64 %arg2, i32 1, i64 0) ret i64 %tmp } +; The "ptrauth-auth-traps" function attribute enables trapping in default +; (checked) mode, with the same behavior as -aarch64-ptrauth-auth-checks=trap. +define i64 @test_resign_with_pc_trap_attribute(i64 %arg, i64 %arg1, i64 %arg2, i64 %arg3) "ptrauth-auth-traps" { +; UNCHECKED-LABEL: test_resign_with_pc_trap_attribute: +; UNCHECKED: ; %bb.0: +; UNCHECKED-NEXT: mov x17, x0 +; UNCHECKED-NEXT: mov x16, x1 +; UNCHECKED-NEXT: mov x15, x2 +; UNCHECKED-NEXT: autia171615 +; UNCHECKED-NEXT: pacia x17, x3 +; UNCHECKED-NEXT: mov x0, x17 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_resign_with_pc_trap_attribute: +; CHECKED: ; %bb.0: +; CHECKED-NEXT: mov x17, x0 +; CHECKED-NEXT: mov x16, x1 +; CHECKED-NEXT: mov x15, x2 +; CHECKED-NEXT: autia171615 +; CHECKED-NEXT: mov x16, x17 +; CHECKED-NEXT: xpaci x16 +; CHECKED-NEXT: cmp x17, x16 +; CHECKED-NEXT: b.eq Lauth_success_6 +; CHECKED-NEXT: brk #0xc470 +; CHECKED-NEXT: Lauth_success_6: +; CHECKED-NEXT: pacia x17, x3 +; CHECKED-NEXT: mov x0, x17 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_resign_with_pc_trap_attribute: +; TRAP: ; %bb.0: +; TRAP-NEXT: mov x17, x0 +; TRAP-NEXT: mov x16, x1 +; TRAP-NEXT: mov x15, x2 +; TRAP-NEXT: autia171615 +; TRAP-NEXT: mov x16, x17 +; TRAP-NEXT: xpaci x16 +; TRAP-NEXT: cmp x17, x16 +; TRAP-NEXT: b.eq Lauth_success_6 +; TRAP-NEXT: brk #0xc470 +; TRAP-NEXT: Lauth_success_6: +; TRAP-NEXT: pacia x17, x3 +; TRAP-NEXT: mov x0, x17 +; TRAP-NEXT: ret + %tmp = call i64 @llvm.ptrauth.auth.with.pc.and.resign(i64 %arg, i32 0, i64 %arg1, i64 %arg2, i32 0, i64 %arg3) + ret i64 %tmp +} + declare i64 @llvm.ptrauth.auth.with.pc.and.resign(i64, i32, i64, i64, i32, i64) >From 5aaa9ac28081e59789156506f5a566a62816c5d9 Mon Sep 17 00:00:00 2001 From: Jon Roelofs <[email protected]> Date: Thu, 11 Jun 2026 15:17:04 -0700 Subject: [PATCH 6/7] clang-format --- llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp index b2deefd50e9e4..e1637e66e2ba5 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp @@ -1790,12 +1790,11 @@ void AArch64DAGToDAGISel::SelectPtrauthResignWithPC(SDNode *N) { SDValue X16Copy = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL, AArch64::X16, AUTAddrDisc, X17Copy.getValue(1)); - SDValue X15Copy = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL, - AArch64::X15, AUTPC, - X16Copy.getValue(1)); + SDValue X15Copy = CurDAG->getCopyToReg( + CurDAG->getEntryNode(), DL, AArch64::X15, AUTPC, X16Copy.getValue(1)); - SDValue Ops[] = {AUTKey, AUTConstDisc, PACKey, PACConstDisc, PACAddrDisc, - X15Copy.getValue(1)}; + SDValue Ops[] = {AUTKey, AUTConstDisc, PACKey, + PACConstDisc, PACAddrDisc, X15Copy.getValue(1)}; SDNode *AUTPCPAC = CurDAG->getMachineNode(AArch64::AUTPCPAC, DL, MVT::i64, Ops); ReplaceNode(N, AUTPCPAC); >From 5fcf19f7fceca8a06965cfc69adbe42f927b25aa Mon Sep 17 00:00:00 2001 From: Jon Roelofs <[email protected]> Date: Fri, 12 Jun 2026 09:31:38 -0700 Subject: [PATCH 7/7] no constant discriminator on aut --- llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 110 +++++++++++------- .../Target/AArch64/AArch64ISelDAGToDAG.cpp | 19 ++- llvm/lib/Target/AArch64/AArch64InstrInfo.td | 11 +- .../GISel/AArch64InstructionSelector.cpp | 12 +- 4 files changed, 79 insertions(+), 73 deletions(-) diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index 47b57721bb635..3a84c275acce9 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -190,13 +190,10 @@ class AArch64AsmPrinter : public AsmPrinter { void emitPtrauthTailCallHardening(const MachineInstr *TC); struct PtrAuthSchema { - // Standard schema: explicit address-discriminator operand, no PC blending. - PtrAuthSchema(AArch64PACKey::ID Key, uint64_t IntDisc, - const MachineOperand &AddrDiscOp); - - // PC-blending schema (for auti[ab]171615): x16 is the implicit address - // discriminator; PCDisc (typically x15) carries the PC half. - PtrAuthSchema(AArch64PACKey::ID Key, uint64_t IntDisc, Register PCDisc); + static PtrAuthSchema CreateImmReg(AArch64PACKey::ID Key, uint64_t IntDisc, + const MachineOperand &AddrDiscOp); + static PtrAuthSchema CreateRegReg(AArch64PACKey::ID Key, Register AddrDisc, + Register PCDisc); AArch64PACKey::ID Key; uint64_t IntDisc; @@ -2244,16 +2241,30 @@ bool AArch64AsmPrinter::emitDeactivationSymbolRelocation(Value *DS) { return false; } -AArch64AsmPrinter::PtrAuthSchema::PtrAuthSchema( - AArch64PACKey::ID Key, uint64_t IntDisc, const MachineOperand &AddrDiscOp) - : Key(Key), IntDisc(IntDisc), AddrDisc(AddrDiscOp.getReg()), - AddrDiscIsKilled(AddrDiscOp.isKill()), PCDisc(AArch64::NoRegister) {} +AArch64AsmPrinter::PtrAuthSchema AArch64AsmPrinter::PtrAuthSchema::CreateImmReg( + AArch64PACKey::ID Key, uint64_t IntDisc, const MachineOperand &AddrDiscOp) { + PtrAuthSchema Schema{ + .Key = Key, + .IntDisc = IntDisc, + .AddrDisc = AddrDiscOp.getReg(), + .AddrDiscIsKilled = AddrDiscOp.isKill(), + }; + return Schema; +} -AArch64AsmPrinter::PtrAuthSchema::PtrAuthSchema(AArch64PACKey::ID Key, - uint64_t IntDisc, - Register PCDisc) - : Key(Key), IntDisc(IntDisc), AddrDisc(AArch64::X16), - AddrDiscIsKilled(false), PCDisc(PCDisc) {} +AArch64AsmPrinter::PtrAuthSchema AArch64AsmPrinter::PtrAuthSchema::CreateRegReg( + AArch64PACKey::ID Key, Register AddrDisc, Register PCDisc) { + assert(PCDisc != AArch64::NoRegister && + "Use CreateImmReg for non-PC schemas"); + PtrAuthSchema Schema{ + .Key = Key, + .IntDisc = 0, + .AddrDisc = AddrDisc, + .AddrDiscIsKilled = true, + .PCDisc = PCDisc, + }; + return Schema; +} void AArch64AsmPrinter::emitPtrauthApplyIndirectAddend(Register Pointer, Register Scratch, @@ -2353,18 +2364,21 @@ void AArch64AsmPrinter::emitPtrauthAuthResign( } if (WithPC) { - // auti[ab]171615: pointer is in x17, address discriminator in x16, - // PC discriminator in x15. assert(Pointer == AArch64::X17 && Scratch == AArch64::X16 && - "AUTPCPAC must use x17/x16 as Pointer/Scratch"); + "AUTx15x16x17PAC must use x17/x16 as Pointer/Scratch"); - // Blend the constant discriminator into x16 in-place. - Register AUTDiscReg = - emitPtrauthDiscriminator(AuthSchema.IntDisc, Scratch, Scratch, - /*MayClobberAddrDisc=*/true); - assert((AUTDiscReg == Scratch || AUTDiscReg == AArch64::XZR) && - "AUT discriminator must be in x16 for auti[ab]171615"); - (void)AUTDiscReg; + assert(AuthSchema.AddrDisc == AArch64::X16 && + "AUTx15x16x17PAC requires address discriminator in X16"); + + assert(AuthSchema.PCDisc == AArch64::X15 && + "AUTx15x16x17PAC requires PC discriminator in X15"); + + assert(AuthSchema.IntDisc == 0 && + "AUTx15x16x17PAC does not support IntDisc"); + + assert((AuthSchema.Key == AArch64PACKey::IB || + AuthSchema.Key == AArch64PACKey::IA) && + "AUTx15x16x17PAC only supports AUT-ing with IA/IB"); if (!emitDeactivationSymbolRelocation(DS)) { unsigned AutOpc = (AuthSchema.Key == AArch64PACKey::IB) @@ -3335,8 +3349,9 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) { const Register Pointer = AArch64::X16; const Register Scratch = AArch64::X17; - PtrAuthSchema AuthSchema((AArch64PACKey::ID)MI->getOperand(0).getImm(), - MI->getOperand(1).getImm(), MI->getOperand(2)); + auto AuthSchema = PtrAuthSchema::CreateImmReg( + (AArch64PACKey::ID)MI->getOperand(0).getImm(), + MI->getOperand(1).getImm(), MI->getOperand(2)); emitPtrauthAuthResign(Pointer, Scratch, AuthSchema, std::nullopt, std::nullopt, MI->getDeactivationSymbol()); @@ -3347,8 +3362,9 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) { const Register Pointer = MI->getOperand(0).getReg(); const Register Scratch = MI->getOperand(1).getReg(); - PtrAuthSchema AuthSchema((AArch64PACKey::ID)MI->getOperand(3).getImm(), - MI->getOperand(4).getImm(), MI->getOperand(5)); + auto AuthSchema = PtrAuthSchema::CreateImmReg( + (AArch64PACKey::ID)MI->getOperand(3).getImm(), + MI->getOperand(4).getImm(), MI->getOperand(5)); emitPtrauthAuthResign(Pointer, Scratch, AuthSchema, std::nullopt, std::nullopt, MI->getDeactivationSymbol()); @@ -3359,25 +3375,27 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) { const Register Pointer = AArch64::X16; const Register Scratch = AArch64::X17; - PtrAuthSchema AuthSchema((AArch64PACKey::ID)MI->getOperand(0).getImm(), - MI->getOperand(1).getImm(), MI->getOperand(2)); + auto AuthSchema = PtrAuthSchema::CreateImmReg( + (AArch64PACKey::ID)MI->getOperand(0).getImm(), + MI->getOperand(1).getImm(), MI->getOperand(2)); - PtrAuthSchema SignSchema((AArch64PACKey::ID)MI->getOperand(3).getImm(), - MI->getOperand(4).getImm(), MI->getOperand(5)); + auto SignSchema = PtrAuthSchema::CreateImmReg( + (AArch64PACKey::ID)MI->getOperand(3).getImm(), + MI->getOperand(4).getImm(), MI->getOperand(5)); emitPtrauthAuthResign(Pointer, Scratch, AuthSchema, SignSchema, std::nullopt, MI->getDeactivationSymbol()); return; } - case AArch64::AUTPCPAC: { - // x17 = pointer, x16 = AUTAddrDisc, x15 = PC discriminator (all implicit). - PtrAuthSchema AuthSchema((AArch64PACKey::ID)MI->getOperand(0).getImm(), - MI->getOperand(1).getImm(), - /*PCDisc=*/AArch64::X15); + case AArch64::AUTx15x16x17PAC: { + auto AuthSchema = PtrAuthSchema::CreateRegReg( + (AArch64PACKey::ID)MI->getOperand(0).getImm(), AArch64::X16, + AArch64::X15); - PtrAuthSchema SignSchema((AArch64PACKey::ID)MI->getOperand(2).getImm(), - MI->getOperand(3).getImm(), MI->getOperand(4)); + auto SignSchema = PtrAuthSchema::CreateImmReg( + (AArch64PACKey::ID)MI->getOperand(1).getImm(), + MI->getOperand(2).getImm(), MI->getOperand(3)); emitPtrauthAuthResign(/*Pointer=*/AArch64::X17, /*Scratch=*/AArch64::X16, AuthSchema, SignSchema, std::nullopt, @@ -3389,11 +3407,13 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) { const Register Pointer = AArch64::X16; const Register Scratch = AArch64::X17; - PtrAuthSchema AuthSchema((AArch64PACKey::ID)MI->getOperand(0).getImm(), - MI->getOperand(1).getImm(), MI->getOperand(2)); + auto AuthSchema = PtrAuthSchema::CreateImmReg( + (AArch64PACKey::ID)MI->getOperand(0).getImm(), + MI->getOperand(1).getImm(), MI->getOperand(2)); - PtrAuthSchema SignSchema((AArch64PACKey::ID)MI->getOperand(3).getImm(), - MI->getOperand(4).getImm(), MI->getOperand(5)); + auto SignSchema = PtrAuthSchema::CreateImmReg( + (AArch64PACKey::ID)MI->getOperand(3).getImm(), + MI->getOperand(4).getImm(), MI->getOperand(5)); emitPtrauthAuthResign(Pointer, Scratch, AuthSchema, SignSchema, MI->getOperand(6).getImm(), diff --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp index e1637e66e2ba5..21e5077e315e5 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp @@ -1777,27 +1777,22 @@ void AArch64DAGToDAGISel::SelectPtrauthResignWithPC(SDNode *N) { AUTKey = CurDAG->getTargetConstant(AUTKeyC, DL, MVT::i64); PACKey = CurDAG->getTargetConstant(PACKeyC, DL, MVT::i64); - SDValue AUTAddrDisc, AUTConstDisc; - std::tie(AUTConstDisc, AUTAddrDisc) = - extractPtrauthBlendDiscriminators(AUTDisc, CurDAG); - SDValue PACAddrDisc, PACConstDisc; std::tie(PACConstDisc, PACAddrDisc) = extractPtrauthBlendDiscriminators(PACDisc, CurDAG); SDValue X17Copy = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL, AArch64::X17, Val, SDValue()); - SDValue X16Copy = - CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL, AArch64::X16, - AUTAddrDisc, X17Copy.getValue(1)); + SDValue X16Copy = CurDAG->getCopyToReg( + CurDAG->getEntryNode(), DL, AArch64::X16, AUTDisc, X17Copy.getValue(1)); SDValue X15Copy = CurDAG->getCopyToReg( CurDAG->getEntryNode(), DL, AArch64::X15, AUTPC, X16Copy.getValue(1)); - SDValue Ops[] = {AUTKey, AUTConstDisc, PACKey, - PACConstDisc, PACAddrDisc, X15Copy.getValue(1)}; - SDNode *AUTPCPAC = - CurDAG->getMachineNode(AArch64::AUTPCPAC, DL, MVT::i64, Ops); - ReplaceNode(N, AUTPCPAC); + SDValue Ops[] = {AUTKey, PACKey, PACConstDisc, PACAddrDisc, + X15Copy.getValue(1)}; + SDNode *AUTx15x16x17PAC = + CurDAG->getMachineNode(AArch64::AUTx15x16x17PAC, DL, MVT::i64, Ops); + ReplaceNode(N, AUTx15x16x17PAC); } bool AArch64DAGToDAGISel::tryIndexedLoad(SDNode *N) { diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index ceb288e1e0e49..21184132b55b5 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -2277,13 +2277,12 @@ let Predicates = [HasPAuth] in { let Uses = [X16]; } - // AUT and re-PAC a value using different keys/data, with a PC value blended - // into the AUT'd discriminator. - // This directly manupulates x15,x16,x17, which are the only registers that - // certain OSs guarantee are safe to use for sensitive operations. - def AUTPCPAC + // AUT (using x15=PC, x16=addr disc, x17=pointer) and re-PAC a value using + // different keys/data. This directly manipulates x15/x16/x17, which are the + // only registers certain OSs guarantee are safe to use for sensitive ops. + def AUTx15x16x17PAC : Pseudo<(outs), - (ins i32imm:$AUTKey, i64imm:$AUTDisc, + (ins i32imm:$AUTKey, i32imm:$PACKey, i64imm:$PACDisc, GPR64noip:$PACAddrDisc), []>, Sched<[WriteI, ReadI]> { let isCodeGenOnly = 1; diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp index eea2e560aa68e..080045265b9ae 100644 --- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp +++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp @@ -6706,28 +6706,20 @@ bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &I, assert((AUTKey == AArch64PACKey::IA || AUTKey == AArch64PACKey::IB) && "auth_with_pc_and_resign only supports IA and IB keys"); - uint16_t AUTConstDiscC = 0; - Register AUTAddrDisc; - std::tie(AUTConstDiscC, AUTAddrDisc) = - extractPtrauthBlendDiscriminators(AUTDisc, MRI); - uint16_t PACConstDiscC = 0; Register PACAddrDisc; std::tie(PACConstDiscC, PACAddrDisc) = extractPtrauthBlendDiscriminators(PACDisc, MRI); - if (AUTAddrDisc == AArch64::NoRegister) - AUTAddrDisc = AArch64::XZR; if (PACAddrDisc == AArch64::NoRegister) PACAddrDisc = AArch64::XZR; MIB.buildCopy({AArch64::X17}, {ValReg}); - MIB.buildCopy({AArch64::X16}, {AUTAddrDisc}); + MIB.buildCopy({AArch64::X16}, {AUTDisc}); MIB.buildCopy({AArch64::X15}, {AUTPC}); - MIB.buildInstr(AArch64::AUTPCPAC) + MIB.buildInstr(AArch64::AUTx15x16x17PAC) .addImm(AUTKey) - .addImm(AUTConstDiscC) .addImm(PACKey) .addImm(PACConstDiscC) .addUse(PACAddrDisc) _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
