[ARM32] Eliminate red zone usage in runtime stubs - #129398

Merged
jkotas merged 16 commits into
dotnet:mainfrom
cshung:feature-avoid-red-zone
Jun 19, 2026
Merged

[ARM32] Eliminate red zone usage in runtime stubs#129398
jkotas merged 16 commits into
dotnet:mainfrom
cshung:feature-avoid-red-zone

Conversation

@cshung

@cshungcshung commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

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):

  • NativeAOT interop thunks (ThunksMapping.cpp) — use ldr pc dispatch directly from r12, no stack intermediate. This also shrinks THUNK_SIZE from 20 to 12 bytes.
  • NativeAOT UniversalTransition — caller pushes args onto stack before branching; prolog reads them from known stack offsets after saving argument registers.
  • NativeAOT interface dispatch (DispatchResolve.S, StubDispatch.S) — PROLOG_PUSH/EPILOG_POP instead of red zone stores.
  • CoreCLR VTableCallStub — pre-indexed str / post-indexed ldr (actual push/pop).

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>
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Jun 14, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

Comment threadsrc/coreclr/vm/CMakeLists.txt Outdated
@MichalPetryka

Copy link
Copy Markdown
Contributor

Windows ARM32 has a well-defined red zone guarantee

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>
Comment threadsrc/coreclr/nativeaot/Runtime/ThunksMapping.cpp Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/ThunksMapping.cpp Outdated
Comment threadsrc/coreclr/vm/arm/virtualcallstubcpu.hpp Outdated
Comment threadsrc/coreclr/vm/arm/virtualcallstubcpu.hpp Outdated
@cshung
cshungforce-pushed the feature-avoid-red-zone branch 2 times, most recently from 7cc9b73 to 59bc77cCompareJune 15, 2026 17:31
Comment threadsrc/coreclr/nativeaot/Runtime/arm/UniversalTransition.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/arm/UniversalTransition.S Outdated
cshungand others added 2 commits June 15, 2026 18:16
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>
@cshung
cshungforce-pushed the feature-avoid-red-zone branch from 59bc77c to 87288dfCompareJune 15, 2026 18:27
Comment threadsrc/coreclr/nativeaot/Runtime/arm/UniversalTransition.S
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotasjkotas left a comment

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.

Thanks!

@jkotas

Copy link
Copy Markdown
Member

Segfaults in many linux arm32 NAOT tests

pushd .
chmod +rwx Microsoft.Extensions.Configuration.FileExtensions.Tests ^&^& ./Microsoft.Extensions.Configuration.FileExtensions.Tests -notrait category=IgnoreForCI -notrait category=OuterLoop -notrait category=failing -xml testResults.xml popd
===========================================================================================================
/root/helix/work/workitem/e /root/helix/work/workitem/e
DOTNET_DbgEnableMiniDump is set and the createdump binary does not exist: ./createdump
./RunTests.sh: line 173: 18 Segmentation fault (core dumped) ./Microsoft.Extensions.Configuration.FileExtensions.Tests -notrait category=IgnoreForCI -notrait category=OuterLoop -notrait category=failing -xml testResults.xml $RSP_FILE
/root/helix/work/workitem/e
----- end Mon Jun 15 09:53:04 PM UTC 2026 ----- exit code 139 ----------------------------------------------------------

Could you please take a look?

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

Comment threadsrc/coreclr/nativeaot/Runtime/arm/DispatchResolve.S
@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotas

Copy link
Copy Markdown
Member

All Arm32 test failures are known

Comment threadsrc/coreclr/nativeaot/Runtime/arm/DispatchResolve.S
Comment threadsrc/coreclr/nativeaot/Runtime/EHHelpers.cpp
Comment threadsrc/coreclr/nativeaot/Runtime/StackFrameIterator.cpp Outdated
jkotasand others added 2 commits June 17, 2026 21:23
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

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotas
jkotas merged commit 083ad8b into dotnet:mainJun 19, 2026
137 checks passed
@cshung
cshung deleted the feature-avoid-red-zone branch June 19, 2026 03:40
@cshung

Copy link
Copy Markdown
ContributorAuthor

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

Copy link
Copy Markdown
Member

@cshung Thank you for fixing this! It is likely source of some of the intermittent arm32 crashes. How did you find the problem?

@cshung

Copy link
Copy Markdown
ContributorAuthor

@cshung Thank you for fixing this! It is likely source of some of the intermittent arm32 crashes. How did you find the problem?

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.

@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview6 milestone Jun 22, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
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>
ManickaP pushed a commit to ManickaP/runtime that referenced this pull request Jul 22, 2026
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>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 23, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

arch-arm32area-NativeAOT-coreclrcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@cshung@MichalPetryka@jkotas@MichalStrehovsky
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

