Skip to content

JIT: fix DWARF register numbers and encoding for APX eGPRs - #133918

Draft
DeepakRajendrakumaran wants to merge 1 commit into
dotnet:mainfrom
DeepakRajendrakumaran:unwinder_aot_linux
Draft

DeepakRajendrakumaran wants to merge 1 commit into
dotnet:mainfrom
DeepakRajendrakumaran:unwinder_aot_linux

Conversation

@DeepakRajendrakumaran

Copy link
Copy Markdown
Contributor

Three related fixes to the Unix CFI unwind path for APX.

1. unwindPush2Pop2CFI described PUSH2 as two separate pushes

. PUSH2 moves RSP by 2 * REGSIZE_BYTES in one step, so it needs a single CFA adjustment of the full amount. Emit one CFI_ADJUST_CFA_OFFSET plus a CFI_REL_OFFSET per callee-saved register, with reg1 at REGSIZE_BYTES and reg2 at 0, matching Intel's PUSH2 semantics ([rsp] = reg2, [rsp + 8] = reg1). This matches what LLVM emits: https://godbolt.org/z/z179oGeq5.

Details:
unwindPush2Pop2CFI was a placeholder that called unwindPushPopCFI twice.
That is correct but describes a single instruction as two, and it left two
adjacent latent bugs on the eGPR path unexercised. Three changes:

unwind.cpp — emit one DW_CFA_def_cfa_offset of 2 * REGSIZE_BYTES
per push2 instead of two of one slot each, matching LLVM's
X86FrameLowering. Intel PUSH2 reg1, reg2 stores [rsp]=reg2 and
[rsp+8]=reg1, so reg1 takes the higher slot: CFI_REL_OFFSET gets
REGSIZE_BYTES for reg1 and 0 for reg2.

How the CFI changed

Measured with unwindTest, a NativeAOT linux-x64 app built with
--codegenopt:EnableAPX=1 + EnableApxPP2=1 + EnableApxPPHint=1, whose frames
exhaust the callee-saved integer set so the JIT pairs the spills. Built and run
both ways on APX hardware.

For a prolog containing push2p %r14,%r15 (AT&T; Intel PUSH2 r15, r14):

  DW_CFA_advance_loc: 6
- DW_CFA_def_cfa_offset: +24
+ DW_CFA_def_cfa_offset: +32
  DW_CFA_offset: R15 -24
- DW_CFA_def_cfa_offset: +32
  DW_CFA_offset: R14 -32

2. mapRegNumToDwarfReg assigned r16-r31 the numbers 16-31.

The x86-64 psABI assigns them 130-145; 16 is the return-address column and 17-32 are XMM0-XMM15. Emitting 16-31 would alias r16 onto the return address and r17-r31 onto XMM0-XMM14: https://lkml.rescloud.iu.edu/hypermail/linux/kernel/2605.3/09638.html.

3. DwarfFde.cs wrote the register operand of DW_CFA_def_cfa_register and DW_CFA_def_cfa as a raw byte.

That is a valid ULEB128 encoding only for values <= 127. 130 encodes as 0x82 0x01; a bare 0x82 sets the continuation bit, swallowing the next byte and desynchronising the rest of the CFI program. Use DwarfHelper.WriteULEB128, as the CFI_REL_OFFSET path already does.

@github-actions github-actions Bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Sep 14, 2026
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 5 pipeline(s).
11 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service dotnet-policy-service Bot added the community-contribution Indicates that the PR has been added by a community member label Sep 14, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

The psABI numbers r16-r31 as 130-145; 16-31 aliased the return-address
column and XMM0-XMM14. ULEB128-encode the DW_CFA_def_cfa[_register]
operand so those values survive; push2 now takes one 16-byte CFA adjust.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant