Skip to content
Open
Show file tree
Hide file tree
Changes from 49 commits
Commits
Show all changes
150 commits
Select commit Hold shift + click to select a range
7dfa35d
Arm64: [PAC-RET] Add Pointer Authentication support for Arm64
SwapnilGaikwad Dec 18, 2025
8551ad0
Merge main
SwapnilGaikwad Mar 11, 2026
584a268
Fix build failures
SwapnilGaikwad Mar 11, 2026
8216472
Merge main
SwapnilGaikwad Mar 12, 2026
74a5293
Fix build errors
SwapnilGaikwad Mar 12, 2026
c9c43c9
Limit thread context changes to Arm64
SwapnilGaikwad Mar 12, 2026
5d6058c
Merge main
SwapnilGaikwad Mar 12, 2026
ce5d79b
Fix build issues on x86
SwapnilGaikwad Mar 12, 2026
8db6f6d
Merge main
SwapnilGaikwad Mar 12, 2026
872443e
Merge branch 'main' into github-add-pac
SwapnilGaikwad Mar 12, 2026
3591b2a
Merge main
SwapnilGaikwad Mar 18, 2026
867e149
Limit framelayout changes to JIT
SwapnilGaikwad Mar 18, 2026
f00f789
Fix formatting
SwapnilGaikwad Mar 18, 2026
9616e73
Merge main
SwapnilGaikwad Mar 31, 2026
4582f73
Add MethodAssociatedData containing hijackinfo for NativeAOT
SwapnilGaikwad Mar 31, 2026
d1e65cb
Merge main
SwapnilGaikwad Apr 9, 2026
e1cfd90
Use unwind info to determine value of SP at the time of signing using…
SwapnilGaikwad Apr 9, 2026
cfe6ab8
Fix windows build
SwapnilGaikwad Apr 10, 2026
bed17cd
Merge main
SwapnilGaikwad Apr 10, 2026
cefcd3f
Fix register addressing in asmhelpers
SwapnilGaikwad Apr 10, 2026
f93804f
Merge main
SwapnilGaikwad Apr 10, 2026
280870c
Refactor out IsPacPresent to avoid parsing unwind info multiple times
SwapnilGaikwad Apr 10, 2026
5cc10be
Merge main
SwapnilGaikwad Apr 10, 2026
f186f19
Bail out of RAH instead of hijacking calling frame
SwapnilGaikwad Apr 10, 2026
941d9e2
Remove left-over changes from MethodAssociated Data approach
SwapnilGaikwad Apr 13, 2026
8f9645b
Merge main
SwapnilGaikwad Apr 14, 2026
a755fba
Fallback to DWARF for PAC unwind codes on macos
SwapnilGaikwad Apr 14, 2026
5bde929
Merge main
SwapnilGaikwad Apr 21, 2026
352b3fd
Used stripped the return address while creating a frame OnHijackWorker
SwapnilGaikwad Apr 21, 2026
264f1fe
Remove redundant lef-over changes
SwapnilGaikwad Apr 21, 2026
f455dc1
Mark PacStrip Arm64 only
SwapnilGaikwad Apr 21, 2026
d5a4abb
Merge main
SwapnilGaikwad Apr 21, 2026
a02fac8
Temporarily Revert "JIT: Restore arm64, LA64 and RISCV64 OSR callee s…
SwapnilGaikwad Apr 22, 2026
0d2d0dd
Restore changes from "JIT: Restore arm64, LA64 and RISCV64 OSR callee…
SwapnilGaikwad Apr 23, 2026
f5b520a
Merge main
SwapnilGaikwad Apr 23, 2026
396c868
Strip return address for correct signing in prolog of Tier0 OSR
SwapnilGaikwad Apr 23, 2026
f7d4548
Avoid stripping while restoring Tier0 registers for OSR
SwapnilGaikwad Apr 27, 2026
3ca8d39
Merge main
SwapnilGaikwad Apr 27, 2026
e98099e
Merge main
SwapnilGaikwad Apr 28, 2026
a1768bd
Keep encrypted LR saved in a slot while creating hijack frame
SwapnilGaikwad Apr 28, 2026
1827095
Remove todo from libunwind to use strip instead of auth
SwapnilGaikwad Apr 28, 2026
b43e5e7
Use auth instead of strip in windows unwinder
SwapnilGaikwad Apr 29, 2026
52ca210
Merge main
SwapnilGaikwad Apr 29, 2026
e5d5ca3
Keep signed return address for the hijackframe and authenticate it on…
SwapnilGaikwad Apr 30, 2026
037a0a4
Merge main
SwapnilGaikwad Apr 30, 2026
1e4ae0a
Merge main
SwapnilGaikwad Apr 30, 2026
067c38f
Fix build issues on macos
SwapnilGaikwad Apr 30, 2026
fcbcdf5
Merge main
SwapnilGaikwad Apr 30, 2026
e1a3695
Handle phantom unwind codes correctly
SwapnilGaikwad Apr 30, 2026
d288cea
Merge main
SwapnilGaikwad May 5, 2026
146da5e
Address review comments
SwapnilGaikwad May 5, 2026
ebad545
Use xpaci instead xpaclri for stripping
SwapnilGaikwad May 5, 2026
89a9ded
Incorporate review comment
SwapnilGaikwad May 5, 2026
650ef08
Merge main
SwapnilGaikwad May 5, 2026
80ed0b4
Merge main
SwapnilGaikwad May 6, 2026
e17d8e9
Refactor GetPacSignInfo
SwapnilGaikwad May 6, 2026
22dccb7
Don't assume sp offset to be zero for PAC signing
SwapnilGaikwad May 7, 2026
21bc75a
Canonicalize return addresses in StackFrameIterator for NativeAOT
SwapnilGaikwad May 7, 2026
cd162df
Merge main
SwapnilGaikwad May 7, 2026
493eff7
Track SP offset for PAC instruction separately while calculating hija…
SwapnilGaikwad May 7, 2026
84741a8
Merge main
SwapnilGaikwad May 7, 2026
bcbc1c1
Use B key on Windows and A key otherwise for PAC
SwapnilGaikwad May 7, 2026
dfac51c
Merge main
SwapnilGaikwad May 7, 2026
24d44ea
Fix formatting
SwapnilGaikwad May 7, 2026
12ca90d
Merge main
SwapnilGaikwad May 8, 2026
7df0c1f
Address review comments
SwapnilGaikwad May 8, 2026
0b6b5a2
Merge main
SwapnilGaikwad May 8, 2026
e9be308
Track PAC CFA offset while unwinding for NativeAOT
SwapnilGaikwad May 8, 2026
ddccab0
Match finding SP for PAC signing on Windows NativeAOT with the JIT
SwapnilGaikwad May 8, 2026
ff1f08e
Fix build errors
SwapnilGaikwad May 11, 2026
3a6ad11
Merge main
SwapnilGaikwad May 11, 2026
e71d980
Merge main
SwapnilGaikwad May 13, 2026
a07d3bd
Merge main
SwapnilGaikwad May 13, 2026
af97173
Remove redundant changes
SwapnilGaikwad May 13, 2026
f153e2b
Merge main
SwapnilGaikwad May 14, 2026
c40c08c
Make JitPacEnabled config variable Arm64 only
SwapnilGaikwad May 14, 2026
27f8c9b
Merge main
SwapnilGaikwad May 15, 2026
a6b6641
Restore clearing THUMB_CODE on arm32
SwapnilGaikwad May 15, 2026
f5b5954
Merge main and JIT changes
SwapnilGaikwad May 19, 2026
b6fa62e
Merge main
SwapnilGaikwad May 19, 2026
401b496
Use PAL unwinder for UNIX to retrieve signing SP for PAC
SwapnilGaikwad May 19, 2026
d21c942
Merge main
SwapnilGaikwad May 20, 2026
9a2a161
Restore missing THUMB_CODE clearing on Arm32
SwapnilGaikwad May 20, 2026
82b962d
Merge main
SwapnilGaikwad May 21, 2026
f4c7ec1
Switch to use PAL unwinder for Windows to retrieve signing SP for PAC
SwapnilGaikwad May 21, 2026
82a8ec4
Try fixing build failures on Windows
SwapnilGaikwad May 21, 2026
64c7367
Merge main
SwapnilGaikwad May 27, 2026
a24b0b7
Merge main
SwapnilGaikwad May 28, 2026
b5bd6c2
Merge main
SwapnilGaikwad May 28, 2026
e44b17a
Update JIT GUID temporarilty to enable SPMI tests
SwapnilGaikwad May 28, 2026
0645777
Merge main
SwapnilGaikwad May 29, 2026
3ef9668
Address review comments
SwapnilGaikwad May 29, 2026
6bdc21f
Merge main
SwapnilGaikwad May 29, 2026
a66dd10
Pass signing sp for managed frame to hijack frame
SwapnilGaikwad May 29, 2026
4113f04
Merge main
SwapnilGaikwad Jun 1, 2026
d539d9d
Strip return address in cdac unwinder
SwapnilGaikwad Jun 1, 2026
88b9eb2
Handle RTL_VIRTUAL_UNWIND2_VALIDATE_PAC in unwinder
SwapnilGaikwad Jun 1, 2026
363156e
Revert "Handle RTL_VIRTUAL_UNWIND2_VALIDATE_PAC in unwinder"
SwapnilGaikwad Jun 1, 2026
13cf190
Merge main
SwapnilGaikwad Jun 2, 2026
d5a1b3c
Use ARM64_ARG macro for Arm64 specific args in HijackFrame
SwapnilGaikwad Jun 2, 2026
3da8014
Merge main
SwapnilGaikwad Jun 3, 2026
b3ffd12
Switch to PAL unwinder for NativeAOT on Windows
SwapnilGaikwad Jun 3, 2026
9dfec15
Use auth instead of strip while returning from hijack in NativeAOT
SwapnilGaikwad Jun 3, 2026
0f7379b
Fix build errors on Windows
SwapnilGaikwad Jun 3, 2026
9f20273
Merge main
SwapnilGaikwad Jun 3, 2026
b7f5452
Merge main
SwapnilGaikwad Jun 4, 2026
528710b
Fix build errors on Windows
SwapnilGaikwad Jun 4, 2026
782e0d8
Try fixing arm32 and x64 build failures
SwapnilGaikwad Jun 4, 2026
ba25589
Merge main
SwapnilGaikwad Jun 4, 2026
3efd414
Try fixing build errors
SwapnilGaikwad Jun 4, 2026
98cbb04
More build fixes
SwapnilGaikwad Jun 4, 2026
e41c3ca
Limit changes to NativeAOT declartions to Arm64 only
SwapnilGaikwad Jun 4, 2026
15fe969
Merge main
SwapnilGaikwad Jun 4, 2026
0910b0a
Avoid separate definitions for NativeAOT in daccess.h
SwapnilGaikwad Jun 5, 2026
0e41b35
Avoid adding crosscomp.h for NativeAOT builds to avoid redef warnings…
SwapnilGaikwad Jun 5, 2026
dbb330a
Merge main
SwapnilGaikwad Jun 5, 2026
2f49693
Address review comments
SwapnilGaikwad Jun 8, 2026
f564983
Merge main
SwapnilGaikwad Jun 8, 2026
473a3a5
Merge main
SwapnilGaikwad Jun 9, 2026
295ab9b
Avoid parsing Apple compact unwind as PAC DWARF info
SwapnilGaikwad Jun 10, 2026
82a1e88
Merge main
SwapnilGaikwad Jun 10, 2026
ffa7fb5
Temporarily disable return address stripping in cdac unwinder
SwapnilGaikwad Jun 10, 2026
f5105ff
Merge main
SwapnilGaikwad Jun 10, 2026
48d0189
Merge main
SwapnilGaikwad Jun 10, 2026
aea1eee
Restore Linux ARM64 NativeAOT unwindability behavior
SwapnilGaikwad Jun 12, 2026
756e59c
Revert cdac unwinder changes
SwapnilGaikwad Jun 12, 2026
1f81993
Merge main
SwapnilGaikwad Jun 12, 2026
fcf77c1
Update return value explicitly when PAC info not found
SwapnilGaikwad Jun 15, 2026
faa2a32
Enable hijacking current frame when interrupted in outside prolog/epi…
SwapnilGaikwad Jun 15, 2026
ff276e4
Merge main
SwapnilGaikwad Jun 15, 2026
7de5a37
Merge main
SwapnilGaikwad Jun 17, 2026
c216dc6
Merge branch 'main' into github-add-pac
jkotas Jun 21, 2026
0ab4e9a
Apply suggestion from @jkotas
jkotas Jun 22, 2026
e4c1e75
Apply suggestion from @jkotas
jkotas Jun 22, 2026
fdcb483
Merge main
SwapnilGaikwad Jun 22, 2026
f704206
Track signing SP in unwind info to handle stack allocation before pac
SwapnilGaikwad Jun 22, 2026
e00e37b
Merge main
SwapnilGaikwad Jun 24, 2026
be49175
Strip return addresses while using in CDAC
SwapnilGaikwad Jun 24, 2026
0d6d757
Fix build errors
SwapnilGaikwad Jun 24, 2026
67a381f
Merge main
SwapnilGaikwad Jun 24, 2026
18a9ab7
Try fixing cdac test failures
SwapnilGaikwad Jun 25, 2026
9a588b5
Avoid hijacking on the return instruction for NativeAOT
SwapnilGaikwad Jun 25, 2026
564fa6a
Merge main
SwapnilGaikwad Jun 25, 2026
3b70987
Try fixing cdac tests
SwapnilGaikwad Jun 26, 2026
ddd0f17
Merge main
SwapnilGaikwad Jun 26, 2026
c520e2f
Address review comments
SwapnilGaikwad Jun 26, 2026
532df3a
Disable hardcoding pauth on Windows
SwapnilGaikwad Jun 26, 2026
59a90e3
Revert adding CFI_DEF_CFA before CFI_NEGATE_RA_STATE
SwapnilGaikwad Jun 29, 2026
ef9c416
Avoid hijacking on RET only when PAC is enabled
SwapnilGaikwad Jun 29, 2026
72a79ff
Merge main
SwapnilGaikwad Jun 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/coreclr/debug/ee/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
#include "../../vm/methoditer.h"
#include "../../vm/tailcallhelp.h"