[ARM32] Eliminate red zone usage in runtime stubs - #129398

Merged
jkotas merged 16 commits into
dotnet:mainfrom
cshung:feature-avoid-red-zone
Jun 19, 2026
Merged

[ARM32] Eliminate red zone usage in runtime stubs#129398
jkotas merged 16 commits into
dotnet:mainfrom
cshung:feature-avoid-red-zone

Conversation

@cshung

@cshungcshung commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

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):

  • NativeAOT interop thunks (ThunksMapping.cpp) — use ldr pc dispatch directly from r12, no stack intermediate. This also shrinks THUNK_SIZE from 20 to 12 bytes.
  • NativeAOT UniversalTransition — caller pushes args onto stack before branching; prolog reads them from known stack offsets after saving argument registers.
  • NativeAOT interface dispatch (DispatchResolve.S, StubDispatch.S) — PROLOG_PUSH/EPILOG_POP instead of red zone stores.
  • CoreCLR VTableCallStub — pre-indexed str / post-indexed ldr (actual push/pop).

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>
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Jun 14, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

Comment threadsrc/coreclr/vm/CMakeLists.txt Outdated
@MichalPetryka

Copy link
Copy Markdown
Contributor

Windows ARM32 has a well-defined red zone guarantee

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>
Comment threadsrc/coreclr/nativeaot/Runtime/ThunksMapping.cpp Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/ThunksMapping.cpp Outdated
Comment threadsrc/coreclr/vm/arm/virtualcallstubcpu.hpp Outdated
Comment threadsrc/coreclr/vm/arm/virtualcallstubcpu.hpp Outdated
@cshung
cshungforce-pushed the feature-avoid-red-zone branch 2 times, most recently from 7cc9b73 to 59bc77cCompareJune 15, 2026 17:31
Comment threadsrc/coreclr/nativeaot/Runtime/arm/UniversalTransition.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/arm/UniversalTransition.S Outdated
cshungand others added 2 commits June 15, 2026 18:16
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>
@cshung
cshungforce-pushed the feature-avoid-red-zone branch from 59bc77c to 87288dfCompareJune 15, 2026 18:27
Comment threadsrc/coreclr/nativeaot/Runtime/arm/UniversalTransition.S
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotasjkotas left a comment

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.

Thanks!

@jkotas

Copy link
Copy Markdown
Member

Segfaults in many linux arm32 NAOT tests

pushd .
chmod +rwx Microsoft.Extensions.Configuration.FileExtensions.Tests ^&^& ./Microsoft.Extensions.Configuration.FileExtensions.Tests -notrait category=IgnoreForCI -notrait category=OuterLoop -notrait category=failing -xml testResults.xml popd
===========================================================================================================
/root/helix/work/workitem/e /root/helix/work/workitem/e
DOTNET_DbgEnableMiniDump is set and the createdump binary does not exist: ./createdump
./RunTests.sh: line 173: 18 Segmentation fault (core dumped) ./Microsoft.Extensions.Configuration.FileExtensions.Tests -notrait category=IgnoreForCI -notrait category=OuterLoop -notrait category=failing -xml testResults.xml $RSP_FILE
/root/helix/work/workitem/e
----- end Mon Jun 15 09:53:04 PM UTC 2026 ----- exit code 139 ----------------------------------------------------------

Could you please take a look?

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

Comment threadsrc/coreclr/nativeaot/Runtime/arm/DispatchResolve.S
@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotas

Copy link
Copy Markdown
Member

All Arm32 test failures are known

Comment threadsrc/coreclr/nativeaot/Runtime/arm/DispatchResolve.S
Comment threadsrc/coreclr/nativeaot/Runtime/EHHelpers.cpp
Comment threadsrc/coreclr/nativeaot/Runtime/StackFrameIterator.cpp Outdated
jkotasand others added 2 commits June 17, 2026 21:23
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

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotas
jkotas merged commit 083ad8b into dotnet:mainJun 19, 2026
137 checks passed
@cshung
cshung deleted the feature-avoid-red-zone branch June 19, 2026 03:40
@cshung

Copy link
Copy Markdown
ContributorAuthor

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

Copy link
Copy Markdown
Member

@cshung Thank you for fixing this! It is likely source of some of the intermittent arm32 crashes. How did you find the problem?

@cshung

Copy link
Copy Markdown
ContributorAuthor

@cshung Thank you for fixing this! It is likely source of some of the intermittent arm32 crashes. How did you find the problem?

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.

@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview6 milestone Jun 22, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
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>
ManickaP pushed a commit to ManickaP/runtime that referenced this pull request Jul 22, 2026
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>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 23, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

arch-arm32area-NativeAOT-coreclrcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@cshung@MichalPetryka@jkotas@MichalStrehovsky
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[ARM32] Eliminate red zone usage in runtime stubs - #129398

