Skip to content

Arm64: don't fold ldr page offset (PAGEOFFSET_12L) for NativeAOT#129966

Merged
MichalStrehovsky merged 7 commits into
dotnet:mainfrom
EgorBo:fix-129936-arm64-12l-naot
Jul 8, 2026
Merged

Arm64: don't fold ldr page offset (PAGEOFFSET_12L) for NativeAOT#129966
MichalStrehovsky merged 7 commits into
dotnet:mainfrom
EgorBo:fix-129936-arm64-12l-naot

Conversation

@EgorBo

@EgorBo EgorBo commented Jun 29, 2026

Copy link
Copy Markdown
Member

Fixes #129936.

PR #129589 added an Arm64 fold of adrp+add+ldr into adrp+ldr[#:lo12:] via a 64-bit PAGEOFFSET_12L reloc (R_AARCH64_LDST64_ABS_LO12_NC). That reloc encodes the offset scaled by 8, so the target must be 8-byte aligned. In R2R the relocatable loads always go through pointer-aligned indirection cells, but NativeAOT can fold a direct 64-bit load of byte-packed frozen data (4-byte aligned), which ld.lld rejects:

ld.lld : error : improper alignment for relocation R_AARCH64_LDST64_ABS_LO12_NC: 0x74A52C is not aligned to 8 bytes

The fold is purely a size optimization, so this restricts it to non-NativeAOT and falls back to the always-safe adrp+add+ldr.

Validation (SPMI, linux-arm64):

  • benchmarks.run (R2R, ~427K contexts): 0 asm diffs — the win is preserved.
  • smoke_tests.nativeaot (18891 ctx): clean replay, no diffs.

The adrp+add+ldr to adrp+ldr[#:lo12:] fold uses a 64-bit PAGEOFFSET_12L
reloc (R_AARCH64_LDST64_ABS_LO12_NC), whose scaled offset requires the
target to be 8-byte aligned. R2R loads always go through pointer-aligned
indirection cells, but NativeAOT can fold a direct 64-bit load of
byte-packed frozen data (4-byte aligned), which the linker rejects with
'improper alignment for relocation'. Restrict the fold to non-NativeAOT.

Fixes dotnet#129936

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 29, 2026 06:02
@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.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adjusts the Arm64 emitter’s TryFoldPageOffsetIntoLdr peephole optimization to avoid emitting PAGEOFFSET_12L relocations when targeting the NativeAOT ABI, preventing generation of linker-invalid R_AARCH64_LDST64_ABS_LO12_NC relocations in scenarios where the referenced symbol may not be 8-byte aligned.

Changes:

  • Disable adrp+add+ldradrp+ldr[#:lo12:] folding for NativeAOT by early-returning in TryFoldPageOffsetIntoLdr.
  • Add an in-code rationale describing the alignment requirement of PAGEOFFSET_12L / R_AARCH64_LDST64_ABS_LO12_NC and why NativeAOT differs.

Comment thread src/coreclr/jit/emitarm64.cpp Outdated

@jakobbotsch jakobbotsch 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.

LGTM

Co-authored-by: Jakob Botsch Nielsen <Jakob.botsch.nielsen@gmail.com>
Copilot AI review requested due to automatic review settings July 1, 2026 16:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.

Comment thread src/coreclr/jit/emitarm64.cpp Outdated
Comment thread src/coreclr/jit/emitarm64.cpp Outdated
@github-actions github-actions Bot mentioned this pull request Jul 2, 2026
The adrp+add+ldr -> adrp+ldr[#:lo12:] fold uses R_AARCH64_LDST64_ABS_LO12_NC,
which encodes the :lo12: page offset scaled by 8, so the reloc target must be
8-byte aligned. Replace the blanket NativeAOT opt-out with a new JIT-EE API,
getAddressAlignment(void*), and only fold when the VM guarantees the target is
at least 8-byte aligned.

- VM (CoreCLR/NGen): reports the alignment of the absolute address.
- crossgen2 (R2R): reports pointer size; direct relocatable loads only target
  pointer-aligned data.
- NativeAOT: reports the exact alignment of non-GC statics (the failing case)
  and pointer size for GC-statics/RVA data, and fails closed otherwise so an
  unaligned relocation can never be emitted.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

@MichalStrehovsky MichalStrehovsky 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.

Thank you for making it work for native AOT!

Comment thread src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs Outdated
Comment thread src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs Outdated
…Alignment

Replace the duplicated per-node alignment logic in getAddressAlignment with a
new IObjectNodeWithAlignment interface implemented by NonGCStaticsNode,
GCStaticsNode and FieldRvaDataNode. Each node's GetData/GetDehydratableData now
uses GetAlignment(factory) so the value reported to the JIT can never drift from
the alignment actually baked into the node's data.

Also move getAddressAlignment out of the shared CorInfoImpl.cs (dropping the
#if READYTORUN split) into CorInfoImpl.ReadyToRun.cs and CorInfoImpl.RyuJit.cs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 6, 2026 17:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 26 out of 26 changed files in this pull request and generated 1 comment.

Comment thread src/coreclr/vm/jitinterface.cpp
…tion)

Address review feedback: instead of R2R's blanket `return PointerSize`,
resolve the reloc target node and report its real alignment, mirroring the
NativeAOT implementation. Adds a parallel R2R IObjectNodeWithAlignment
interface (R2R has a separate node/NodeFactory system, so it can't share the
NAOT one) implemented on Import (returns the pointer-sized import-section
EntrySize) and CopiedFieldRvaNode. Unknown targets fall back to 1 so the JIT
never emits an alignment-sensitive reloc it can't prove is legal.

Validated: full System.Private.CoreLib arm64 R2R crossgen compiles cleanly;
every LDST64 fold candidate is an Import subclass reporting align=8 (no MISS,
no align<8), so the adrp+add+ldr -> adrp+ldr[:lo12:] fold is preserved.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs Outdated
EgorBo and others added 2 commits July 7, 2026 11:57
The R2R and NAOT bodies are now identical, so host it once in the shared
partial. Each compiler still binds its own IObjectNodeWithAlignment and
NodeFactory (only one is visible per compilation), so it resolves correctly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…naot

# Conflicts:
#	src/coreclr/inc/jiteeversionguid.h
Copilot AI review requested due to automatic review settings July 7, 2026 10:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 29 out of 29 changed files in this pull request and generated no new comments.

@EgorBo

EgorBo commented Jul 7, 2026

Copy link
Copy Markdown
Member Author

@jkotas @MichalStrehovsky anything else here?

@MichalStrehovsky MichalStrehovsky 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.

We now have two IObjectNodeWithAlignment.cs files with slightly different comments. But I really just want to unblock the CI. I would have preferred we revert the change that broke ARM64 testing the moment we found out it's not quite right and then do it properly at leisure.

@MichalStrehovsky MichalStrehovsky enabled auto-merge (squash) July 8, 2026 00:27
@MichalStrehovsky MichalStrehovsky merged commit a526847 into dotnet:main Jul 8, 2026
121 of 127 checks passed
@MichalStrehovsky

Copy link
Copy Markdown
Member

RyuJIT assert == build break and we cannot test anything.

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.

[ci-scan] Build break: NativeAOT linker alignment error in PhysicalPromotion test (arm64)

5 participants