Skip to content

Commit 4b73d17

Browse files
committed
keep SSP value in REGDISPLAY, update as we unwind.
1 parent 27e9b9d commit 4b73d17

7 files changed

Lines changed: 88 additions & 23 deletions

File tree

src/coreclr/nativeaot/Runtime/PalRedhawkCommon.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ struct PAL_LIMITED_CONTEXT
153153
uintptr_t R13;
154154
uintptr_t R14;
155155
uintptr_t R15;
156-
uintptr_t __explicit_padding__;
156+
uintptr_t SSP;
157157
Fp128 Xmm6;
158158
Fp128 Xmm7;
159159
Fp128 Xmm8;

src/coreclr/nativeaot/Runtime/StackFrameIterator.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,12 @@ void StackFrameIterator::InternalInit(Thread * pThreadToWalk, PTR_PAL_LIMITED_CO
517517
m_RegDisplay.pR13 = (PTR_uintptr_t)PTR_TO_MEMBER_TADDR(PAL_LIMITED_CONTEXT, pCtx, R13);
518518
m_RegDisplay.pR14 = (PTR_uintptr_t)PTR_TO_MEMBER_TADDR(PAL_LIMITED_CONTEXT, pCtx, R14);
519519
m_RegDisplay.pR15 = (PTR_uintptr_t)PTR_TO_MEMBER_TADDR(PAL_LIMITED_CONTEXT, pCtx, R15);
520+
521+
//
522+
// SSP, we only need the value
523+
//
524+
m_RegDisplay.SSP = pCtx->SSP;
525+
520526
//
521527
// preserved xmm regs
522528
//
@@ -633,6 +639,11 @@ void StackFrameIterator::InternalInit(Thread * pThreadToWalk, NATIVE_CONTEXT* pC
633639
m_RegDisplay.pR14 = (PTR_uintptr_t)PTR_TO_REG(pCtx, R14);
634640
m_RegDisplay.pR15 = (PTR_uintptr_t)PTR_TO_REG(pCtx, R15);
635641

642+
//
643+
// SSP, not needed. Unwind from native context is never for EH.
644+
//
645+
m_RegDisplay.SSP = 0;
646+
636647
//
637648
// scratch regs
638649
//
@@ -1005,6 +1016,11 @@ void StackFrameIterator::UnwindFuncletInvokeThunk()
10051016
m_RegDisplay.pR14 = SP++;
10061017
m_RegDisplay.pR15 = SP++;
10071018

1019+
if (m_RegDisplay.SSP)
1020+
{
1021+
m_RegDisplay.SSP += 8;
1022+
}
1023+
10081024
#elif defined(TARGET_X86)
10091025
SP = (PTR_uintptr_t)(m_RegDisplay.SP + 0x4); // skip the saved assembly-routine-EBP
10101026

@@ -1369,6 +1385,12 @@ void StackFrameIterator::UnwindUniversalTransitionThunk()
13691385
m_RegDisplay.SetIP(PCODEToPINSTR(*addressOfPushedCallerIP));
13701386
m_RegDisplay.SetSP((uintptr_t)dac_cast<TADDR>(stackFrame->get_CallerSP()));
13711387
SetControlPC(dac_cast<PTR_VOID>(m_RegDisplay.GetIP()));
1388+
#if defined(TARGET_AMD64) && defined(TARGET_WINDOWS)
1389+
if (m_RegDisplay.SSP)
1390+
{
1391+
m_RegDisplay.SSP += 8;
1392+
}
1393+
#endif
13721394

13731395
// All universal transition cases rely on conservative GC reporting being applied to the
13741396
// full argument set that flowed into the call. Report the lower bound of this range (the
@@ -1429,6 +1451,12 @@ void StackFrameIterator::UnwindThrowSiteThunk()
14291451
m_RegDisplay.pR13 = (PTR_uintptr_t)PTR_TO_MEMBER_TADDR(PAL_LIMITED_CONTEXT, pContext, R13);
14301452
m_RegDisplay.pR14 = (PTR_uintptr_t)PTR_TO_MEMBER_TADDR(PAL_LIMITED_CONTEXT, pContext, R14);
14311453
m_RegDisplay.pR15 = (PTR_uintptr_t)PTR_TO_MEMBER_TADDR(PAL_LIMITED_CONTEXT, pContext, R15);
1454+
1455+
if (m_RegDisplay.SSP)
1456+
{
1457+
m_RegDisplay.SSP += 8;
1458+
}
1459+
14321460
#elif defined(TARGET_ARM)
14331461
m_RegDisplay.pR4 = (PTR_uintptr_t)PTR_TO_MEMBER_TADDR(PAL_LIMITED_CONTEXT, pContext, R4);
14341462
m_RegDisplay.pR5 = (PTR_uintptr_t)PTR_TO_MEMBER_TADDR(PAL_LIMITED_CONTEXT, pContext, R5);

src/coreclr/nativeaot/Runtime/amd64/AsmOffsetsCpu.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ PLAT_ASM_OFFSET(0f0, PAL_LIMITED_CONTEXT, Xmm15)
5959
PLAT_ASM_SIZEOF(130, REGDISPLAY)
6060
PLAT_ASM_OFFSET(78, REGDISPLAY, SP)
6161
PLAT_ASM_OFFSET(80, REGDISPLAY, IP)
62+
PLAT_ASM_OFFSET(88, REGDISPLAY, SSP)
6263

6364
PLAT_ASM_OFFSET(18, REGDISPLAY, pRbx)
6465
PLAT_ASM_OFFSET(20, REGDISPLAY, pRbp)

src/coreclr/nativeaot/Runtime/amd64/ExceptionHandling.asm

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ ALTERNATE_ENTRY RhpThrowHwExGEHCONT ; this needs to be an EHCONT target since we
4444
.pushframe
4545

4646
alloc_stack SIZEOF_XmmSaves + 8h ;; reserve stack for the xmm saves (+8h to realign stack)
47-
push_vol_reg r8 ;; padding
47+
rdsspq r8 ;; nop if SSP is not implemented, 0 if not enabled
48+
push_vol_reg r8 ;; SSP
49+
xor r8, r8
4850
push_nonvol_reg r15
4951
push_nonvol_reg r14
5052
push_nonvol_reg r13
@@ -127,7 +129,9 @@ NESTED_ENTRY RhpThrowEx, _TEXT
127129
xor r8, r8
128130

129131
alloc_stack SIZEOF_XmmSaves + 8h ;; reserve stack for the xmm saves (+8h to realign stack)
130-
push_vol_reg r8 ;; padding
132+
rdsspq r8 ;; nop if SSP is not implemented, 0 if not enabled
133+
push_vol_reg r8 ;; SSP
134+
xor r8, r8
131135
push_nonvol_reg r15
132136
push_nonvol_reg r14
133137
push_nonvol_reg r13
@@ -221,7 +225,9 @@ NESTED_ENTRY RhpRethrow, _TEXT
221225
xor r8, r8
222226

223227
alloc_stack SIZEOF_XmmSaves + 8h ;; reserve stack for the xmm saves (+8h to realign stack)
224-
push_vol_reg r8 ;; padding
228+
rdsspq r8 ;; nop if SSP is not implemented, 0 if not enabled
229+
push_vol_reg r8 ;; SSP
230+
xor r8, r8
225231
push_nonvol_reg r15
226232
push_nonvol_reg r14
227233
push_nonvol_reg r13
@@ -490,7 +496,7 @@ endif
490496
INLINE_THREAD_UNHIJACK rdx, rcx, r9 ;; Thread in rdx, trashes rcx and r9
491497

492498
mov rcx, [rsp + rsp_offsetof_arguments + 18h] ;; rcx <- current ExInfo *
493-
mov r10, [r8 + OFFSETOF__REGDISPLAY__IP] ;; r10 <- original IP value
499+
mov r11, [r8 + OFFSETOF__REGDISPLAY__SSP] ;; r11 <- resume SSP value
494500
mov r8, [r8 + OFFSETOF__REGDISPLAY__SP] ;; r8 <- resume SP value
495501
xor r9, r9 ;; r9 <- 0
496502

@@ -505,7 +511,7 @@ endif
505511
;; Sanity check: if we have shadow stack, it should agree with what we have in rsp
506512
LOCAL_STACK_USE equ 118h
507513
ifdef _DEBUG
508-
rdsspq r9
514+
rdsspq r9 ;; NB, r9 == 0 prior to this
509515
test r9, r9
510516
jz @f
511517
mov r9, [r9]
@@ -531,23 +537,23 @@ endif
531537
;; reset RSP and jump to RAX
532538
@@: mov rsp, r8 ;; reset the SP to resume SP value
533539

534-
;; if have shadow stack, then we need to reconcile it with the rsp change we have just made
535-
rdsspq r9
540+
;; if have shadow stack, then we need to reconcile it with the rsp change we have just made. (r11 must contain target SSP)
541+
rdsspq r9 ;; NB, r9 == 0 prior to this
536542
test r9, r9
537-
jz NoSSP
538-
539-
;; Find the shadow stack pointer for the frame we are going to restore to.
540-
;; The SSP we search is pointing to the return address of the frame represented
541-
;; by the passed in context. So we search for the instruction pointer from
542-
;; the context and return one slot up from there.
543-
;; (Same logic as in GetSSPForFrameOnCurrentStack)
544-
xor r11, r11
545-
@@: inc r11
546-
cmp [r9 + r11 * 8 - 8], r10
547-
jne @b
548-
549-
incsspq r11
550-
NoSSP: jmp rax
543+
je No_Ssp_Update
544+
sub r11, r9
545+
shr r11, 3
546+
;; the incsspq instruction uses only the lowest 8 bits of the argument, so we need to loop in case the increment is larger than 255
547+
mov r9, 255
548+
Update_Loop:
549+
cmp r11, r9
550+
cmovb r9, r11
551+
incsspq r9
552+
sub r11, r9
553+
ja Update_Loop
554+
555+
556+
No_Ssp_Update: jmp rax
551557

552558

553559
NESTED_END RhpCallCatchFunclet, _TEXT

src/coreclr/nativeaot/Runtime/regdisplay.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,12 @@ struct REGDISPLAY
3030
#endif // TARGET_AMD64
3131

3232
uintptr_t SP;
33-
PCODE IP;
33+
PCODE IP;
34+
35+
#ifdef TARGET_AMD64
36+
uintptr_t SSP; // keep track of SSP for EH unwind
37+
// we do not adjust the original, so only need the value
38+
#endif
3439

3540
#if defined(TARGET_AMD64) && !defined(UNIX_AMD64_ABI)
3641
Fp128 Xmm[16-6]; // preserved xmm6..xmm15 regs for EH stackwalk
@@ -68,6 +73,7 @@ struct REGDISPLAY
6873
inline void SetEdiLocation(unsigned long *loc) { pRdi = (PTR_uintptr_t)loc; }
6974
inline void SetEbpLocation(unsigned long *loc) { pRbp = (PTR_uintptr_t)loc; }
7075
#endif
76+
7177
};
7278

7379
#ifdef TARGET_X86

src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,10 @@ bool CoffNativeCodeManager::UnwindStackFrame(MethodInfo * pMethodInfo,
790790
if (!(flags & USFF_GcUnwind))
791791
{
792792
memcpy(pRegisterSet->Xmm, &context.Xmm6, sizeof(pRegisterSet->Xmm));
793+
if (pRegisterSet->SSP)
794+
{
795+
pRegisterSet->SSP += 8;
796+
}
793797
}
794798
#elif defined(TARGET_ARM64)
795799
if (!(flags & USFF_GcUnwind))

src/tests/nativeaot/SmokeTests/UnitTests/Generics.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2356,10 +2356,30 @@ public void Blagh()
23562356
}
23572357
}
23582358

2359+
[MethodImpl(MethodImplOptions.NoInlining)]
2360+
private static void DeepAV(int x)
2361+
{
2362+
if (x > 0)
2363+
DeepAV(x - 1);
2364+
2365+
// Call an instance method on something we never allocated, but overrides a used virtual.
2366+
// This asserted the compiler when trying to build a template for Unused<__Canon>.
2367+
((Unused<object>)s_ref).Blagh();
2368+
}
2369+
23592370
public static void Run()
23602371
{
23612372
new Used().DoStuff();
23622373

2374+
for (int i = 0; i < 10; i++)
2375+
try
2376+
{
2377+
DeepAV(i);
2378+
}
2379+
catch (NullReferenceException)
2380+
{
2381+
}
2382+
23632383
try
23642384
{
23652385
// Call an instance method on something we never allocated, but overrides a used virtual.

0 commit comments

Comments
 (0)