Merged
jkotas merged 16 commits into
dotnet:mainfrom
cshung:feature-avoid-red-zone
Jun 19, 2026
Merged

[ARM32] Eliminate red zone usage in runtime stubs#129398
jkotas merged 16 commits into
dotnet:mainfrom
cshung:feature-avoid-red-zone

Conversation

@cshung

@cshungcshung commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

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):

  • NativeAOT interop thunks (ThunksMapping.cpp) — use ldr pc dispatch directly from r12, no stack intermediate. This also shrinks THUNK_SIZE from 20 to 12 bytes.
  • NativeAOT UniversalTransition — caller pushes args onto stack before branching; prolog reads them from known stack offsets after saving argument registers.
  • NativeAOT interface dispatch (DispatchResolve.S, StubDispatch.S) — PROLOG_PUSH/EPILOG_POP instead of red zone stores.
  • CoreCLR VTableCallStub — pre-indexed str / post-indexed ldr (actual push/pop).

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>
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Jun 14, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

Comment threadsrc/coreclr/vm/CMakeLists.txt Outdated
@MichalPetryka

Copy link
Copy Markdown
Contributor

Windows ARM32 has a well-defined red zone guarantee

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>
Comment threadsrc/coreclr/nativeaot/Runtime/ThunksMapping.cpp Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/ThunksMapping.cpp Outdated
Comment threadsrc/coreclr/vm/arm/virtualcallstubcpu.hpp Outdated
Comment threadsrc/coreclr/vm/arm/virtualcallstubcpu.hpp Outdated
@cshung
cshungforce-pushed the feature-avoid-red-zone branch 2 times, most recently from 7cc9b73 to 59bc77cCompareJune 15, 2026 17:31
Comment threadsrc/coreclr/nativeaot/Runtime/arm/UniversalTransition.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/arm/UniversalTransition.S Outdated
cshungand others added 2 commits June 15, 2026 18:16
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>
@cshung
cshungforce-pushed the feature-avoid-red-zone branch from 59bc77c to 87288dfCompareJune 15, 2026 18:27
Comment threadsrc/coreclr/nativeaot/Runtime/arm/UniversalTransition.S
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotasjkotas left a comment

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.

Thanks!

@jkotas

Copy link
Copy Markdown
Member

Segfaults in many linux arm32 NAOT tests

pushd .
chmod +rwx Microsoft.Extensions.Configuration.FileExtensions.Tests ^&^& ./Microsoft.Extensions.Configuration.FileExtensions.Tests -notrait category=IgnoreForCI -notrait category=OuterLoop -notrait category=failing -xml testResults.xml popd
===========================================================================================================
/root/helix/work/workitem/e /root/helix/work/workitem/e
DOTNET_DbgEnableMiniDump is set and the createdump binary does not exist: ./createdump
./RunTests.sh: line 173: 18 Segmentation fault (core dumped) ./Microsoft.Extensions.Configuration.FileExtensions.Tests -notrait category=IgnoreForCI -notrait category=OuterLoop -notrait category=failing -xml testResults.xml $RSP_FILE
/root/helix/work/workitem/e
----- end Mon Jun 15 09:53:04 PM UTC 2026 ----- exit code 139 ----------------------------------------------------------

Could you please take a look?

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

Comment threadsrc/coreclr/nativeaot/Runtime/arm/DispatchResolve.S
@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotas

Copy link
Copy Markdown
Member

All Arm32 test failures are known

Comment threadsrc/coreclr/nativeaot/Runtime/arm/DispatchResolve.S
Comment threadsrc/coreclr/nativeaot/Runtime/EHHelpers.cpp
Comment threadsrc/coreclr/nativeaot/Runtime/StackFrameIterator.cpp Outdated
jkotasand others added 2 commits June 17, 2026 21:23
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

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotas
jkotas merged commit 083ad8b into dotnet:mainJun 19, 2026
137 checks passed
@cshung
cshung deleted the feature-avoid-red-zone branch June 19, 2026 03:40
@cshung

Copy link
Copy Markdown
ContributorAuthor

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

Copy link
Copy Markdown
Member

@cshung Thank you for fixing this! It is likely source of some of the intermittent arm32 crashes. How did you find the problem?

@cshung

Copy link
Copy Markdown
ContributorAuthor

@cshung Thank you for fixing this! It is likely source of some of the intermittent arm32 crashes. How did you find the problem?

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.

@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview6 milestone Jun 22, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
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>
ManickaP pushed a commit to ManickaP/runtime that referenced this pull request Jul 22, 2026
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>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 23, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

arch-arm32area-NativeAOT-coreclrcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@cshung@MichalPetryka@jkotas@MichalStrehovsky
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[ARM32] Eliminate red zone usage in runtime stubs - #129398

