Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Nov 4, 2025

Summary: Add ARM64 ADRP/LDR pair support for crossgen2

This PR adds support for the IMAGE_REL_BASED_ARM64_PAGEOFFSET_12L relocation type and converts ARM64 indirect address loads in crossgen2 to use ADRP/LDR pairs instead of PC-relative LDR with DIR64 relocations.

Problem

The previous implementation used PC-relative LDR instructions with 64-bit absolute address relocations (DIR64) in the TEXT section. This violates the W^X (Write XOR Execute) security model enforced by Apple's linkers, preventing the generation of Mach-O images for ARM64 targets (as identified in PR #120454).

Solution

Replaced the problematic pattern with ADRP/LDR pairs that use RIP-relative addressing:

  • Before: ldr x12, [PC+offset] + DIR64 relocation
  • After: adrp x12, symbol (PAGE21) + ldr x12, [x12, #page_offset] (PAGEOFF12L)

Implementation Checklist

  • Relocation.cs - Core relocation support

    • Added GetArm64Rel12Ldr() and PutArm64Rel12Ldr() helper functions
    • Properly handles 8-byte scaling for 64-bit LDR instructions
    • Added support in WriteValue(), ReadValue(), and GetSize() methods
    • Enhanced documentation with detailed bit mask explanations
  • ARM64Emitter.cs - Emitter updates

    • Added EmitADRP() method for ADRP instruction with PAGE21 relocation
    • Added EmitLDR(Register, Register, ISymbolNode) overload for LDR with PAGEOFFSET_12L
    • Modified EmitJMP() for indirection cells to use ADRP/LDR pair (eliminates DIR64)
  • ImportThunk (ReadyToRun) - R2R thunk updates

    • Updated EmitCode() to use ADRP/LDR pairs for ModuleImport references
    • Removed pointer alignment requirement and associated assertions
    • Updated constructor to not set _symbolOffset to 8 for ARM64
  • ObjectWriter integration

    • CoffObjectWriter.cs: Maps to IMAGE_REL_ARM64_PAGEOFFSET_12L
    • ElfObjectWriter.cs: Maps to R_AARCH64_LDST64_ABS_LO12_NC (reloc type 286)
    • MachObjectWriter.cs: Maps to ARM64_RELOC_PAGEOFF12
    • PEObjectWriter.cs: Added relocation resolution support
  • Build & Test

    • Successfully built CoreCLR and libraries with release configuration
    • Successfully built ReadyToRun compiler
    • No build errors or warnings
    • Code review feedback addressed

Technical Details

LDR Instruction Encoding

For 64-bit LDR instructions, the immediate value represents offset/8:

  • The 12-bit immediate field (bits 21-10) holds the scaled value
  • Actual byte offset is scaled by 8 (left shift by 3)
  • Maximum representable offset: 4095 * 8 = 32,760 bytes

Relocation Types

  • IMAGE_REL_BASED_ARM64_PAGEBASE_REL21 (0x81): ADRP instruction, 21-bit page-aligned offset
  • IMAGE_REL_BASED_ARM64_PAGEOFFSET_12L (0x83): LDR instruction, 12-bit page offset

Impact

Enables Mach-O image generation for ARM64 targets (macOS, iOS)
Improves security by complying with W^X requirements
Maintains compatibility with existing COFF (Windows) and ELF (Linux) formats
Uses RIP-relative addressing instead of absolute addresses

Files Changed

  • src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs
  • src/coreclr/tools/Common/Compiler/DependencyAnalysis/Target_ARM64/ARM64Emitter.cs
  • src/coreclr/tools/Common/Compiler/ObjectWriter/CoffObjectWriter.cs
  • src/coreclr/tools/Common/Compiler/ObjectWriter/ElfObjectWriter.cs
  • src/coreclr/tools/Common/Compiler/ObjectWriter/MachObjectWriter.cs
  • src/coreclr/tools/Common/Compiler/ObjectWriter/PEObjectWriter.cs
  • src/coreclr/tools/aot/ILCompiler.ReadyToRun/.../Target_ARM64/ImportThunk.cs
  • src/coreclr/tools/aot/ILCompiler.ReadyToRun/.../ImportThunk.cs
Original prompt

This section details on the original issue you should resolve

<issue_title>Use ADRP/LDR pairs for ARM64 64-bit indirect address loads in crossgen2</issue_title>
<issue_description>Does this really need to be here? Could we do an adrp/ldr pair for this?

Originally posted by @davidwrighton in #120454 (comment)

RiscV64 and Loongarch64 have similar issues</issue_description>

<agent_instructions>Add support in Relocation.cs for the IMAGE_REL_BASED_ARM64_PAGEOFFSET_12L relocation.

In ARM64Emitter.cs and Target_ARM64/ARM64Emitter.cs, convert the two usages of DIR64 relocs that are then loaded using LDR instructions (via the EmitLDR method calls) to instead use the ADRP instruction (with the RelocType.IMAGE_REL_BASED_ARM64_PAGEBASE_REL21 reloc) and an LDR instruction (with the RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12L reloc added above).

Add support to PEObjectWriter.cs, CoffObjectWriter.cs, ElfObjectWriter.cs, MachObjectWriter.cs, and ObjectWriter.cs for IMAGE_REL_BASED_ARM64_PAGEOFFSET_12L as needed.</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@jkoritzinsky Based on my research into the failures in https://dev.azure.com/dnceng-public/public/_build/results?buildId=1192259&view=logs&jobId=51b7f64e-2e22-59d4-4754-0789f9ab4927&j=51b7f64e-2e22-59d4-4754-0789f9ab4927&t=fbf6158e-fc6f-5409-f83e-2965da63b2da, this is issue is not only a perf improvement, but it is required for us to be able to emit Mach-O images.

Basically, the Apple linkers won't allow you to have a 64-bit absolute address reloc in the TEXT section as that means the dynamic linker needs to make the TEXT section writable on load, which violates their W^X security model. As a result, we need to shift the ARM64 case to RIP-relative addressing with ADRP/LDR to be able to emit Mach-O images.</comment_new>


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

@github-actions github-actions bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Nov 4, 2025
Copilot AI and others added 3 commits November 4, 2025 20:06
…itJMP to use ADRP/LDR pair

Co-authored-by: jkoritzinsky <1571408+jkoritzinsky@users.noreply.github.com>
Co-authored-by: jkoritzinsky <1571408+jkoritzinsky@users.noreply.github.com>
Co-authored-by: jkoritzinsky <1571408+jkoritzinsky@users.noreply.github.com>
Copilot AI changed the title [WIP] Add support for ADRP/LDR pairs in ARM64 indirect address loads Use ADRP/LDR pairs for ARM64 64-bit indirect address loads in crossgen2 Nov 4, 2025
Copilot AI requested a review from jkoritzinsky November 4, 2025 20:20
Copilot finished work on behalf of jkoritzinsky November 4, 2025 20:20
@jkoritzinsky
Copy link
Member

@copilot You should also edit the implementation of ImportThunk.EmitCode(NodeFactory, ref ARM64Emitter, bool) to reference the ModuleImport node in the same way:

  1. Update the instruction sequences that use PC-relative loads to load from the ModuleImport reloc to instead load it using ADRP/LDR. After doing so, you can remove the assert that the instruction encoder has zero bytes at the start and remove the requirement for pointer alignment.
  2. Update ImportThunk's constructor to not set _symbolOffset to 8 for ARM64.

…ences

Co-authored-by: jkoritzinsky <1571408+jkoritzinsky@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Nov 4, 2025

@copilot You should also edit the implementation of ImportThunk.EmitCode(NodeFactory, ref ARM64Emitter, bool) to reference the ModuleImport node in the same way:

  1. Update the instruction sequences t...

Updated in commit 8c37adf:

  1. Modified ImportThunk.EmitCode() to use ADRP/LDR pairs for ModuleImport references instead of PC-relative loads
  2. Removed the RequireInitialPointerAlignment() call and the zero-byte assertion
  3. Updated the constructor to exclude ARM64 from the _symbolOffset = 8 logic (now only applies to LoongArch64 and RiscV64)

The changes eliminate all DIR64 relocations in the TEXT section for ARM64 targets.

Copilot finished work on behalf of jkoritzinsky November 4, 2025 21:00
@jkoritzinsky jkoritzinsky marked this pull request as ready for review November 4, 2025 21:06
Copilot AI review requested due to automatic review settings November 4, 2025 21:06
@jkoritzinsky
Copy link
Member

/azp run runtime-coreclr r2r

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This pull request modernizes ARM64 code generation in the ReadyToRun compiler by replacing PC-relative addressing with ADRP/LDR instruction pairs for accessing module imports. The change eliminates the need for embedded 64-bit relocations and alignment requirements, resulting in more efficient and position-independent code generation.

Key changes:

  • Replaced PC-relative LDR instructions with ADRP/LDR pairs for loading module pointers
  • Introduced a new relocation type IMAGE_REL_BASED_ARM64_PAGEOFFSET_12L specifically for LDR instructions with scaled immediate offsets
  • Removed ARM64 from architectures requiring special symbol offset handling for non-Eager import thunks

Reviewed Changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
Target_ARM64/ImportThunk.cs Replaced PC-relative loads with ADRP/LDR pairs for module import access
ImportThunk.cs Removed ARM64 from architectures requiring symbol offset adjustments
Relocation.cs Added new relocation type and helper functions for LDR instruction encoding
ARM64Emitter.cs Added EmitADRP and symbol-based EmitLDR methods, updated EmitJMP for indirection cells
PEObjectWriter.cs Added handling for new ARM64_PAGEOFFSET_12L relocation type
MachObjectWriter.cs Added support for new relocation type in Mach-O format, corrected IsPCRelative logic
ElfObjectWriter.cs Mapped new relocation type to ELF R_AARCH64_LDST64_ABS_LO12_NC
CoffObjectWriter.cs Mapped new relocation type to COFF IMAGE_REL_ARM64_PAGEOFFSET_12L

…n.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: jkoritzinsky <1571408+jkoritzinsky@users.noreply.github.com>
Copilot AI requested a review from jkoritzinsky November 4, 2025 22:35
Copilot finished work on behalf of jkoritzinsky November 4, 2025 22:35
@jkoritzinsky
Copy link
Member

/ba-g android timeouts

@jkoritzinsky jkoritzinsky merged commit 11702c4 into main Nov 5, 2025
87 of 97 checks passed
@jkoritzinsky jkoritzinsky deleted the copilot/add-adrp-ldr-support-arm64 branch November 5, 2025 22:24
jkoritzinsky added a commit to jkoritzinsky/runtime that referenced this pull request Nov 7, 2025
They now match the ARM64 model we just moved to in dotnet#121352

Also, clean up the ARM64 emitter while we're at it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Use ADRP/LDR pairs for ARM64 64-bit indirect address loads in crossgen2

3 participants