From 0ab5d47bfdb77d8e6870e6f80714790f0317ad8a Mon Sep 17 00:00:00 2001 From: Abhay Kanhere Date: Wed, 28 May 2025 16:35:05 -0700 Subject: [PATCH 1/2] [CodeGen][AArch64] ptrauth intrinsic to safely construct relative pointer for swift coroutines A ptrauth intrinsic for swift co-routine support that allows creation of signed pointer from offset stored at address relative to the pointer. Following C-like pseudo code (ignoring keys,discriminators) explains its operation: let rawptr = PACauth(inputptr); return PACsign( rawptr + *(int32*)(rawptr+addend) ) What: Authenticate a signed pointer, load a 32bit value at offset 'addend' from pointer, add this value to pointer, sign this new pointer. builtin: __builtin_ptrauth_auth_load_relative_and_sign intrinsic: ptrauth_auth_resign_load_relative note: conflicts resolved llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp due to upstream change in args for emitPtrauthAuthResign --- clang/include/clang/Basic/Builtins.td | 6 + .../clang/Basic/DiagnosticSemaKinds.td | 2 + clang/lib/CodeGen/CGBuiltin.cpp | 6 +- clang/lib/Headers/ptrauth.h | 37 +- clang/lib/Sema/SemaChecking.cpp | 28 + clang/test/CodeGen/ptrauth-intrinsics.c | 12 + clang/test/Sema/ptrauth.c | 23 + llvm/include/llvm/IR/Intrinsics.td | 13 + llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 92 +++- .../Target/AArch64/AArch64ISelDAGToDAG.cpp | 37 +- llvm/lib/Target/AArch64/AArch64InstrInfo.td | 20 + .../GISel/AArch64InstructionSelector.cpp | 36 ++ llvm/lib/Transforms/Utils/Local.cpp | 1 + ...uth-intrinsic-auth-resign-relative-load.ll | 516 ++++++++++++++++++ 14 files changed, 808 insertions(+), 21 deletions(-) create mode 100644 llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign-relative-load.ll diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index c81714e9b009d..ce5ac81474de5 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4655,6 +4655,12 @@ def PtrauthAuthAndResign : Builtin { let Prototype = "void*(void*,int,void*,int,void*)"; } +def PtrauthAuthLoadRelativeAndSign : Builtin { + let Spellings = ["__builtin_ptrauth_auth_load_relative_and_sign"]; + let Attributes = [CustomTypeChecking, NoThrow]; + let Prototype = "void*(void*,int,void*,int,void*,ptrdiff_t)"; +} + def PtrauthAuth : Builtin { let Spellings = ["__builtin_ptrauth_auth"]; let Attributes = [CustomTypeChecking, NoThrow]; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 27d2152805f97..0f1271a18445e 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -11097,6 +11097,8 @@ def err_builtin_requires_language : Error<"'%0' is only available in %1">; def err_constant_integer_arg_type : Error< "argument to %0 must be a constant integer">; +def err_constant_integer_last_arg_type + : Error<"last argument to %0 must be a constant integer">; def ext_mixed_decls_code : Extension< "mixing declarations and code is a C99 extension">, diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index e1f7ea08837c5..8cba775db63e5 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -5601,12 +5601,13 @@ 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_load_relative_and_sign: case Builtin::BI__builtin_ptrauth_blend_discriminator: case Builtin::BI__builtin_ptrauth_sign_generic_data: case Builtin::BI__builtin_ptrauth_sign_unauthenticated: case Builtin::BI__builtin_ptrauth_strip: { // Emit the arguments. - SmallVector Args; + SmallVector Args; for (auto argExpr : E->arguments()) Args.push_back(EmitScalarExpr(argExpr)); @@ -5617,6 +5618,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, switch (BuiltinID) { case Builtin::BI__builtin_ptrauth_auth_and_resign: + case Builtin::BI__builtin_ptrauth_auth_load_relative_and_sign: if (Args[4]->getType()->isPointerTy()) Args[4] = Builder.CreatePtrToInt(Args[4], IntPtrTy); [[fallthrough]]; @@ -5644,6 +5646,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_load_relative_and_sign: + return Intrinsic::ptrauth_resign_load_relative; case Builtin::BI__builtin_ptrauth_blend_discriminator: return Intrinsic::ptrauth_blend; case Builtin::BI__builtin_ptrauth_sign_generic_data: diff --git a/clang/lib/Headers/ptrauth.h b/clang/lib/Headers/ptrauth.h index 7f7d387cbdfda..2eb23803f9faa 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 one scheme, load 32bit value at offset addend + from the pointer, and add this value to the pointer, sign using specified + 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 addend must be an immediate ptrdiff_t value. + 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. + + Do not pass a null pointer to this function. A null pointer + will not successfully authenticate. */ +#define ptrauth_auth_load_relative_and_sign(__value, __old_key, __old_data, \ + __new_key, __new_data, __addend) \ + __builtin_ptrauth_auth_load_relative_and_sign( \ + __value, __old_key, __old_data, __new_key, __new_data, __addend) + /* Authenticate a pointer using one scheme and resign it as a C function pointer. @@ -351,6 +376,17 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t; __value; \ }) +#define ptrauth_auth_load_relative_and_sign(__value, __old_key, __old_data, \ + __new_key, __new_data, __addend) \ + ({ \ + (void)__old_key; \ + (void)__old_data; \ + (void)__new_key; \ + (void)__new_data; \ + const char *__value_tmp = (const char *)(__value); \ + (void *)(__value_tmp + *(const int *)(__value_tmp + (__addend))); \ + }) + #define ptrauth_auth_function(__value, __old_key, __old_data) \ ({ \ (void)__old_key; \ @@ -380,7 +416,6 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t; ((ptrauth_generic_signature_t)0); \ }) - #define ptrauth_cxx_vtable_pointer(key, address_discrimination, \ extra_discrimination...) diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index c74b67106ad74..d4b02487a6adc 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -1814,6 +1814,32 @@ static ExprResult PointerAuthAuthAndResign(Sema &S, CallExpr *Call) { return Call; } +static ExprResult PointerAuthAuthLoadRelativeAndSign(Sema &S, CallExpr *Call) { + if (S.checkArgCount(Call, 6)) + return ExprError(); + if (checkPointerAuthEnabled(S, Call)) + return ExprError(); + const Expr *AddendExpr = Call->getArg(5); + bool AddendIsConstInt = AddendExpr->isIntegerConstantExpr(S.Context); + if (!AddendIsConstInt) { + const Expr *Arg = Call->getArg(5)->IgnoreParenImpCasts(); + DeclRefExpr *DRE = cast(Call->getCallee()->IgnoreParenCasts()); + FunctionDecl *FDecl = cast(DRE->getDecl()); + S.Diag(Arg->getBeginLoc(), diag::err_constant_integer_last_arg_type) + << FDecl->getDeclName() << Arg->getSourceRange(); + } + if (checkPointerAuthValue(S, Call->getArgs()[0], PAO_Auth) || + checkPointerAuthKey(S, Call->getArgs()[1]) || + checkPointerAuthValue(S, Call->getArgs()[2], PAO_Discriminator) || + checkPointerAuthKey(S, Call->getArgs()[3]) || + checkPointerAuthValue(S, Call->getArgs()[4], PAO_Discriminator) || + !AddendIsConstInt) + return ExprError(); + + Call->setType(Call->getArgs()[0]->getType()); + return Call; +} + static ExprResult PointerAuthStringDiscriminator(Sema &S, CallExpr *Call) { if (checkPointerAuthEnabled(S, Call)) return ExprError(); @@ -2866,6 +2892,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_load_relative_and_sign: + return PointerAuthAuthLoadRelativeAndSign(*this, TheCall); case Builtin::BI__builtin_ptrauth_string_discriminator: return PointerAuthStringDiscriminator(*this, TheCall); diff --git a/clang/test/CodeGen/ptrauth-intrinsics.c b/clang/test/CodeGen/ptrauth-intrinsics.c index 50bf1898e4b37..bd348f9b3551a 100644 --- a/clang/test/CodeGen/ptrauth-intrinsics.c +++ b/clang/test/CodeGen/ptrauth-intrinsics.c @@ -55,6 +55,18 @@ void test_auth_and_resign() { fnptr = __builtin_ptrauth_auth_and_resign(fnptr, 0, ptr_discriminator, 3, 15); } +// CHECK-LABEL: define {{.*}}void @test_auth_load_relative_and_sign() +void test_auth_load_relative_and_sign() { + // CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr, + // CHECK-NEXT: [[DISC0:%.*]] = load ptr, ptr @ptr_discriminator, + // CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[PTR]] to i64 + // CHECK-NEXT: [[DISC:%.*]] = ptrtoint ptr [[DISC0]] to i64 + // CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign.load.relative(i64 [[T0]], i32 0, i64 [[DISC]], i32 3, i64 15, i64 16) + // CHECK-NEXT: [[RESULT:%.*]] = inttoptr i64 [[T1]] to ptr + // CHECK-NEXT: store ptr [[RESULT]], ptr @fnptr, + fnptr = __builtin_ptrauth_auth_load_relative_and_sign(fnptr, 0, ptr_discriminator, 3, 15, 16L); +} + // CHECK-LABEL: define {{.*}}void @test_blend_discriminator() void test_blend_discriminator() { // CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr, diff --git a/clang/test/Sema/ptrauth.c b/clang/test/Sema/ptrauth.c index b4e5214a7cb50..2dadb6334f45d 100644 --- a/clang/test/Sema/ptrauth.c +++ b/clang/test/Sema/ptrauth.c @@ -121,6 +121,29 @@ void test_auth_and_resign(int *dp, int (*fp)(int)) { float *mismatch = __builtin_ptrauth_auth_and_resign(dp, VALID_DATA_KEY, 0, VALID_DATA_KEY, dp); // expected-warning {{incompatible pointer types initializing 'float *' with an expression of type 'int *'}} } +void test_auth_load_relative_and_sign(int *dp, int (*fp)(int)) { + __builtin_ptrauth_auth_load_relative_and_sign(dp, VALID_DATA_KEY, 0, VALID_DATA_KEY, 0); // expected-error {{too few arguments}} + __builtin_ptrauth_auth_load_relative_and_sign(dp, VALID_DATA_KEY, dp, VALID_DATA_KEY, dp, 0, 0); // expected-error {{too many arguments}} + int n = *dp; + __builtin_ptrauth_auth_load_relative_and_sign(dp, VALID_DATA_KEY, dp, VALID_DATA_KEY, dp,n); // expected-error {{last argument to '__builtin_ptrauth_auth_load_relative_and_sign' must be a constant integer}} + __builtin_ptrauth_auth_load_relative_and_sign(mismatched_type, VALID_DATA_KEY, 0, VALID_DATA_KEY, dp, 0); // expected-error {{signed value must have pointer type; type here is 'struct A'}} + __builtin_ptrauth_auth_load_relative_and_sign(dp, mismatched_type, 0, VALID_DATA_KEY, dp, 0); // expected-error {{passing 'struct A' to parameter of incompatible type 'int'}} + __builtin_ptrauth_auth_load_relative_and_sign(dp, VALID_DATA_KEY, mismatched_type, VALID_DATA_KEY, dp, 0); // expected-error {{extra discriminator must have pointer or integer type; type here is 'struct A'}} + __builtin_ptrauth_auth_load_relative_and_sign(dp, VALID_DATA_KEY, 0, mismatched_type, dp, 0); // expected-error {{passing 'struct A' to parameter of incompatible type 'int'}} + __builtin_ptrauth_auth_load_relative_and_sign(dp, VALID_DATA_KEY, 0, VALID_DATA_KEY, mismatched_type, 0); // expected-error {{extra discriminator must have pointer or integer type; type here is 'struct A'}} + + (void) __builtin_ptrauth_auth_and_resign(NULL, VALID_DATA_KEY, 0, VALID_DATA_KEY, dp); // expected-warning {{authenticating a null pointer will almost certainly trap}} + + int *dr = __builtin_ptrauth_auth_load_relative_and_sign(dp, VALID_DATA_KEY, 0, VALID_DATA_KEY, dp, 10); + dr = __builtin_ptrauth_auth_load_relative_and_sign(dp, INVALID_KEY, 0, VALID_DATA_KEY, dp, 10); // expected-error {{does not identify a valid pointer authentication key for the current target}} + dr = __builtin_ptrauth_auth_load_relative_and_sign(dp, VALID_DATA_KEY, 0, INVALID_KEY, dp, 10); // expected-error {{does not identify a valid pointer authentication key for the current target}} + + int (*fr)(int) = __builtin_ptrauth_auth_load_relative_and_sign(fp, VALID_CODE_KEY, 0, VALID_CODE_KEY, dp, 10); + fr = __builtin_ptrauth_auth_load_relative_and_sign(fp, INVALID_KEY, 0, VALID_CODE_KEY, dp, 10); // expected-error {{does not identify a valid pointer authentication key for the current target}} + fr = __builtin_ptrauth_auth_load_relative_and_sign(fp, VALID_CODE_KEY, 0, INVALID_KEY, dp, 10); // expected-error {{does not identify a valid pointer authentication key for the current target}} + + float *mismatch = __builtin_ptrauth_auth_load_relative_and_sign(dp, VALID_DATA_KEY, 0, VALID_DATA_KEY, dp,0); // expected-warning {{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}} diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td index bd6f94ac1286c..85d2be4326ce5 100644 --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -2818,6 +2818,19 @@ def int_ptrauth_resign : Intrinsic<[llvm_i64_ty], [IntrNoMem, ImmArg>, ImmArg>]>; +// Authenticate a signed pointer, load 32bit value at offset from pointer, add +// both, and sign it. The second (key) and third (discriminator) arguments +// specify the signing schema used for authenticating. The fourth and fifth +// arguments specify the schema used for signing. The sixth argument is addend +// added to pointer to load the relative offset. The signature must be valid. +// This is a combined form of int_ptrauth_resign for relative pointers +def int_ptrauth_resign_load_relative + : Intrinsic<[llvm_i64_ty], + [llvm_i64_ty, llvm_i32_ty, llvm_i64_ty, llvm_i32_ty, + llvm_i64_ty, llvm_i64_ty], + [IntrReadMem, ImmArg>, ImmArg>, + ImmArg>]>; + // Strip the embedded signature out of a signed pointer. // The second argument specifies the key. // This behaves like @llvm.ptrauth.auth, but doesn't require the signature to diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index c52487ab8a79a..684d8caad724e 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -168,13 +168,14 @@ class AArch64AsmPrinter : public AsmPrinter { // Check authenticated LR before tail calling. void emitPtrauthTailCallHardening(const MachineInstr *TC); - // Emit the sequence for AUT or AUTPAC. + // Emit the sequence for AUT or AUTPAC. Addend if AUTRELLOADPAC void emitPtrauthAuthResign(Register AUTVal, AArch64PACKey::ID AUTKey, uint64_t AUTDisc, const MachineOperand *AUTAddrDisc, Register Scratch, std::optional PACKey, - uint64_t PACDisc, Register PACAddrDisc); + uint64_t PACDisc, Register PACAddrDisc, + std::optional Addend); // Emit the sequence for PAC. void emitPtrauthSign(const MachineInstr *MI); @@ -2078,9 +2079,9 @@ void AArch64AsmPrinter::emitPtrauthAuthResign( Register AUTVal, AArch64PACKey::ID AUTKey, uint64_t AUTDisc, const MachineOperand *AUTAddrDisc, Register Scratch, std::optional PACKey, uint64_t PACDisc, - Register PACAddrDisc) { + Register PACAddrDisc, std::optional OptAddend) { const bool IsAUTPAC = PACKey.has_value(); - + const bool HasLoad = OptAddend.has_value(); // We expand AUT/AUTPAC into a sequence of the form // // ; authenticate x16 @@ -2151,12 +2152,76 @@ void AArch64AsmPrinter::emitPtrauthAuthResign( } // We already emitted unchecked and checked-but-non-trapping AUTs. - // That left us with trapping AUTs, and AUTPACs. + // That left us with trapping AUTs, and AUTPA/AUTRELLOADPACs. // Trapping AUTs don't need PAC: we're done. if (!IsAUTPAC) return; - // Compute pac discriminator + if (HasLoad) { + int64_t Addend = *OptAddend; + // incoming rawpointer in X16, X17 is not live at this point. + // LDSRWpre x17, x16, simm9 ; note: x16+simm9 used later. + if (isInt<9>(Addend)) { + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDRSWpre) + .addReg(AArch64::X16) + .addReg(AArch64::X17) + .addReg(AArch64::X16) + .addImm(/*simm9:*/ Addend)); + } else { + // x16 = x16 + Addend computation has 2 variants + if (isUInt<24>(Addend)) { + // variant 1: add x16, x16, Addend >> shift12 ls shift12 + // This can take upto 2 instructions. + for (int BitPos = 0; BitPos != 24 && (Addend >> BitPos); BitPos += 12) { + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ADDXri) + .addReg(AArch64::X16) + .addReg(AArch64::X16) + .addImm((Addend >> BitPos) & 0xfff) + .addImm(AArch64_AM::getShifterImm( + AArch64_AM::LSL, BitPos))); + } + } else { + // variant 2: accumulate constant in X17 16 bits at a time, and add to + // X16 This can take 2-5 instructions. + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVZXi) + .addReg(AArch64::X17) + .addImm(Addend & 0xffff) + .addImm(AArch64_AM::getShifterImm( + AArch64_AM::LSL, 0))); + + for (int Offset = 16; Offset < 64; Offset += 16) { + uint16_t Fragment = static_cast(Addend >> Offset); + if (!Fragment) + continue; + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVKXi) + .addReg(AArch64::X17) + .addReg(AArch64::X17) + .addImm(Fragment) + .addImm(/*shift:*/ Offset)); + } + // addx x16, x16, x17 + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ADDXrs) + .addReg(AArch64::X16) + .addReg(AArch64::X16) + .addReg(AArch64::X17) + .addImm(0)); + } + // ldrsw x17,x16(0) + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDRSWui) + .addReg(AArch64::X17) + .addReg(AArch64::X16) + .addImm(0)); + } + // addx x16, x16, x17 + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ADDXrs) + .addReg(AArch64::X16) + .addReg(AArch64::X16) + .addReg(AArch64::X17) + .addImm(0)); + + } /* HasLoad == true */ + + // Compute pac discriminator into x17 assert(isUInt<16>(PACDisc)); Register PACDiscReg = emitPtrauthDiscriminator(PACDisc, PACAddrDisc, Scratch); @@ -2906,22 +2971,31 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) { emitPtrauthAuthResign(AArch64::X16, (AArch64PACKey::ID)MI->getOperand(0).getImm(), MI->getOperand(1).getImm(), &MI->getOperand(2), - AArch64::X17, std::nullopt, 0, 0); + AArch64::X17, std::nullopt, 0, 0, std::nullopt); return; case AArch64::AUTxMxN: emitPtrauthAuthResign(MI->getOperand(0).getReg(), (AArch64PACKey::ID)MI->getOperand(3).getImm(), MI->getOperand(4).getImm(), &MI->getOperand(5), - MI->getOperand(1).getReg(), std::nullopt, 0, 0); + MI->getOperand(1).getReg(), std::nullopt, 0, 0, + std::nullopt); return; + case AArch64::AUTRELLOADPAC: + emitPtrauthAuthResign( + AArch64::X16, (AArch64PACKey::ID)MI->getOperand(0).getImm(), + MI->getOperand(1).getImm(), &MI->getOperand(2), AArch64::X17, + (AArch64PACKey::ID)MI->getOperand(3).getImm(), + MI->getOperand(4).getImm(), MI->getOperand(5).getReg(), + MI->getOperand(6).getImm()); + return; case AArch64::AUTPAC: emitPtrauthAuthResign( AArch64::X16, (AArch64PACKey::ID)MI->getOperand(0).getImm(), MI->getOperand(1).getImm(), &MI->getOperand(2), AArch64::X17, (AArch64PACKey::ID)MI->getOperand(3).getImm(), - MI->getOperand(4).getImm(), MI->getOperand(5).getReg()); + MI->getOperand(4).getImm(), MI->getOperand(5).getReg(), std::nullopt); return; case AArch64::PAC: diff --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp index ad42f4b56caf2..4aedab377e917 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp @@ -1552,12 +1552,15 @@ void AArch64DAGToDAGISel::SelectPtrauthAuth(SDNode *N) { void AArch64DAGToDAGISel::SelectPtrauthResign(SDNode *N) { SDLoc DL(N); - // IntrinsicID is operand #0 - SDValue Val = N->getOperand(1); - SDValue AUTKey = N->getOperand(2); - SDValue AUTDisc = N->getOperand(3); - SDValue PACKey = N->getOperand(4); - SDValue PACDisc = N->getOperand(5); + // IntrinsicID is operand #0, if W_CHAIN it is #1 + int OffsetBase = N->getOpcode() == ISD::INTRINSIC_W_CHAIN ? 1 : 0; + SDValue Val = N->getOperand(OffsetBase + 1); + SDValue AUTKey = N->getOperand(OffsetBase + 2); + SDValue AUTDisc = N->getOperand(OffsetBase + 3); + SDValue PACKey = N->getOperand(OffsetBase + 4); + SDValue PACDisc = N->getOperand(OffsetBase + 5); + uint32_t IntNum = N->getConstantOperandVal(OffsetBase + 0); + bool HasLoad = IntNum == Intrinsic::ptrauth_resign_load_relative; unsigned AUTKeyC = cast(AUTKey)->getZExtValue(); unsigned PACKeyC = cast(PACKey)->getZExtValue(); @@ -1576,11 +1579,22 @@ void AArch64DAGToDAGISel::SelectPtrauthResign(SDNode *N) { SDValue X16Copy = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL, AArch64::X16, Val, SDValue()); - SDValue Ops[] = {AUTKey, AUTConstDisc, AUTAddrDisc, PACKey, - PACConstDisc, PACAddrDisc, X16Copy.getValue(1)}; + if (HasLoad) { + SDValue Addend = N->getOperand(OffsetBase + 6); + SDValue Ops[] = {AUTKey, AUTConstDisc, AUTAddrDisc, + PACKey, PACConstDisc, PACAddrDisc, + Addend, X16Copy.getValue(1)}; - SDNode *AUTPAC = CurDAG->getMachineNode(AArch64::AUTPAC, DL, MVT::i64, Ops); - ReplaceNode(N, AUTPAC); + SDNode *AUTRELLOADPAC = CurDAG->getMachineNode(AArch64::AUTRELLOADPAC, DL, + MVT::i64, MVT::Other, Ops); + ReplaceNode(N, AUTRELLOADPAC); + } else { + SDValue Ops[] = {AUTKey, AUTConstDisc, AUTAddrDisc, PACKey, + PACConstDisc, PACAddrDisc, X16Copy.getValue(1)}; + + SDNode *AUTPAC = CurDAG->getMachineNode(AArch64::AUTPAC, DL, MVT::i64, Ops); + ReplaceNode(N, AUTPAC); + } } bool AArch64DAGToDAGISel::tryIndexedLoad(SDNode *N) { @@ -5777,6 +5791,9 @@ void AArch64DAGToDAGISel::Select(SDNode *Node) { {AArch64::BF2CVT_2ZZ_BtoH, AArch64::F2CVT_2ZZ_BtoH})) SelectCVTIntrinsicFP8(Node, 2, Opc); return; + case Intrinsic::ptrauth_resign_load_relative: + SelectPtrauthResign(Node); + return; } } break; case ISD::INTRINSIC_WO_CHAIN: { diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index 251fd44b6ea31..f682a5f2fad64 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -2190,6 +2190,26 @@ let Predicates = [HasPAuth] in { let Uses = [X16]; } + // 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 + // guarantees are safe to use for sensitive operations. + def AUTRELLOADPAC + : Pseudo<(outs), + (ins i32imm:$AUTKey, i64imm:$AUTDisc, GPR64:$AUTAddrDisc, + i32imm:$PACKey, i64imm:$PACDisc, GPR64noip:$PACAddrDisc, + i64imm:$Addend), + []>, + Sched<[WriteI, ReadI]> { + let isCodeGenOnly = 1; + let hasSideEffects = 1; + let mayStore = 0; + let mayLoad = 1; + let Size = 84; + let Defs = [X16, X17, NZCV]; + let Uses = [X16]; + } + // Materialize a signed global address, with adrp+add and PAC. def MOVaddrPAC : Pseudo<(outs), (ins i64imm:$Addr, i32imm:$Key, diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp index 1381a9b70df87..2b554002dd21d 100644 --- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp +++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp @@ -6665,6 +6665,42 @@ bool AArch64InstructionSelector::selectIntrinsicWithSideEffects( constrainSelectedInstRegOperands(*Memset, TII, TRI, RBI); break; } + case Intrinsic::ptrauth_resign_load_relative: { + 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(); + uint64_t PACKey = I.getOperand(5).getImm(); + Register PACDisc = I.getOperand(6).getReg(); + int64_t Addend = I.getOperand(7).getImm(); + + 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); + + MIB.buildCopy({AArch64::X16}, {ValReg}); + + MIB.buildInstr(AArch64::AUTRELLOADPAC) + .addImm(AUTKey) + .addImm(AUTConstDiscC) + .addUse(AUTAddrDisc) + .addImm(PACKey) + .addImm(PACConstDiscC) + .addUse(PACAddrDisc) + .addImm(Addend) + .constrainAllUses(TII, TRI, RBI); + MIB.buildCopy({DstReg}, Register(AArch64::X16)); + + RBI.constrainGenericRegister(DstReg, AArch64::GPR64RegClass, MRI); + I.eraseFromParent(); + return true; + } } I.eraseFromParent(); diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp index babd7f6b3a058..ed8d476fe94b6 100644 --- a/llvm/lib/Transforms/Utils/Local.cpp +++ b/llvm/lib/Transforms/Utils/Local.cpp @@ -457,6 +457,7 @@ bool llvm::wouldInstructionBeTriviallyDead(const Instruction *I, case Intrinsic::wasm_trunc_unsigned: case Intrinsic::ptrauth_auth: case Intrinsic::ptrauth_resign: + case Intrinsic::ptrauth_resign_load_relative: return true; default: return false; diff --git a/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign-relative-load.ll b/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign-relative-load.ll new file mode 100644 index 0000000000000..affa0c2369ba2 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign-relative-load.ll @@ -0,0 +1,516 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel=0 -verify-machineinstrs \ +; RUN: -aarch64-ptrauth-auth-checks=none | FileCheck %s -DL="L" --check-prefix=UNCHECKED +; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel -global-isel-abort=1 -verify-machineinstrs \ +; RUN: -aarch64-ptrauth-auth-checks=none | FileCheck %s -DL="L" --check-prefix=UNCHECKED + +; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel=0 -verify-machineinstrs \ +; RUN: | FileCheck %s -DL="L" --check-prefix=CHECKED +; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel -global-isel-abort=1 -verify-machineinstrs \ +; RUN: | FileCheck %s -DL="L" --check-prefix=CHECKED + +; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel=0 -verify-machineinstrs \ +; RUN: -aarch64-ptrauth-auth-checks=trap | FileCheck %s -DL="L" --check-prefix=TRAP +; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel -global-isel-abort=1 -verify-machineinstrs \ +; RUN: -aarch64-ptrauth-auth-checks=trap | FileCheck %s -DL="L" --check-prefix=TRAP + +;RUN: llc < %s -mtriple aarch64-linux-gnu -mattr=+pauth -global-isel=0 -verify-machineinstrs \ +;RUN: -aarch64-ptrauth-auth-checks=none | FileCheck %s -DL=".L" --check-prefix=UNCHECKED +;RUN: llc < %s -mtriple aarch64-linux-gnu -mattr=+pauth -global-isel -global-isel-abort=1 -verify-machineinstrs \ +;RUN: -aarch64-ptrauth-auth-checks=none | FileCheck %s -DL=".L" --check-prefix=UNCHECKED + +;RUN: llc < %s -mtriple aarch64-linux-gnu -mattr=+pauth -global-isel=0 -verify-machineinstrs \ +;RUN: | FileCheck %s -DL=".L" --check-prefix=CHECKED +;RUN: llc < %s -mtriple aarch64-linux-gnu -mattr=+pauth -global-isel -global-isel-abort=1 -verify-machineinstrs \ +;RUN: | FileCheck %s -DL=".L" --check-prefix=CHECKED + +;RUN: llc < %s -mtriple aarch64-linux-gnu -mattr=+pauth -global-isel=0 -verify-machineinstrs \ +;RUN: -aarch64-ptrauth-auth-checks=trap | FileCheck %s -DL=".L" --check-prefix=TRAP +;RUN: llc < %s -mtriple aarch64-linux-gnu -mattr=+pauth -global-isel -global-isel-abort=1 -verify-machineinstrs \ +;RUN: -aarch64-ptrauth-auth-checks=trap | FileCheck %s -DL=".L" --check-prefix=TRAP + +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" + +define i64 @test_resign_load_relative_ia_ia(i64 %arg, i64 %arg1, i64 %arg2) { +; UNCHECKED-LABEL: test_resign_load_relative_ia_ia: +; UNCHECKED: %bb.0: +; UNCHECKED-NEXT: mov x16, x0 +; UNCHECKED-NEXT: autia x16, x1 +; UNCHECKED-NEXT: ldrsw x17, [x16, #-256]! +; UNCHECKED-NEXT: add x16, x16, x17 +; UNCHECKED-NEXT: pacia x16, x2 +; UNCHECKED-NEXT: mov x0, x16 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_resign_load_relative_ia_ia: +; CHECKED: %bb.0: +; CHECKED-NEXT: mov x16, x0 +; CHECKED-NEXT: autia x16, x1 +; CHECKED-NEXT: mov x17, x16 +; CHECKED-NEXT: xpaci x17 +; CHECKED-NEXT: cmp x16, x17 +; CHECKED-NEXT: b.eq [[L]]auth_success_0 +; CHECKED-NEXT: mov x16, x17 +; CHECKED-NEXT: b [[L]]resign_end_0 +; CHECKED-NEXT: Lauth_success_0: +; CHECKED-NEXT: ldrsw x17, [x16, #-256]! +; CHECKED-NEXT: add x16, x16, x17 +; CHECKED-NEXT: pacia x16, x2 +; CHECKED-NEXT: Lresign_end_0: +; CHECKED-NEXT: mov x0, x16 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_resign_load_relative_ia_ia: +; TRAP: %bb.0: +; TRAP-NEXT: mov x16, x0 +; TRAP-NEXT: autia x16, x1 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpaci x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq [[L]]auth_success_0 +; TRAP-NEXT: brk #0xc470 +; TRAP-NEXT: Lauth_success_0: +; TRAP-NEXT: ldrsw x17, [x16, #-256]! +; TRAP-NEXT: add x16, x16, x17 +; TRAP-NEXT: pacia x16, x2 +; TRAP-NEXT: mov x0, x16 +; TRAP-NEXT: ret + %tmp = call i64 @llvm.ptrauth.resign.load.relative(i64 %arg, i32 0, i64 %arg1, i32 0, i64 %arg2, i64 -256) + ret i64 %tmp +} + +; note: offset 256 is larger tha 255 (largest simm9), is uint<24> +define i64 @test_resign_load_relative_ib_ia(i64 %arg, i64 %arg1, i64 %arg2) { +; UNCHECKED-LABEL: test_resign_load_relative_ib_ia: +; UNCHECKED: %bb.0: +; UNCHECKED-NEXT: mov x16, x0 +; UNCHECKED-NEXT: autib x16, x1 +; UNCHECKED-NEXT: add x16, x16, #256 +; UNCHECKED-NEXT: ldrsw x17, [x16] +; UNCHECKED-NEXT: add x16, x16, x17 +; UNCHECKED-NEXT: pacia x16, x2 +; UNCHECKED-NEXT: mov x0, x16 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_resign_load_relative_ib_ia: +; CHECKED: %bb.0: +; CHECKED-NEXT: mov x16, x0 +; CHECKED-NEXT: autib x16, x1 +; CHECKED-NEXT: mov x17, x16 +; CHECKED-NEXT: xpaci x17 +; CHECKED-NEXT: cmp x16, x17 +; CHECKED-NEXT: b.eq [[L]]auth_success_1 +; CHECKED-NEXT: mov x16, x17 +; CHECKED-NEXT: b [[L]]resign_end_1 +; CHECKED-NEXT: Lauth_success_1: +; CHECKED-NEXT: add x16, x16, #256 +; CHECKED-NEXT: ldrsw x17, [x16] +; CHECKED-NEXT: add x16, x16, x17 +; CHECKED-NEXT: pacia x16, x2 +; CHECKED-NEXT: Lresign_end_1: +; CHECKED-NEXT: mov x0, x16 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_resign_load_relative_ib_ia: +; TRAP: %bb.0: +; TRAP-NEXT: mov x16, x0 +; TRAP-NEXT: autib x16, x1 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpaci x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq [[L]]auth_success_1 +; TRAP-NEXT: brk #0xc471 +; TRAP-NEXT: Lauth_success_1: +; TRAP-NEXT: add x16, x16, #256 +; TRAP-NEXT: ldrsw x17, [x16] +; TRAP-NEXT: add x16, x16, x17 +; TRAP-NEXT: pacia x16, x2 +; TRAP-NEXT: mov x0, x16 +; TRAP-NEXT: ret + %tmp = call i64 @llvm.ptrauth.resign.load.relative(i64 %arg, i32 1, i64 %arg1, i32 0, i64 %arg2, i64 256) + ret i64 %tmp +} + +define i64 @test_resign_load_relative_da_ia(i64 %arg, i64 %arg1, i64 %arg2) { +; UNCHECKED-LABEL: test_resign_load_relative_da_ia: +; UNCHECKED: %bb.0: +; UNCHECKED-NEXT: mov x16, x0 +; UNCHECKED-NEXT: autda x16, x1 +; UNCHECKED-NEXT: add x16, x16, #256 +; UNCHECKED-NEXT: ldrsw x17, [x16] +; UNCHECKED-NEXT: add x16, x16, x17 +; UNCHECKED-NEXT: pacia x16, x2 +; UNCHECKED-NEXT: mov x0, x16 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_resign_load_relative_da_ia: +; CHECKED: %bb.0: +; CHECKED-NEXT: mov x16, x0 +; CHECKED-NEXT: autda x16, x1 +; CHECKED-NEXT: mov x17, x16 +; CHECKED-NEXT: xpacd x17 +; CHECKED-NEXT: cmp x16, x17 +; CHECKED-NEXT: b.eq [[L]]auth_success_2 +; CHECKED-NEXT: mov x16, x17 +; CHECKED-NEXT: b [[L]]resign_end_2 +; CHECKED-NEXT: Lauth_success_2: +; CHECKED-NEXT: add x16, x16, #256 +; CHECKED-NEXT: ldrsw x17, [x16] +; CHECKED-NEXT: add x16, x16, x17 +; CHECKED-NEXT: pacia x16, x2 +; CHECKED-NEXT: Lresign_end_2: +; CHECKED-NEXT: mov x0, x16 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_resign_load_relative_da_ia: +; TRAP: %bb.0: +; TRAP-NEXT: mov x16, x0 +; TRAP-NEXT: autda x16, x1 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpacd x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq [[L]]auth_success_2 +; TRAP-NEXT: brk #0xc472 +; TRAP-NEXT: Lauth_success_2: +; TRAP-NEXT: add x16, x16, #256 +; TRAP-NEXT: ldrsw x17, [x16] +; TRAP-NEXT: add x16, x16, x17 +; TRAP-NEXT: pacia x16, x2 +; TRAP-NEXT: mov x0, x16 +; TRAP-NEXT: ret + %tmp = call i64 @llvm.ptrauth.resign.load.relative(i64 %arg, i32 2, i64 %arg1, i32 0, i64 %arg2, i64 256) + ret i64 %tmp +} + +define i64 @test_resign_load_relative_db_da(i64 %arg, i64 %arg1, i64 %arg2) { +; UNCHECKED-LABEL: test_resign_load_relative_db_da: +; UNCHECKED: %bb.0: +; UNCHECKED-NEXT: mov x16, x0 +; UNCHECKED-NEXT: autdb x16, x1 +; UNCHECKED-NEXT: add x16, x16, #256 +; UNCHECKED-NEXT: ldrsw x17, [x16] +; UNCHECKED-NEXT: add x16, x16, x17 +; UNCHECKED-NEXT: pacda x16, x2 +; UNCHECKED-NEXT: mov x0, x16 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_resign_load_relative_db_da: +; CHECKED: %bb.0: +; CHECKED-NEXT: mov x16, x0 +; CHECKED-NEXT: autdb x16, x1 +; CHECKED-NEXT: mov x17, x16 +; CHECKED-NEXT: xpacd x17 +; CHECKED-NEXT: cmp x16, x17 +; CHECKED-NEXT: b.eq [[L]]auth_success_3 +; CHECKED-NEXT: mov x16, x17 +; CHECKED-NEXT: b [[L]]resign_end_3 +; CHECKED-NEXT: Lauth_success_3: +; CHECKED-NEXT: add x16, x16, #256 +; CHECKED-NEXT: ldrsw x17, [x16] +; CHECKED-NEXT: add x16, x16, x17 +; CHECKED-NEXT: pacda x16, x2 +; CHECKED-NEXT: Lresign_end_3: +; CHECKED-NEXT: mov x0, x16 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_resign_load_relative_db_da: +; TRAP: %bb.0: +; TRAP-NEXT: mov x16, x0 +; TRAP-NEXT: autdb x16, x1 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpacd x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq [[L]]auth_success_3 +; TRAP-NEXT: brk #0xc473 +; TRAP-NEXT: Lauth_success_3: +; TRAP-NEXT: add x16, x16, #256 +; TRAP-NEXT: ldrsw x17, [x16] +; TRAP-NEXT: add x16, x16, x17 +; TRAP-NEXT: pacda x16, x2 +; TRAP-NEXT: mov x0, x16 +; TRAP-NEXT: ret + %tmp = call i64 @llvm.ptrauth.resign.load.relative(i64 %arg, i32 3, i64 %arg1, i32 2, i64 %arg2, i64 256) + ret i64 %tmp +} + +define i64 @test_resign_load_relative_iza_db(i64 %arg, i64 %arg1, i64 %arg2) { +; UNCHECKED-LABEL: test_resign_load_relative_iza_db: +; UNCHECKED: %bb.0: +; UNCHECKED-NEXT: mov x16, x0 +; UNCHECKED-NEXT: autiza x16 +; UNCHECKED-NEXT: add x16, x16, #256 +; UNCHECKED-NEXT: ldrsw x17, [x16] +; UNCHECKED-NEXT: add x16, x16, x17 +; UNCHECKED-NEXT: pacdb x16, x2 +; UNCHECKED-NEXT: mov x0, x16 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_resign_load_relative_iza_db: +; CHECKED: %bb.0: +; CHECKED-NEXT: mov x16, x0 +; CHECKED-NEXT: autiza x16 +; CHECKED-NEXT: mov x17, x16 +; CHECKED-NEXT: xpaci x17 +; CHECKED-NEXT: cmp x16, x17 +; CHECKED-NEXT: b.eq [[L]]auth_success_4 +; CHECKED-NEXT: mov x16, x17 +; CHECKED-NEXT: b [[L]]resign_end_4 +; CHECKED-NEXT: Lauth_success_4: +; CHECKED-NEXT: add x16, x16, #256 +; CHECKED-NEXT: ldrsw x17, [x16] +; CHECKED-NEXT: add x16, x16, x17 +; CHECKED-NEXT: pacdb x16, x2 +; CHECKED-NEXT: Lresign_end_4: +; CHECKED-NEXT: mov x0, x16 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_resign_load_relative_iza_db: +; TRAP: %bb.0: +; TRAP-NEXT: mov x16, x0 +; TRAP-NEXT: autiza x16 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpaci x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq [[L]]auth_success_4 +; TRAP-NEXT: brk #0xc470 +; TRAP-NEXT: Lauth_success_4: +; TRAP-NEXT: add x16, x16, #256 +; TRAP-NEXT: ldrsw x17, [x16] +; TRAP-NEXT: add x16, x16, x17 +; TRAP-NEXT: pacdb x16, x2 +; TRAP-NEXT: mov x0, x16 +; TRAP-NEXT: ret + %tmp = call i64 @llvm.ptrauth.resign.load.relative(i64 %arg, i32 0, i64 0, i32 3, i64 %arg2, i64 256) + ret i64 %tmp +} + +define i64 @test_resign_load_relative_da_dzb(i64 %arg, i64 %arg1, i64 %arg2) { +; UNCHECKED-LABEL: test_resign_load_relative_da_dzb: +; UNCHECKED: %bb.0: +; UNCHECKED-NEXT: mov x16, x0 +; UNCHECKED-NEXT: autda x16, x1 +; UNCHECKED-NEXT: add x16, x16, #256 +; UNCHECKED-NEXT: ldrsw x17, [x16] +; UNCHECKED-NEXT: add x16, x16, x17 +; UNCHECKED-NEXT: pacdzb x16 +; UNCHECKED-NEXT: mov x0, x16 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_resign_load_relative_da_dzb: +; CHECKED: %bb.0: +; CHECKED-NEXT: mov x16, x0 +; CHECKED-NEXT: autda x16, x1 +; CHECKED-NEXT: mov x17, x16 +; CHECKED-NEXT: xpacd x17 +; CHECKED-NEXT: cmp x16, x17 +; CHECKED-NEXT: b.eq [[L]]auth_success_5 +; CHECKED-NEXT: mov x16, x17 +; CHECKED-NEXT: b [[L]]resign_end_5 +; CHECKED-NEXT: Lauth_success_5: +; CHECKED-NEXT: add x16, x16, #256 +; CHECKED-NEXT: ldrsw x17, [x16] +; CHECKED-NEXT: add x16, x16, x17 +; CHECKED-NEXT: pacdzb x16 +; CHECKED-NEXT: Lresign_end_5: +; CHECKED-NEXT: mov x0, x16 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_resign_load_relative_da_dzb: +; TRAP: %bb.0: +; TRAP-NEXT: mov x16, x0 +; TRAP-NEXT: autda x16, x1 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpacd x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq [[L]]auth_success_5 +; TRAP-NEXT: brk #0xc472 +; TRAP-NEXT: Lauth_success_5: +; TRAP-NEXT: add x16, x16, #256 +; TRAP-NEXT: ldrsw x17, [x16] +; TRAP-NEXT: add x16, x16, x17 +; TRAP-NEXT: pacdzb x16 +; TRAP-NEXT: mov x0, x16 +; TRAP-NEXT: ret + %tmp = call i64 @llvm.ptrauth.resign.load.relative(i64 %arg, i32 2, i64 %arg1, i32 3, i64 0,i64 256) + ret i64 %tmp +} + +define i64 @test_resign_load_relative_da_constdisc(i64 %arg, i64 %arg1) { +; UNCHECKED-LABEL: test_resign_load_relative_da_constdisc: +; UNCHECKED: %bb.0: +; UNCHECKED-NEXT: mov x16, x0 +; UNCHECKED-NEXT: autda x16, x1 +; UNCHECKED-NEXT: add x16, x16, #256 +; UNCHECKED-NEXT: ldrsw x17, [x16] +; UNCHECKED-NEXT: add x16, x16, x17 +; UNCHECKED-NEXT: mov x17, #256 +; UNCHECKED-NEXT: pacda x16, x17 +; UNCHECKED-NEXT: mov x0, x16 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_resign_load_relative_da_constdisc: +; CHECKED: %bb.0: +; CHECKED-NEXT: mov x16, x0 +; CHECKED-NEXT: autda x16, x1 +; CHECKED-NEXT: mov x17, x16 +; CHECKED-NEXT: xpacd x17 +; CHECKED-NEXT: cmp x16, x17 +; CHECKED-NEXT: b.eq [[L]]auth_success_6 +; CHECKED-NEXT: mov x16, x17 +; CHECKED-NEXT: b [[L]]resign_end_6 +; CHECKED-NEXT: Lauth_success_6: +; CHECKED-NEXT: add x16, x16, #256 +; CHECKED-NEXT: ldrsw x17, [x16] +; CHECKED-NEXT: add x16, x16, x17 +; CHECKED-NEXT: mov x17, #256 +; CHECKED-NEXT: pacda x16, x17 +; CHECKED-NEXT: Lresign_end_6: +; CHECKED-NEXT: mov x0, x16 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_resign_load_relative_da_constdisc: +; TRAP: %bb.0: +; TRAP-NEXT: mov x16, x0 +; TRAP-NEXT: autda x16, x1 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpacd x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq [[L]]auth_success_6 +; TRAP-NEXT: brk #0xc472 +; TRAP-NEXT: Lauth_success_6: +; TRAP-NEXT: add x16, x16, #256 +; TRAP-NEXT: ldrsw x17, [x16] +; TRAP-NEXT: add x16, x16, x17 +; TRAP-NEXT: mov x17, #256 +; TRAP-NEXT: pacda x16, x17 +; TRAP-NEXT: mov x0, x16 +; TRAP-NEXT: ret + %tmp = call i64 @llvm.ptrauth.resign.load.relative(i64 %arg, i32 2, i64 %arg1, i32 2, i64 256,i64 256) + ret i64 %tmp +} + +; note: addend is larger than 24bit integer +define i64 @test_resign_load_relative_loadNegOffset_constdisc(i64 %arg,i64 %arg1) { +; UNCHECKED-LABEL: test_resign_load_relative_loadNegOffset_constdisc: +; UNCHECKED: %bb.0: +; UNCHECKED-NEXT: mov x16, x0 +; UNCHECKED-NEXT: autda x16, x1 +; UNCHECKED-NEXT: mov x17, #62980 +; UNCHECKED-NEXT: movk x17, #65535, lsl #16 +; UNCHECKED-NEXT: movk x17, #65535, lsl #32 +; UNCHECKED-NEXT: movk x17, #65535, lsl #48 +; UNCHECKED-NEXT: add x16, x16, x17 +; UNCHECKED-NEXT: ldrsw x17, [x16] +; UNCHECKED-NEXT: add x16, x16, x17 +; UNCHECKED-NEXT: mov x17, #256 +; UNCHECKED-NEXT: pacda x16, x17 +; UNCHECKED-NEXT: mov x0, x16 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_resign_load_relative_loadNegOffset_constdisc: +; CHECKED: %bb.0: +; CHECKED-NEXT: mov x16, x0 +; CHECKED-NEXT: autda x16, x1 +; CHECKED-NEXT: mov x17, x16 +; CHECKED-NEXT: xpacd x17 +; CHECKED-NEXT: cmp x16, x17 +; CHECKED-NEXT: b.eq [[L]]auth_success_7 +; CHECKED-NEXT: mov x16, x17 +; CHECKED-NEXT: b [[L]]resign_end_7 +; CHECKED-NEXT: Lauth_success_7: +; CHECKED-NEXT: mov x17, #62980 +; CHECKED-NEXT: movk x17, #65535, lsl #16 +; CHECKED-NEXT: movk x17, #65535, lsl #32 +; CHECKED-NEXT: movk x17, #65535, lsl #48 +; CHECKED-NEXT: add x16, x16, x17 +; CHECKED-NEXT: ldrsw x17, [x16] +; CHECKED-NEXT: add x16, x16, x17 +; CHECKED-NEXT: mov x17, #256 +; CHECKED-NEXT: pacda x16, x17 +; CHECKED-NEXT: Lresign_end_7: +; CHECKED-NEXT: mov x0, x16 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_resign_load_relative_loadNegOffset_constdisc: +; TRAP: %bb.0: +; TRAP-NEXT: mov x16, x0 +; TRAP-NEXT: autda x16, x1 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpacd x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq [[L]]auth_success_7 +; TRAP-NEXT: brk #0xc472 +; TRAP-NEXT: Lauth_success_7: +; TRAP-NEXT: mov x17, #62980 +; TRAP-NEXT: movk x17, #65535, lsl #16 +; TRAP-NEXT: movk x17, #65535, lsl #32 +; TRAP-NEXT: movk x17, #65535, lsl #48 +; TRAP-NEXT: add x16, x16, x17 +; TRAP-NEXT: ldrsw x17, [x16] +; TRAP-NEXT: add x16, x16, x17 +; TRAP-NEXT: mov x17, #256 +; TRAP-NEXT: pacda x16, x17 +; TRAP-NEXT: mov x0, x16 +; TRAP-NEXT: ret + %tmp = call i64 @llvm.ptrauth.resign.load.relative(i64 %arg,i32 2,i64 %arg1,i32 2,i64 256,i64 -2556) + ret i64 %tmp +} +define i64 @test_resign_load_relative_largeOffset_constdisc(i64 %arg,i64 %arg1) { +; UNCHECKED-LABEL: test_resign_load_relative_largeOffset_constdisc: +; UNCHECKED: %bb.0: +; UNCHECKED-NEXT: mov x16, x0 +; UNCHECKED-NEXT: autda x16, x1 +; UNCHECKED-NEXT: add x16, x16, #3884 +; UNCHECKED-NEXT: add x16, x16, #7, lsl #12 +; UNCHECKED-NEXT: ldrsw x17, [x16] +; UNCHECKED-NEXT: add x16, x16, x17 +; UNCHECKED-NEXT: mov x17, #256 +; UNCHECKED-NEXT: pacda x16, x17 +; UNCHECKED-NEXT: mov x0, x16 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_resign_load_relative_largeOffset_constdisc: +; CHECKED: %bb.0: +; CHECKED-NEXT: mov x16, x0 +; CHECKED-NEXT: autda x16, x1 +; CHECKED-NEXT: mov x17, x16 +; CHECKED-NEXT: xpacd x17 +; CHECKED-NEXT: cmp x16, x17 +; CHECKED-NEXT: b.eq [[L]]auth_success_8 +; CHECKED-NEXT: mov x16, x17 +; CHECKED-NEXT: b [[L]]resign_end_8 +; CHECKED-NEXT: Lauth_success_8: +; CHECKED-NEXT: add x16, x16, #3884 +; CHECKED-NEXT: add x16, x16, #7, lsl #12 +; CHECKED-NEXT: ldrsw x17, [x16] +; CHECKED-NEXT: add x16, x16, x17 +; CHECKED-NEXT: mov x17, #256 +; CHECKED-NEXT: pacda x16, x17 +; CHECKED-NEXT: Lresign_end_8: +; CHECKED-NEXT: mov x0, x16 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_resign_load_relative_largeOffset_constdisc: +; TRAP: %bb.0: +; TRAP-NEXT: mov x16, x0 +; TRAP-NEXT: autda x16, x1 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpacd x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq [[L]]auth_success_8 +; TRAP-NEXT: brk #0xc472 +; TRAP-NEXT: Lauth_success_8: +; TRAP-NEXT: add x16, x16, #3884 +; TRAP-NEXT: add x16, x16, #7, lsl #12 +; TRAP-NEXT: ldrsw x17, [x16] +; TRAP-NEXT: add x16, x16, x17 +; TRAP-NEXT: mov x17, #256 +; TRAP-NEXT: pacda x16, x17 +; TRAP-NEXT: mov x0, x16 +; TRAP-NEXT: ret + %tmp = call i64 @llvm.ptrauth.resign.load.relative(i64 %arg,i32 2,i64 %arg1,i32 2,i64 256,i64 32556) + ret i64 %tmp +} +declare i64 @llvm.ptrauth.auth(i64, i32, i64) +declare i64 @llvm.ptrauth.resign(i64, i32, i64, i32, i64) +declare i64 @llvm.ptrauth.resign.load.relative(i64,i32,i64,i32,i64,i64) From b57dd79aa2cac1dbb8636e24f59ff73cdd71ab37 Mon Sep 17 00:00:00 2001 From: Abhay Kanhere Date: Thu, 31 Jul 2025 09:43:30 -0700 Subject: [PATCH 2/2] renamed addend to offset, other nits --- clang/lib/Headers/ptrauth.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/clang/lib/Headers/ptrauth.h b/clang/lib/Headers/ptrauth.h index 2eb23803f9faa..5aa99daf58971 100644 --- a/clang/lib/Headers/ptrauth.h +++ b/clang/lib/Headers/ptrauth.h @@ -199,9 +199,9 @@ 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_load_relative_and_sign(__value, __old_key, __old_data, \ - __new_key, __new_data, __addend) \ + __new_key, __new_data, __offset) \ __builtin_ptrauth_auth_load_relative_and_sign( \ - __value, __old_key, __old_data, __new_key, __new_data, __addend) + __value, __old_key, __old_data, __new_key, __new_data, __offset) /* Authenticate a pointer using one scheme and resign it as a C function pointer. @@ -377,14 +377,14 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t; }) #define ptrauth_auth_load_relative_and_sign(__value, __old_key, __old_data, \ - __new_key, __new_data, __addend) \ + __new_key, __new_data, __offset) \ ({ \ (void)__old_key; \ (void)__old_data; \ (void)__new_key; \ (void)__new_data; \ const char *__value_tmp = (const char *)(__value); \ - (void *)(__value_tmp + *(const int *)(__value_tmp + (__addend))); \ + (void *)(__value_tmp + *(const int *)(__value_tmp + (__offset))); \ }) #define ptrauth_auth_function(__value, __old_key, __old_data) \ @@ -416,6 +416,7 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t; ((ptrauth_generic_signature_t)0); \ }) + #define ptrauth_cxx_vtable_pointer(key, address_discrimination, \ extra_discrimination...)