Merged
jkotas merged 16 commits into
dotnet:mainfrom
cshung:feature-avoid-red-zone
Jun 19, 2026
Merged

[ARM32] Eliminate red zone usage in runtime stubs#129398
jkotas merged 16 commits into
dotnet:mainfrom
cshung:feature-avoid-red-zone

Conversation

@cshung

@cshungcshung commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

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):

  • NativeAOT interop thunks (ThunksMapping.cpp) — use ldr pc dispatch directly from r12, no stack intermediate. This also shrinks THUNK_SIZE from 20 to 12 bytes.
  • NativeAOT UniversalTransition — caller pushes args onto stack before branching; prolog reads them from known stack offsets after saving argument registers.
  • NativeAOT interface dispatch (DispatchResolve.S, StubDispatch.S) — PROLOG_PUSH/EPILOG_POP instead of red zone stores.
  • CoreCLR VTableCallStub — pre-indexed str / post-indexed ldr (actual push/pop).

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>
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Jun 14, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

Comment threadsrc/coreclr/vm/CMakeLists.txt Outdated
@MichalPetryka

Copy link
Copy Markdown
Contributor

Windows ARM32 has a well-defined red zone guarantee

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>
Comment threadsrc/coreclr/nativeaot/Runtime/ThunksMapping.cpp Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/ThunksMapping.cpp Outdated
Comment threadsrc/coreclr/vm/arm/virtualcallstubcpu.hpp Outdated
Comment threadsrc/coreclr/vm/arm/virtualcallstubcpu.hpp Outdated
@cshung
cshungforce-pushed the feature-avoid-red-zone branch 2 times, most recently from 7cc9b73 to 59bc77cCompareJune 15, 2026 17:31
Comment threadsrc/coreclr/nativeaot/Runtime/arm/UniversalTransition.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/arm/UniversalTransition.S Outdated
cshungand others added 2 commits June 15, 2026 18:16
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>
@cshung
cshungforce-pushed the feature-avoid-red-zone branch from 59bc77c to 87288dfCompareJune 15, 2026 18:27
Comment threadsrc/coreclr/nativeaot/Runtime/arm/UniversalTransition.S
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotasjkotas left a comment

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.

Thanks!

@jkotas

Copy link
Copy Markdown
Member

Segfaults in many linux arm32 NAOT tests

pushd .
chmod +rwx Microsoft.Extensions.Configuration.FileExtensions.Tests ^&^& ./Microsoft.Extensions.Configuration.FileExtensions.Tests -notrait category=IgnoreForCI -notrait category=OuterLoop -notrait category=failing -xml testResults.xml popd
===========================================================================================================
/root/helix/work/workitem/e /root/helix/work/workitem/e
DOTNET_DbgEnableMiniDump is set and the createdump binary does not exist: ./createdump
./RunTests.sh: line 173: 18 Segmentation fault (core dumped) ./Microsoft.Extensions.Configuration.FileExtensions.Tests -notrait category=IgnoreForCI -notrait category=OuterLoop -notrait category=failing -xml testResults.xml $RSP_FILE
/root/helix/work/workitem/e
----- end Mon Jun 15 09:53:04 PM UTC 2026 ----- exit code 139 ----------------------------------------------------------

Could you please take a look?

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

Comment threadsrc/coreclr/nativeaot/Runtime/arm/DispatchResolve.S
@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotas

Copy link
Copy Markdown
Member

All Arm32 test failures are known

Comment threadsrc/coreclr/nativeaot/Runtime/arm/DispatchResolve.S
Comment threadsrc/coreclr/nativeaot/Runtime/EHHelpers.cpp
Comment threadsrc/coreclr/nativeaot/Runtime/StackFrameIterator.cpp Outdated
jkotasand others added 2 commits June 17, 2026 21:23
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

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotas
jkotas merged commit 083ad8b into dotnet:mainJun 19, 2026
137 checks passed
@cshung
cshung deleted the feature-avoid-red-zone branch June 19, 2026 03:40
@cshung

Copy link
Copy Markdown
ContributorAuthor

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

Copy link
Copy Markdown
Member

@cshung Thank you for fixing this! It is likely source of some of the intermittent arm32 crashes. How did you find the problem?

@cshung

Copy link
Copy Markdown
ContributorAuthor

@cshung Thank you for fixing this! It is likely source of some of the intermittent arm32 crashes. How did you find the problem?

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.

@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview6 milestone Jun 22, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
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>
ManickaP pushed a commit to ManickaP/runtime that referenced this pull request Jul 22, 2026
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>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 23, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

arch-arm32area-NativeAOT-coreclrcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@cshung@MichalPetryka@jkotas@MichalStrehovsky
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

[ARM32] Eliminate red zone usage in runtime stubs - #129398

