[clang] [llvm] [arm64e] Add a builtin + intrinsic for arm64e PAuth_LR: __builtin_ptr_auth_auth_with_pc_and_resign (PR #202742)
Jon Roelofs via cfe-commits
cfe-commits at lists.llvm.org
Thu Jun 11 13:01:44 PDT 2026
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 <jonathan_roelofs at apple.com>
Date: Tue, 9 Jun 2026 12:01:23 -0700
Subject: [PATCH 1/4] [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 <jonathan_roelofs at apple.com>
Date: Tue, 9 Jun 2026 12:04:54 -0700
Subject: [PATCH 2/4] 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 <jonathan_roelofs at apple.com>
Date: Thu, 11 Jun 2026 12:09:16 -0700
Subject: [PATCH 3/4] __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 <jonathan_roelofs at apple.com>
Date: Thu, 11 Jun 2026 12:34:39 -0700
Subject: [PATCH 4/4] 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()
More information about the cfe-commits
mailing list