#if defined(TARGET_ARM64)
extern "C" void* PacStripPtr(void* ptr);
#endif // TARGET_ARM64

const char *GetTType( TraceType tt);

#define IsSingleStep(exception) ((exception) == EXCEPTION_SINGLE_STEP)
Expand Down Expand Up @@ -6198,6 +6202,12 @@ static bool IsTailCall(const BYTE * ip, ControllerStackInfo* info, TailCallFunct
TailCallTls* tls = GetThread()->GetTailCallTls();
LPVOID tailCallAwareRetAddr = tls->GetFrame()->TailCallAwareReturnAddress;

#if defined(TARGET_ARM64)
//TODO-PAC: Authenticate instead of stripping the return addresses.
retAddr = PacStripPtr(retAddr);
tailCallAwareRetAddr = PacStripPtr(tailCallAwareRetAddr);
#endif // TARGET_ARM64

LOG((LF_CORDB,LL_INFO1000, "ITCTR: ret addr is %p, tailcall aware ret addr is %p\n",
retAddr, tailCallAwareRetAddr));

Expand Down
4 changes: 3 additions & 1 deletion src/coreclr/inc/cfi.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ enum CFI_OPCODE
{
CFI_ADJUST_CFA_OFFSET, // Offset is adjusted relative to the current one.
CFI_DEF_CFA_REGISTER, // New register is used to compute CFA
CFI_REL_OFFSET // Register is saved at offset from the current CFA
CFI_REL_OFFSET, // Register is saved at offset from the current CFA
CFI_DEF_CFA, // Take address from register and add offset to it
CFI_NEGATE_RA_STATE, // Sign the return address in lr with paciasp
};

struct CFI_CODE
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/inc/clrconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,7 @@ RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableArm64Sm4, W("EnableArm64Sm
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableArm64SveAes, W("EnableArm64SveAes"), 1, "Allows Arm64 SveAes+ hardware intrinsics to be disabled")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableArm64SveSha3, W("EnableArm64SveSha3"), 1, "Allows Arm64 SveSha3+ hardware intrinsics to be disabled")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableArm64SveSm4, W("EnableArm64SveSm4"), 1, "Allows Arm64 SveSm4+ hardware intrinsics to be disabled")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_JitPacEnabled, W("JitPacEnabled"), 1, "Allows Arm64 Pointer Authentication (PAC) to be disabled")
#elif defined(TARGET_RISCV64)
Comment thread
SwapnilGaikwad marked this conversation as resolved.
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableRiscV64Zba, W("EnableRiscV64Zba"), 1, "Allows RiscV64 Zba hardware intrinsics to be disabled")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableRiscV64Zbb, W("EnableRiscV64Zbb"), 1, "Allows RiscV64 Zbb hardware intrinsics to be disabled")
Expand Down
7 changes: 6 additions & 1 deletion src/coreclr/inc/gcinfodecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ typedef void * OBJECTREF;