Merged
jkotas merged 16 commits into
dotnet:mainfrom
cshung:feature-avoid-red-zone
Jun 19, 2026
Merged

[ARM32] Eliminate red zone usage in runtime stubs#129398
jkotas merged 16 commits into
dotnet:mainfrom
cshung:feature-avoid-red-zone

Conversation

@cshung

@cshungcshung commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

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):

  • NativeAOT interop thunks (ThunksMapping.cpp) — use ldr pc dispatch directly from r12, no stack intermediate. This also shrinks THUNK_SIZE from 20 to 12 bytes.
  • NativeAOT UniversalTransition — caller pushes args onto stack before branching; prolog reads them from known stack offsets after saving argument registers.
  • NativeAOT interface dispatch (DispatchResolve.S, StubDispatch.S) — PROLOG_PUSH/EPILOG_POP instead of red zone stores.
  • CoreCLR VTableCallStub — pre-indexed str / post-indexed ldr (actual push/pop).

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>
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Jun 14, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

Comment threadsrc/coreclr/vm/CMakeLists.txt Outdated
@MichalPetryka

Copy link
Copy Markdown
Contributor

Windows ARM32 has a well-defined red zone guarantee

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>
Comment threadsrc/coreclr/nativeaot/Runtime/ThunksMapping.cpp Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/ThunksMapping.cpp Outdated
Comment threadsrc/coreclr/vm/arm/virtualcallstubcpu.hpp Outdated
Comment threadsrc/coreclr/vm/arm/virtualcallstubcpu.hpp Outdated
@cshung
cshungforce-pushed the feature-avoid-red-zone branch 2 times, most recently from 7cc9b73 to 59bc77cCompareJune 15, 2026 17:31
Comment threadsrc/coreclr/nativeaot/Runtime/arm/UniversalTransition.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/arm/UniversalTransition.S Outdated
cshungand others added 2 commits June 15, 2026 18:16
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>
@cshung
cshungforce-pushed the feature-avoid-red-zone branch from 59bc77c to 87288dfCompareJune 15, 2026 18:27
Comment threadsrc/coreclr/nativeaot/Runtime/arm/UniversalTransition.S
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotasjkotas left a comment

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.

Thanks!

@jkotas

Copy link
Copy Markdown
Member

Segfaults in many linux arm32 NAOT tests

pushd .
chmod +rwx Microsoft.Extensions.Configuration.FileExtensions.Tests ^&^& ./Microsoft.Extensions.Configuration.FileExtensions.Tests -notrait category=IgnoreForCI -notrait category=OuterLoop -notrait category=failing -xml testResults.xml popd
===========================================================================================================
/root/helix/work/workitem/e /root/helix/work/workitem/e
DOTNET_DbgEnableMiniDump is set and the createdump binary does not exist: ./createdump
./RunTests.sh: line 173: 18 Segmentation fault (core dumped) ./Microsoft.Extensions.Configuration.FileExtensions.Tests -notrait category=IgnoreForCI -notrait category=OuterLoop -notrait category=failing -xml testResults.xml $RSP_FILE
/root/helix/work/workitem/e
----- end Mon Jun 15 09:53:04 PM UTC 2026 ----- exit code 139 ----------------------------------------------------------

Could you please take a look?

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

Comment threadsrc/coreclr/nativeaot/Runtime/arm/DispatchResolve.S
@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotas

Copy link
Copy Markdown
Member

All Arm32 test failures are known

Comment threadsrc/coreclr/nativeaot/Runtime/arm/DispatchResolve.S
Comment threadsrc/coreclr/nativeaot/Runtime/EHHelpers.cpp
Comment threadsrc/coreclr/nativeaot/Runtime/StackFrameIterator.cpp Outdated
jkotasand others added 2 commits June 17, 2026 21:23
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

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotas
jkotas merged commit 083ad8b into dotnet:mainJun 19, 2026
137 checks passed
@cshung
cshung deleted the feature-avoid-red-zone branch June 19, 2026 03:40
@cshung

Copy link
Copy Markdown
ContributorAuthor

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

Copy link
Copy Markdown
Member

@cshung Thank you for fixing this! It is likely source of some of the intermittent arm32 crashes. How did you find the problem?

@cshung

Copy link
Copy Markdown
ContributorAuthor

@cshung Thank you for fixing this! It is likely source of some of the intermittent arm32 crashes. How did you find the problem?

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.

@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview6 milestone Jun 22, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
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>
ManickaP pushed a commit to ManickaP/runtime that referenced this pull request Jul 22, 2026
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>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 23, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

arch-arm32area-NativeAOT-coreclrcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@cshung@MichalPetryka@jkotas@MichalStrehovsky
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[ARM32] Eliminate red zone usage in runtime stubs - #129398

