Uh oh!
There was an error while loading. Please reload this page.
[ARM32] Eliminate red zone usage in runtime stubs - #129398
Conversation
On ARM32 Linux, the area below SP is not guaranteed to be preserved across signal delivery. Replace red zone reads/writes with explicit stack adjustments (push/pop) in: - NativeAOT interop thunks (ldr pc dispatch, no stack intermediate) - NativeAOT UniversalTransition (caller pushes args onto stack) - NativeAOT interface dispatch stubs (PROLOG_STACK_ALLOC instead of sub-SP stores) - CoreCLR VTableCallStub (pre-indexed str/post-indexed ldr) Guarded by FEATURE_AVOID_RED_ZONE, enabled for ARM32 non-Windows targets. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib |
Uh oh!
There was an error while loading. Please reload this page.
MichalPetryka
commented
Jun 15, 2026
Windows ARM32 is no longer supported. |
Windows ARM32 is no longer supported, so every ARM32 target is Linux. The red zone avoidance is always needed — remove the preprocessor guard and delete the old red zone code paths entirely. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
7cc9b73 to
59bc77cCompareUh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
The ldr pc dispatch needs only 12 bytes (mov r12 + ldr pc), no padding required. This increases thunks per page from 204 to 341 (67% more). Also shorten verbose comments per review feedback. Co-authored-by: Jan Kotas <jkotas@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- StubDispatch: use PROLOG_PUSH/EPILOG_POP {r1,r2} instead of manual
STACK_ALLOC + str/ldr
- UniversalTransition: replace interleaved ldr/push dance with a single
PROLOG_PUSH {r0-r3} then load caller args from known stack offsets
- Clean up stale red zone comments
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>59bc77c to
87288dfCompareUh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
jkotas
commented
Jun 15, 2026
/azp run runtime-nativeaot-outerloop |
|
Azure Pipelines successfully started running 1 pipeline(s). |
jkotas
commented
Jun 16, 2026
Segfaults in many linux arm32 NAOT tests Could you please take a look? |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
jkotas
commented
Jun 17, 2026
/azp run runtime-nativeaot-outerloop |
|
Azure Pipelines successfully started running 1 pipeline(s). |
Uh oh!
There was an error while loading. Please reload this page.
jkotas
commented
Jun 17, 2026
/azp run runtime-nativeaot-outerloop |
|
Azure Pipelines successfully started running 1 pipeline(s). |
jkotas
commented
Jun 18, 2026
All Arm32 test failures are known |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Co-authored-by: Michal Strehovský <MichalStrehovsky@users.noreply.github.com>
…USH/EPILOG_POP
- DispatchResolve.S: use PROLOG_PUSH/EPILOG_POP for {r3,r4,r5,r6,r8}, add
.save {r1,r2} at Hashtable entry, drop lr from push list
- UniversalTransition.S: rewrite prolog to preserve original frame layout
(push r0-r1, capture caller args, store r2-r3 into caller slots)
- StackFrameIterator.cpp: revert to original UniversalTransitionStackFrame
layout (no m_callerPushedArgs)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>jkotas
commented
Jun 18, 2026
/azp run runtime-nativeaot-outerloop |
|
Azure Pipelines successfully started running 1 pipeline(s). |
jkotas
commented
Jun 18, 2026
/azp run runtime-nativeaot-outerloop |
|
Azure Pipelines successfully started running 1 pipeline(s). |
Uh oh!
There was an error while loading. Please reload this page.
cshung
commented
Jun 19, 2026
Thanks @jkotas and @MichalStrehovsky for the thorough review and guidance! The prolog trick to preserve the original frame layout was particularly elegant — avoiding the TransitionBlock.cs changes made this much cleaner. Appreciated the push toward idiomatic ARM patterns (PROLOG_PUSH/EPILOG_POP, r8 as scratch) and the thunk size reduction as a bonus. Learned a lot from this one. |
jkotas
commented
Jun 19, 2026
@cshung Thank you for fixing this! It is likely source of some of the intermittent arm32 crashes. How did you find the problem? |
cshung
commented
Jun 19, 2026
I am trying to get it to run on low-end devices without virtual memory support. On those platforms, using red zone will fail pretty easily. |
On ARM32 Linux, the area below SP is not guaranteed to be preserved across signal delivery. The runtime previously used the red zone (writing below SP without adjusting it) in several stubs, which can cause silent corruption or crashes when a signal is delivered at the wrong moment. This PR eliminates all red zone usage in ARM32 runtime stubs by replacing sub-SP reads/writes with explicit stack adjustments (push/pop): --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Jan Kotas <jkotas@microsoft.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Michal Strehovský <MichalStrehovsky@users.noreply.github.com>
On ARM32 Linux, the area below SP is not guaranteed to be preserved across signal delivery. The runtime previously used the red zone (writing below SP without adjusting it) in several stubs, which can cause silent corruption or crashes when a signal is delivered at the wrong moment. This PR eliminates all red zone usage in ARM32 runtime stubs by replacing sub-SP reads/writes with explicit stack adjustments (push/pop): --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Jan Kotas <jkotas@microsoft.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Michal Strehovský <MichalStrehovsky@users.noreply.github.com>
On ARM32 Linux, the area below SP is not guaranteed to be preserved across signal delivery. The runtime previously used the red zone (writing below SP without adjusting it) in several stubs, which can cause silent corruption or crashes when a signal is delivered at the wrong moment.
This PR eliminates all red zone usage in ARM32 runtime stubs by replacing sub-SP reads/writes with explicit stack adjustments (push/pop):
ThunksMapping.cpp) — useldr pcdispatch directly from r12, no stack intermediate. This also shrinks THUNK_SIZE from 20 to 12 bytes.DispatchResolve.S,StubDispatch.S) —PROLOG_PUSH/EPILOG_POPinstead of red zone stores.