Skip to content

Fix Arm64 disassembler for .NET 10 DMB-prefixed stubs - #3208

Merged
timcassell merged 1 commit into
dotnet:masterfrom
timcassell:fix-arm64-net10-dmb-stub
Jul 26, 2026
Merged

Fix Arm64 disassembler for .NET 10 DMB-prefixed stubs#3208
timcassell merged 1 commit into
dotnet:masterfrom
timcassell:fix-arm64-net10-dmb-stub

Conversation

@timcassell

@timcassell timcassell commented Jul 26, 2026

Copy link
Copy Markdown
Collaborator

Fixes #3207.

.NET 10 prefixes AArch64 precode/stub shapes (at least FixupPrecodeCode_Fixup) with a leading DMB ISH for concurrent stub-patching safety. The existing TryResolvePrecode / TryFollowJumpTrampoline in Arm64Disassembler.cs read a fixed 12-byte window and match a 3-instruction pattern, so the barrier caused every prefixed stub to miss.

Symptom

After landing on a benchmark-method call site under CsProjCoreToolchain.NetCoreApp10_0 on ARM64, the disassembler stopped chasing instead of following into the target — DisassemblyDiagnoser only recovered the wrapper method. This surfaces as failures in tests like CanDisassembleInlinableBenchmarks once the toolchain is bumped to .NET 10.

Fix

Add TryReadStubHead: read up to 16 bytes, detect DMB ISH (0xD50339BF) at instr0, skip 4 bytes and return an effective parseBase so LDR-literal offset math stays correct. Use it from both stub-parsing entry points; slot addresses now use parseBase instead of address.

TryFollowJumpTrampoline's short B imm26 path is intentionally left as a 4-byte read since the barrier is only emitted for precode/stub shapes, not JIT-emitted jump trampolines.

Verification

Verified on GitHub-hosted ubuntu-24.04-arm runner (.NET SDK 10.0.302 / runtime 10.0.10): the full DisassemblyDiagnoserTests suite (CanDisassembleAllMethodCalls, CanDisassembleAllMethodCallsUsingFilters, CanDisassembleGenericTypes, CanDisassembleInlinableBenchmarks) passes end-to-end under both InProcessEmit and CsProjCore .NET 10 toolchains. Run: https://github.com/timcassell/BenchmarkDotNet/actions/runs/30183840865

.NET 10 prefixes AArch64 precode/stub shapes (at least FixupPrecodeCode_Fixup) with a leading DMB ISH for concurrent stub-patching safety. The existing TryResolvePrecode / TryFollowJumpTrampoline read a fixed 12-byte window and match a 3-instruction pattern, so the barrier caused every prefixed stub to miss.

Symptom: after landing on a benchmark-method call site under CsProjCoreToolchain.NetCoreApp10_0 on ARM64, the disassembler stopped instead of chasing into the target, so DisassemblyDiagnoser only recovered the wrapper method (surfacing as failures in tests like CanDisassembleInlinableBenchmarks once the toolchain is bumped to .NET 10).

Add TryReadStubHead: read up to 16 bytes, detect DMB ISH (0xD50339BF) at instr0, skip 4 bytes and return an effective parseBase so LDR-literal offset math stays correct. Use it from both stub-parsing entry points; slot addresses now use parseBase instead of address.

TryFollowJumpTrampoline's short 'B imm26' path is intentionally left as a 4-byte read since the barrier is only emitted for precode/stub shapes, not JIT-emitted jump trampolines.

Verified on Ubuntu 24.04 ARM64 GitHub-hosted runner (.NET SDK 10.0.302 / runtime 10.0.10): the full DisassemblyDiagnoserTests suite passes end-to-end under both InProcessEmit and CsProjCore .NET 10 toolchains.
@timcassell
timcassell merged commit fb2bd55 into dotnet:master Jul 26, 2026
11 checks passed
@timcassell timcassell added this to the v0.16.0 milestone Jul 26, 2026
@timcassell
timcassell deleted the fix-arm64-net10-dmb-stub branch July 26, 2026 23:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CanDisassembleInlinableBenchmarks failed on arm64 platform when running with .NET 10

1 participant