Merged
jkotas merged 16 commits into
dotnet:mainfrom
cshung:feature-avoid-red-zone
Jun 19, 2026
Merged

[ARM32] Eliminate red zone usage in runtime stubs#129398
jkotas merged 16 commits into
dotnet:mainfrom
cshung:feature-avoid-red-zone

Conversation

@cshung

@cshungcshung commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

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):

  • NativeAOT interop thunks (ThunksMapping.cpp) — use ldr pc dispatch directly from r12, no stack intermediate. This also shrinks THUNK_SIZE from 20 to 12 bytes.
  • NativeAOT UniversalTransition — caller pushes args onto stack before branching; prolog reads them from known stack offsets after saving argument registers.
  • NativeAOT interface dispatch (DispatchResolve.S, StubDispatch.S) — PROLOG_PUSH/EPILOG_POP instead of red zone stores.
  • CoreCLR VTableCallStub — pre-indexed str / post-indexed ldr (actual push/pop).

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>
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Jun 14, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

Comment threadsrc/coreclr/vm/CMakeLists.txt Outdated
@MichalPetryka

Copy link
Copy Markdown
Contributor

Windows ARM32 has a well-defined red zone guarantee

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>
Comment threadsrc/coreclr/nativeaot/Runtime/ThunksMapping.cpp Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/ThunksMapping.cpp Outdated
Comment threadsrc/coreclr/vm/arm/virtualcallstubcpu.hpp Outdated
Comment threadsrc/coreclr/vm/arm/virtualcallstubcpu.hpp Outdated
@cshung
cshungforce-pushed the feature-avoid-red-zone branch 2 times, most recently from 7cc9b73 to 59bc77cCompareJune 15, 2026 17:31
Comment threadsrc/coreclr/nativeaot/Runtime/arm/UniversalTransition.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/arm/UniversalTransition.S Outdated
cshungand others added 2 commits June 15, 2026 18:16
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>
@cshung
cshungforce-pushed the feature-avoid-red-zone branch from 59bc77c to 87288dfCompareJune 15, 2026 18:27
Comment threadsrc/coreclr/nativeaot/Runtime/arm/UniversalTransition.S
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotasjkotas left a comment

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.

Thanks!

@jkotas

Copy link
Copy Markdown
Member

Segfaults in many linux arm32 NAOT tests

pushd .
chmod +rwx Microsoft.Extensions.Configuration.FileExtensions.Tests ^&^& ./Microsoft.Extensions.Configuration.FileExtensions.Tests -notrait category=IgnoreForCI -notrait category=OuterLoop -notrait category=failing -xml testResults.xml popd
===========================================================================================================
/root/helix/work/workitem/e /root/helix/work/workitem/e
DOTNET_DbgEnableMiniDump is set and the createdump binary does not exist: ./createdump
./RunTests.sh: line 173: 18 Segmentation fault (core dumped) ./Microsoft.Extensions.Configuration.FileExtensions.Tests -notrait category=IgnoreForCI -notrait category=OuterLoop -notrait category=failing -xml testResults.xml $RSP_FILE
/root/helix/work/workitem/e
----- end Mon Jun 15 09:53:04 PM UTC 2026 ----- exit code 139 ----------------------------------------------------------

Could you please take a look?

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

Comment threadsrc/coreclr/nativeaot/Runtime/arm/DispatchResolve.S
@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotas

Copy link
Copy Markdown
Member

All Arm32 test failures are known

Comment threadsrc/coreclr/nativeaot/Runtime/arm/DispatchResolve.S
Comment threadsrc/coreclr/nativeaot/Runtime/EHHelpers.cpp
Comment threadsrc/coreclr/nativeaot/Runtime/StackFrameIterator.cpp Outdated
jkotasand others added 2 commits June 17, 2026 21:23
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

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotas
jkotas merged commit 083ad8b into dotnet:mainJun 19, 2026
137 checks passed
@cshung
cshung deleted the feature-avoid-red-zone branch June 19, 2026 03:40
@cshung

Copy link
Copy Markdown
ContributorAuthor

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

Copy link
Copy Markdown
Member

@cshung Thank you for fixing this! It is likely source of some of the intermittent arm32 crashes. How did you find the problem?

@cshung

Copy link
Copy Markdown
ContributorAuthor

@cshung Thank you for fixing this! It is likely source of some of the intermittent arm32 crashes. How did you find the problem?

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.

@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview6 milestone Jun 22, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
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>
ManickaP pushed a commit to ManickaP/runtime that referenced this pull request Jul 22, 2026
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>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 23, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

arch-arm32area-NativeAOT-coreclrcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@cshung@MichalPetryka@jkotas@MichalStrehovsky
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[ARM32] Eliminate red zone usage in runtime stubs - #129398