#ifndef __cgencpu_h__

#if defined(TARGET_ARM64)
extern "C" void* PacStripPtr(void* ptr);
#endif // TARGET_ARM64

inline void SetIP(T_CONTEXT* context, PCODE rip)
{
_ASSERTE(!"don't call this");
Expand Down Expand Up @@ -105,7 +109,8 @@ inline PCODE GetIP(T_CONTEXT* context)
#elif defined(TARGET_ARM)
return (PCODE)context->Pc;
#elif defined(TARGET_ARM64)
return (PCODE)context->Pc;
//TODO-PAC: Authenticate instead of stripping the return address.
Comment thread
SwapnilGaikwad marked this conversation as resolved.
Outdated
return (PCODE) PacStripPtr((void *)context->Pc);
#elif defined(TARGET_LOONGARCH64)
return (PCODE)context->Pc;
#elif defined(TARGET_RISCV64)
Expand Down
37 changes: 33 additions & 4 deletions src/coreclr/jit/codegenarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,11 @@ void CodeGen::genPopCalleeSavedRegistersAndFreeLclFrame(bool jmpEpilog)
}
}

if (JitConfig.JitPacEnabled() != 0)
{
GetEmitter()->emitPacInEpilog();
}

// For OSR, we must also adjust the SP to remove the Tier0 frame.
//
if (m_compiler->opts.IsOSR())
Expand Down Expand Up @@ -487,12 +492,13 @@ void CodeGen::genPrologSaveRegPair(regNumber reg1,

if ((spOffset == 0) && (spDelta >= -512))
{
// We can use pre-indexed addressing.
// We can use pre-indexed addressing when the stack adjustment fits in the instruction.
// Generate:
// stp REG, REG + 1, [SP, #spDelta]!
// 64-bit STP offset range: -512 to 504, multiple of 8.
assert(reg1 != REG_LR);
Comment thread
SwapnilGaikwad marked this conversation as resolved.
GetEmitter()->emitIns_R_R_R_I(INS_stp, EA_PTRSIZE, reg1, reg2, REG_SPBASE, spDelta, INS_OPTS_PRE_INDEX);
m_compiler->unwindSaveRegPairPreindexed(reg1, reg2, spDelta);

needToSaveRegs = false;
}
else // (spOffset != 0) || (spDelta < -512)
Expand All @@ -511,6 +517,8 @@ void CodeGen::genPrologSaveRegPair(regNumber reg1,
// 64-bit STP offset range: -512 to 504, multiple of 8.
assert(spOffset <= 504);
assert((spOffset % 8) == 0);
assert(reg1 != REG_LR);

GetEmitter()->emitIns_R_R_R_I(INS_stp, EA_PTRSIZE, reg1, reg2, REG_SPBASE, spOffset);

if (TargetOS::IsUnix && m_compiler->generateCFIUnwindCodes())
Expand Down Expand Up @@ -622,6 +630,7 @@ void CodeGen::genRestoreRegPair(regNumber reg1,
assert((spDelta % 16) == 0); // SP changes must be 16-byte aligned
assert(genIsValidFloatReg(reg1) == genIsValidFloatReg(reg2)); // registers must be both general-purpose, or both
// FP/SIMD
assert(reg1 != REG_LR);

if (spDelta != 0)
{
Expand Down Expand Up @@ -1384,6 +1393,11 @@ void CodeGen::genFuncletProlog(BasicBlock* block)

m_compiler->unwindBegProlog();

if (JitConfig.JitPacEnabled() != 0)
{
GetEmitter()->emitPacInProlog();
}

regMaskTP maskSaveRegsFloat = genFuncletInfo.fiSaveRegs & RBM_ALLFLOAT;
regMaskTP maskSaveRegsInt = genFuncletInfo.fiSaveRegs & ~maskSaveRegsFloat;

Expand Down Expand Up @@ -1590,7 +1604,6 @@ void CodeGen::genFuncletEpilog(BasicBlock* /* block */)
{
GetEmitter()->emitIns_R_R_R_I(INS_ldp, EA_PTRSIZE, REG_FP, REG_LR, REG_SPBASE, 0);
m_compiler->unwindSaveRegPair(REG_FP, REG_LR, 0);

genStackPointerAdjustment(-genFuncletInfo.fiSpDelta1, REG_SCRATCH, nullptr, /* reportUnwindData */ true);
}
else
Expand Down Expand Up @@ -1621,7 +1634,6 @@ void CodeGen::genFuncletEpilog(BasicBlock* /* block */)
else if (genFuncletInfo.fiFrameType == 3)
{
// With OSR we may see large values for fiSpDelta1
//
if (m_compiler->opts.IsOSR())
{
GetEmitter()->emitIns_R_R_R_I(INS_ldp, EA_PTRSIZE, REG_FP, REG_LR, REG_SPBASE, 0);
Expand Down Expand Up @@ -1669,6 +1681,11 @@ void CodeGen::genFuncletEpilog(BasicBlock* /* block */)
}
}

if (JitConfig.JitPacEnabled() != 0)
{
GetEmitter()->emitPacInEpilog();
}

inst_RV(INS_ret, REG_LR, TYP_I_IMPL);
m_compiler->unwindReturn(REG_LR);

Expand Down Expand Up @@ -5675,6 +5692,18 @@ void CodeGen::genOSRHandleTier0CalleeSavedRegistersAndFrame()
genRestoreRegPair(REG_FP, REG_LR, REG_FP, 0, 0, false, REG_IP1, nullptr,
/* reportUnwindData */ false);

if (JitConfig.JitPacEnabled() != 0)
{
// Tier0 signed LR with the Tier0 caller SP before allocating its frame.
// Recreate that SP from the current Tier0 body SP so we can authenticate
// LR before the OSR prolog later re-signs it with the OSR SP via PACIASP.
genInstrWithConstant(INS_add, EA_PTRSIZE, REG_IP0, REG_SPBASE, patchpointInfo->TotalFrameSize(), REG_IP0,
/* inUnwindRegion */ false);
GetEmitter()->emitIns_Mov(INS_mov, EA_PTRSIZE, REG_IP1, REG_LR, /* canSkip */ false);
GetEmitter()->emitIns(INS_autia1716);
GetEmitter()->emitIns_Mov(INS_mov, EA_PTRSIZE, REG_LR, REG_IP1, /* canSkip */ false);
}

// Emit phantom unwind data for the tier0 frame.
m_compiler->unwindAllocStack(patchpointInfo->TotalFrameSize());
// Emit nops to make the prolog 1:1 in unwind codes to instructions. This
Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/jit/codegenarmarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4476,6 +4476,11 @@ void CodeGen::genPushCalleeSavedRegisters(regNumber initReg, bool* pInitRegZeroe
}
#endif // DEBUG

if (JitConfig.JitPacEnabled() != 0)
{
GetEmitter()->emitPacInProlog();
}

// The frameType number is arbitrary, is defined below, and corresponds to one of the frame styles we
// generate based on various sizes.
int frameType = 0;
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -9558,6 +9558,7 @@ class Compiler
void unwindSaveRegPair(regNumber reg1, regNumber reg2, int offset); // stp reg1, reg2, [sp, #offset]
void unwindSaveRegPairPreindexed(regNumber reg1, regNumber reg2, int offset); // stp reg1, reg2, [sp, #offset]!
void unwindSaveNext(); // unwind code: save_next
void unwindPacSignLR(); // unwind code: pac_sign_lr
void unwindReturn(regNumber reg); // ret lr
#endif // defined(TARGET_ARM64)

Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/jit/emit.h
Original file line number Diff line number Diff line change
Expand Up @@ -3337,6 +3337,11 @@ class emitter
instrDescAlign* emitNewInstrAlign();
#endif

#if defined(TARGET_ARM64)
void emitPacInProlog();
void emitPacInEpilog();
#endif

instrDesc* emitNewInstrSmall(emitAttr attr);
instrDesc* emitNewInstr(emitAttr attr = EA_4BYTE);
instrDesc* emitNewInstrSC(emitAttr attr, cnsval_ssize_t cns);
Expand Down
26 changes: 26 additions & 0 deletions src/coreclr/jit/emitarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1431,6 +1431,32 @@ static const char * const bRegNames[] =

// clang-format on

//------------------------------------------------------------------------
// emitPacInProlog: Sign LR as part of Pointer Authentication (PAC) support
//
void emitter::emitPacInProlog()
{
if (JitConfig.JitPacEnabled() == 0)
{
return;
}
emitIns(INS_paciasp);
m_compiler->unwindPacSignLR();
}

//------------------------------------------------------------------------
// emitPacInEpilog: unsign LR as part of Pointer Authentication (PAC) support
//
void emitter::emitPacInEpilog()
{
if (JitConfig.JitPacEnabled() == 0)
{
return;
}
emitIns(INS_autiasp);
m_compiler->unwindPacSignLR();
Comment thread
SwapnilGaikwad marked this conversation as resolved.
}

//------------------------------------------------------------------------
// emitRegName: Returns a general-purpose register name or SIMD and floating-point scalar register name.
//
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/jitconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ CONFIG_STRING(JitInlineMethodsWithEHRange, "JitInlineMethodsWithEHRange")

CONFIG_INTEGER(JitLongAddress, "JitLongAddress", 0) // Force using the large pseudo instruction form for long address
CONFIG_INTEGER(JitMaxUncheckedOffset, "JitMaxUncheckedOffset", 8)
RELEASE_CONFIG_INTEGER(JitPacEnabled, "JitPacEnabled", 1)

Comment thread
SwapnilGaikwad marked this conversation as resolved.
// Enable devirtualization for generic virtual methods
RELEASE_CONFIG_INTEGER(JitEnableGenericVirtualDevirtualization, "JitEnableGenericVirtualDevirtualization", 1)
Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/jit/unwind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,11 @@ void Compiler::DumpCfiInfo(bool isHotCode,
assert(dwarfReg == DWARF_REG_ILLEGAL);
printf(" CodeOffset: 0x%02X Op: AdjustCfaOffset Offset:0x%X\n", codeOffset, offset);
break;
case CFI_NEGATE_RA_STATE:
assert(dwarfReg == DWARF_REG_ILLEGAL);
assert(offset == 0);
printf(" CodeOffset: 0x%02X Op: NegateRAState\n", codeOffset);
break;
default:
printf(" Unrecognized CFI_CODE: 0x%llX\n", *(UINT64*)pCode);
break;
Expand Down
33 changes: 33 additions & 0 deletions src/coreclr/jit/unwindarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,33 @@ void Compiler::unwindSaveNext()
pu->AddCode(0xE6);
}

void Compiler::unwindPacSignLR()
{
if (JitConfig.JitPacEnabled() == 0)
{
return;
}
#if defined(FEATURE_CFI_SUPPORT)
if (generateCFIUnwindCodes())
{
// Emit NEGATE_RA_STATE opcode in prologs.
if (!compGeneratingProlog)
{
return;
}
FuncInfoDsc* func = funCurrentFunc();
UNATIVE_OFFSET cbProlog = unwindGetCurrentOffset(func);
// Maps to DW_CFA_AARCH64_negate_ra_state
createCfiCode(func, cbProlog, CFI_NEGATE_RA_STATE, DWARF_REG_ILLEGAL);

return;
}
#endif // FEATURE_CFI_SUPPORT

// pac_sign_lr: 11111100: sign the return address in lr with paciasp
funCurrentFunc()->uwi.AddCode(0xFC);
Comment thread
dhartglassMSFT marked this conversation as resolved.
}
Comment thread
SwapnilGaikwad marked this conversation as resolved.

void Compiler::unwindReturn(regNumber reg)
{
// Nothing to do; we will always have at least one trailing "end" opcode in our padding.
Expand Down Expand Up @@ -1081,6 +1108,12 @@ void DumpUnwindInfo(Compiler* comp,

printf(" %02X save_next\n", b1);
}
else if (b1 == 0xFC)
{
// pac_sign_lr: 11111100 : sign the return address in lr with paciasp.

printf(" %02X pac_sign_lr\n", b1);
}
else
{
// Unknown / reserved unwind code
Expand Down
3 changes: 2 additions & 1 deletion src/coreclr/nativeaot/Runtime/ICodeManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@ class ICodeManager

virtual bool GetReturnAddressHijackInfo(MethodInfo * pMethodInfo,
REGDISPLAY * pRegisterSet, // in
PTR_PTR_VOID * ppvRetAddrLocation // out
PTR_PTR_VOID * ppvRetAddrLocation, // out
uintptr_t * pSpForArm64PacSign // out
) PURE_VIRTUAL

#ifdef TARGET_X86
Expand Down
14 changes: 14 additions & 0 deletions src/coreclr/nativeaot/Runtime/StackFrameIterator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ EXTERN_C CODE_LOCATION RhpRethrow2;
#define FAILFAST_OR_DAC_FAIL_UNCONDITIONALLY(msg) { ASSERT_UNCONDITIONALLY(msg); RhFailFast(); }
#endif

#if defined(TARGET_ARM64)
extern "C" void* PacStripPtr(void* ptr);
#endif // TARGET_ARM64

StackFrameIterator::StackFrameIterator(Thread * pThreadToWalk, PInvokeTransitionFrame* pInitialTransitionFrame)
{
STRESS_LOG0(LF_STACKWALK, LL_INFO10000, "----Init---- [ GC ]\n");
Expand Down Expand Up @@ -1854,7 +1858,12 @@ void StackFrameIterator::NextInternal()
// if the thread is safe to walk, it better not have a hijack in place.
ASSERT(!m_pThread->IsHijacked());

#if defined(TARGET_ARM64)
// TODO-PAC: Authenticate instead of stripping the return address.
SetControlPC(PacStripPtr(dac_cast<PTR_VOID>(PCODEToPINSTR(m_RegDisplay.GetIP()))));
#else
SetControlPC(dac_cast<PTR_VOID>(PCODEToPINSTR(m_RegDisplay.GetIP())));
#endif // TARGET_ARM64

PTR_VOID collapsingTargetFrame = NULL;

Expand Down Expand Up @@ -2185,6 +2194,11 @@ void StackFrameIterator::CalculateCurrentMethodState()
return;
}

#if defined(TARGET_ARM64)
//TODO-PAC: Authenticate instead of stripping the return addresses.
m_ControlPC = PacStripPtr(m_ControlPC);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would expect the stripping to be always done when we are converting return address to a PC.

It is hard to see that stripping in the middle like here is done correctly. We should avoid fields that are mix of stripped and signed values depending on the code location.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid a location dependent value, I updated the patch to always save plain return address in m_RegDisplay instead of stripping it on-demand at use sites. Not sure if this is an ideal approach but it avoids confusion.
Happy to incorporate if you suggest any other approach.

#endif // TARGET_ARM64

// Assume that the caller is likely to be in the same module
if (m_pCodeManager == NULL || !m_pCodeManager->FindMethodInfo(m_ControlPC, &m_methodInfo))
{
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/nativeaot/Runtime/arm64/GcProbe.S
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@
// Fix the stack by restoring the original return address
//
ldr lr, [x9, #OFFSETOF__Thread__m_pvHijackedReturnAddress]
xpaclri

//
// Clear hijack state
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/nativeaot/Runtime/arm64/GcProbe.asm
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ PROBE_FRAME_SIZE field 0
;; Fix the stack by restoring the original return address
;;
ldr lr, [x9, #OFFSETOF__Thread__m_pvHijackedReturnAddress]
DCD 0xD50320FF ;; xpaclri instruction in binary to avoid error while compiling with non-PAC enabled compilers

;;
;; Clear hijack state
Expand Down
25 changes: 25 additions & 0 deletions src/coreclr/nativeaot/Runtime/arm64/MiscStubs.S
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,28 @@

#include <unixasmmacros.inc>
#include "AsmOffsets.inc"

// void* PacStripPtr(void *);
// This function strips the pointer of PAC info that is passed as an agrument.
// To avoid failing on non-PAC enabled machines, we use xpaclri (instead of xpaci) which strips lr explicitly.
// Thus we move need to move input in lr, strip it and copy it back to the result register.
.arch_extension pauth
LEAF_ENTRY PacStripPtr, _TEXT
mov x9, lr
mov lr, x0
xpaclri
mov x0, lr
ret x9
LEAF_END PacStripPtr, _TEXT

// void* PacSignPtr(void *, void *);
// This function sign the input pointer using zero as salt.
// Thus we need to move input in lr, sign it and then copy it back to the result register.
.arch_extension pauth
LEAF_ENTRY PacSignPtr, _TEXT
mov x17, x0
mov x16, x1
pacia1716
mov x0, x17
ret
LEAF_END PacSignPtr, _TEXT
Loading
Loading