Merged
jkotas merged 16 commits into
dotnet:mainfrom
cshung:feature-avoid-red-zone
Jun 19, 2026
Merged

[ARM32] Eliminate red zone usage in runtime stubs#129398
jkotas merged 16 commits into
dotnet:mainfrom
cshung:feature-avoid-red-zone

Conversation

@cshung

@cshungcshung commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

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):

  • NativeAOT interop thunks (ThunksMapping.cpp) — use ldr pc dispatch directly from r12, no stack intermediate. This also shrinks THUNK_SIZE from 20 to 12 bytes.
  • NativeAOT UniversalTransition — caller pushes args onto stack before branching; prolog reads them from known stack offsets after saving argument registers.
  • NativeAOT interface dispatch (DispatchResolve.S, StubDispatch.S) — PROLOG_PUSH/EPILOG_POP instead of red zone stores.
  • CoreCLR VTableCallStub — pre-indexed str / post-indexed ldr (actual push/pop).

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>
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Jun 14, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

Comment threadsrc/coreclr/vm/CMakeLists.txt Outdated
@MichalPetryka

Copy link
Copy Markdown
Contributor

Windows ARM32 has a well-defined red zone guarantee

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>
Comment threadsrc/coreclr/nativeaot/Runtime/ThunksMapping.cpp Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/ThunksMapping.cpp Outdated
Comment threadsrc/coreclr/vm/arm/virtualcallstubcpu.hpp Outdated
Comment threadsrc/coreclr/vm/arm/virtualcallstubcpu.hpp Outdated
@cshung
cshungforce-pushed the feature-avoid-red-zone branch 2 times, most recently from 7cc9b73 to 59bc77cCompareJune 15, 2026 17:31
Comment threadsrc/coreclr/nativeaot/Runtime/arm/UniversalTransition.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/arm/UniversalTransition.S Outdated
cshungand others added 2 commits June 15, 2026 18:16
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>
@cshung
cshungforce-pushed the feature-avoid-red-zone branch from 59bc77c to 87288dfCompareJune 15, 2026 18:27
Comment threadsrc/coreclr/nativeaot/Runtime/arm/UniversalTransition.S
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotasjkotas left a comment

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.

Thanks!

@jkotas

Copy link
Copy Markdown
Member

Segfaults in many linux arm32 NAOT tests

pushd .
chmod +rwx Microsoft.Extensions.Configuration.FileExtensions.Tests ^&^& ./Microsoft.Extensions.Configuration.FileExtensions.Tests -notrait category=IgnoreForCI -notrait category=OuterLoop -notrait category=failing -xml testResults.xml popd
===========================================================================================================
/root/helix/work/workitem/e /root/helix/work/workitem/e
DOTNET_DbgEnableMiniDump is set and the createdump binary does not exist: ./createdump
./RunTests.sh: line 173: 18 Segmentation fault (core dumped) ./Microsoft.Extensions.Configuration.FileExtensions.Tests -notrait category=IgnoreForCI -notrait category=OuterLoop -notrait category=failing -xml testResults.xml $RSP_FILE
/root/helix/work/workitem/e
----- end Mon Jun 15 09:53:04 PM UTC 2026 ----- exit code 139 ----------------------------------------------------------

Could you please take a look?

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

Comment threadsrc/coreclr/nativeaot/Runtime/arm/DispatchResolve.S
@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotas

Copy link
Copy Markdown
Member

All Arm32 test failures are known

Comment threadsrc/coreclr/nativeaot/Runtime/arm/DispatchResolve.S
Comment threadsrc/coreclr/nativeaot/Runtime/EHHelpers.cpp
Comment threadsrc/coreclr/nativeaot/Runtime/StackFrameIterator.cpp Outdated
jkotasand others added 2 commits June 17, 2026 21:23
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

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotas
jkotas merged commit 083ad8b into dotnet:mainJun 19, 2026
137 checks passed
@cshung
cshung deleted the feature-avoid-red-zone branch June 19, 2026 03:40
@cshung

Copy link
Copy Markdown
ContributorAuthor

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

Copy link
Copy Markdown
Member

@cshung Thank you for fixing this! It is likely source of some of the intermittent arm32 crashes. How did you find the problem?

@cshung

Copy link
Copy Markdown
ContributorAuthor

@cshung Thank you for fixing this! It is likely source of some of the intermittent arm32 crashes. How did you find the problem?

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.

@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview6 milestone Jun 22, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
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>
ManickaP pushed a commit to ManickaP/runtime that referenced this pull request Jul 22, 2026
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>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 23, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

arch-arm32area-NativeAOT-coreclrcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@cshung@MichalPetryka@jkotas@MichalStrehovsky
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

[ARM32] Eliminate red zone usage in runtime stubs - #129398

Merged
jkotas merged 16 commits into
dotnet:mainfrom
cshung:feature-avoid-red-zone
Jun 19, 2026
Merged

[ARM32] Eliminate red zone usage in runtime stubs#129398
jkotas merged 16 commits into
dotnet:mainfrom
cshung:feature-avoid-red-zone

Conversation

@cshung

@cshungcshung commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

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):

  • NativeAOT interop thunks (ThunksMapping.cpp) — use ldr pc dispatch directly from r12, no stack intermediate. This also shrinks THUNK_SIZE from 20 to 12 bytes.
  • NativeAOT UniversalTransition — caller pushes args onto stack before branching; prolog reads them from known stack offsets after saving argument registers.
  • NativeAOT interface dispatch (DispatchResolve.S, StubDispatch.S) — PROLOG_PUSH/EPILOG_POP instead of red zone stores.
  • CoreCLR VTableCallStub — pre-indexed str / post-indexed ldr (actual push/pop).

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>
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Jun 14, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

Comment threadsrc/coreclr/vm/CMakeLists.txt Outdated
@MichalPetryka

Copy link
Copy Markdown
Contributor

Windows ARM32 has a well-defined red zone guarantee

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>
Comment threadsrc/coreclr/nativeaot/Runtime/ThunksMapping.cpp Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/ThunksMapping.cpp Outdated
Comment threadsrc/coreclr/vm/arm/virtualcallstubcpu.hpp Outdated
Comment threadsrc/coreclr/vm/arm/virtualcallstubcpu.hpp Outdated
@cshung
cshungforce-pushed the feature-avoid-red-zone branch 2 times, most recently from 7cc9b73 to 59bc77cCompareJune 15, 2026 17:31
Comment threadsrc/coreclr/nativeaot/Runtime/arm/UniversalTransition.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/arm/UniversalTransition.S Outdated
cshungand others added 2 commits June 15, 2026 18:16
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>
@cshung
cshungforce-pushed the feature-avoid-red-zone branch from 59bc77c to 87288dfCompareJune 15, 2026 18:27
Comment threadsrc/coreclr/nativeaot/Runtime/arm/UniversalTransition.S
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S Outdated
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S
Comment threadsrc/coreclr/runtime/arm/StubDispatch.S
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotasjkotas left a comment

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.

Thanks!

@jkotas

Copy link
Copy Markdown
Member

Segfaults in many linux arm32 NAOT tests

pushd .
chmod +rwx Microsoft.Extensions.Configuration.FileExtensions.Tests ^&^& ./Microsoft.Extensions.Configuration.FileExtensions.Tests -notrait category=IgnoreForCI -notrait category=OuterLoop -notrait category=failing -xml testResults.xml popd
===========================================================================================================
/root/helix/work/workitem/e /root/helix/work/workitem/e
DOTNET_DbgEnableMiniDump is set and the createdump binary does not exist: ./createdump
./RunTests.sh: line 173: 18 Segmentation fault (core dumped) ./Microsoft.Extensions.Configuration.FileExtensions.Tests -notrait category=IgnoreForCI -notrait category=OuterLoop -notrait category=failing -xml testResults.xml $RSP_FILE
/root/helix/work/workitem/e
----- end Mon Jun 15 09:53:04 PM UTC 2026 ----- exit code 139 ----------------------------------------------------------

Could you please take a look?

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

Comment threadsrc/coreclr/nativeaot/Runtime/arm/DispatchResolve.S
@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotas

Copy link
Copy Markdown
Member

All Arm32 test failures are known

Comment threadsrc/coreclr/nativeaot/Runtime/arm/DispatchResolve.S
Comment threadsrc/coreclr/nativeaot/Runtime/EHHelpers.cpp
Comment threadsrc/coreclr/nativeaot/Runtime/StackFrameIterator.cpp Outdated
jkotasand others added 2 commits June 17, 2026 21:23
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

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotas
jkotas merged commit 083ad8b into dotnet:mainJun 19, 2026
137 checks passed
@cshung
cshung deleted the feature-avoid-red-zone branch June 19, 2026 03:40
@cshung

Copy link
Copy Markdown
ContributorAuthor

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

Copy link
Copy Markdown
Member

@cshung Thank you for fixing this! It is likely source of some of the intermittent arm32 crashes. How did you find the problem?

@cshung

Copy link
Copy Markdown
ContributorAuthor

@cshung Thank you for fixing this! It is likely source of some of the intermittent arm32 crashes. How did you find the problem?

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.

@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview6 milestone Jun 22, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
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>
ManickaP pushed a commit to ManickaP/runtime that referenced this pull request Jul 22, 2026
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>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 23, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

arch-arm32area-NativeAOT-coreclrcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@cshung@MichalPetryka@jkotas@MichalStrehovsky