From ba5224b5e1eb917aa5a89c8604ac0fd6f8515995 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Wed, 13 May 2026 12:06:14 -0700 Subject: [PATCH 1/5] Add missing THUMB_BRANCH24 and ARM64_BRANCH26 to Relocation.GetSize These relocation types were handled in ReadValue/WriteValue but missing from GetSize, causing a NotSupportedException when PEObjectWriter resolves relocations during ARM/ARM64 composite R2R image emission. Fixes crossgen2 crash in runtime-coreclr crossgen2-composite pipeline on linux arm (Generate CORE_ROOT step). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../tools/Common/Compiler/DependencyAnalysis/Relocation.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs index 3ed1f41e378e9d..11ac821aa0d759 100644 --- a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs +++ b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs @@ -703,6 +703,8 @@ public static int GetSize(RelocType relocType) RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12L => 4, RelocType.IMAGE_REL_BASED_THUMB_MOV32 => 8, RelocType.IMAGE_REL_BASED_THUMB_MOV32_PCREL => 8, + RelocType.IMAGE_REL_BASED_THUMB_BRANCH24 => 4, + RelocType.IMAGE_REL_BASED_ARM64_BRANCH26 => 4, RelocType.IMAGE_REL_BASED_LOONGARCH64_PC => 8, RelocType.IMAGE_REL_BASED_LOONGARCH64_JIR => 8, RelocType.IMAGE_REL_BASED_RISCV64_CALL_PLT => 8, From a0b82dd28e1a0431d7613d5cea5574aa9d8962d6 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Wed, 13 May 2026 16:21:55 -0700 Subject: [PATCH 2/5] Handle ARM branch relocs in composite R2R Resolve ARM branch relocations in PE images and avoid out-of-range Thumb branches for composite ARM exact method body calls. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/coreclr/jit/instr.cpp | 10 ++++- .../Compiler/DependencyAnalysis/Relocation.cs | 2 +- .../Compiler/ObjectWriter/PEObjectWriter.cs | 24 +++++++++++- .../tools/Common/JitInterface/CorInfoImpl.cs | 37 +++++++++++++++++++ 4 files changed, 69 insertions(+), 4 deletions(-) diff --git a/src/coreclr/jit/instr.cpp b/src/coreclr/jit/instr.cpp index 8e7451a9bc1a86..44dc3294b79517 100644 --- a/src/coreclr/jit/instr.cpp +++ b/src/coreclr/jit/instr.cpp @@ -1885,11 +1885,17 @@ bool CodeGen::arm_Valid_Imm_For_Add_SP(target_ssize_t imm) bool CodeGenInterface::validImmForBL(ssize_t addr) { + CorInfoReloc relocTypeHint = m_compiler->eeGetRelocTypeHint((void*)addr); + if (relocTypeHint != CorInfoReloc::NONE) + { + // Honor explicit non-branch hints from the EE by forcing an indirect call. + return relocTypeHint == CorInfoReloc::ARM32_THUMB_BRANCH24; + } + return // If we are running the altjit for AOT, then assume we can use the "BL" instruction. // This matches the usual behavior for AOT, since we normally do generate "BL". - (!m_compiler->info.compMatchedVM && m_compiler->IsAot()) || - (m_compiler->eeGetRelocTypeHint((void*)addr) == CorInfoReloc::ARM32_THUMB_BRANCH24); + (!m_compiler->info.compMatchedVM && m_compiler->IsAot()); } #endif // TARGET_ARM diff --git a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs index 8fe1e21be92cae..8fc1eed9871f3e 100644 --- a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs +++ b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs @@ -407,7 +407,7 @@ private static unsafe int GetArm64Rel28(uint* pCode) return imm28; } - private static bool FitsInArm64Rel28(long imm28) + public static bool FitsInArm64Rel28(long imm28) { return (imm28 >= -0x08000000L) && (imm28 < 0x08000000L); } diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/PEObjectWriter.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/PEObjectWriter.cs index 48b5209a8f81c0..912dbbf21c1521 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/PEObjectWriter.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/PEObjectWriter.cs @@ -904,7 +904,7 @@ private unsafe void ResolveRelocations(int sectionIndex, List= (nuint)_handleToObject.Count) + { + return false; + } + + obj = _handleToObject[(int)index]; + return true; + } + private MethodDesc HandleToObject(CORINFO_METHOD_STRUCT_* method) => (MethodDesc)HandleToObject((void*)method); private CORINFO_METHOD_STRUCT_* ObjectToHandle(MethodDesc method) => (CORINFO_METHOD_STRUCT_*)ObjectToHandle((object)method); private TypeDesc HandleToObject(CORINFO_CLASS_STRUCT_* type) => (TypeDesc)HandleToObject((void*)type); @@ -4349,6 +4377,15 @@ private CorInfoReloc getRelocTypeHint(void* target) #if READYTORUN case TargetArchitecture.ARM: + // Direct Thumb branches may not reach across large composite images. + // Force exact local method body calls through a relocatable movw/movt sequence. + if (_compilation.CompilationModuleGroup.IsCompositeBuildMode && + TryHandleToObject(target, out object targetObject) && + targetObject is MethodWithGCInfo) + { + return CorInfoReloc.ARM32_THUMB_MOV32; + } + return CorInfoReloc.ARM32_THUMB_BRANCH24; #endif From 75193ac544455d34050869498e5949b43ba6b7ea Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Mon, 18 May 2026 15:12:06 -0700 Subject: [PATCH 3/5] Narrow PE branch relocation handling Remove the speculative ARM composite-mode branch heuristic and keep PE relocation handling consistent with existing unchecked relocation resolution. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/coreclr/jit/instr.cpp | 10 +---- .../Compiler/DependencyAnalysis/Relocation.cs | 2 +- .../Compiler/ObjectWriter/PEObjectWriter.cs | 20 +--------- .../tools/Common/JitInterface/CorInfoImpl.cs | 37 ------------------- 4 files changed, 5 insertions(+), 64 deletions(-) diff --git a/src/coreclr/jit/instr.cpp b/src/coreclr/jit/instr.cpp index 44dc3294b79517..8e7451a9bc1a86 100644 --- a/src/coreclr/jit/instr.cpp +++ b/src/coreclr/jit/instr.cpp @@ -1885,17 +1885,11 @@ bool CodeGen::arm_Valid_Imm_For_Add_SP(target_ssize_t imm) bool CodeGenInterface::validImmForBL(ssize_t addr) { - CorInfoReloc relocTypeHint = m_compiler->eeGetRelocTypeHint((void*)addr); - if (relocTypeHint != CorInfoReloc::NONE) - { - // Honor explicit non-branch hints from the EE by forcing an indirect call. - return relocTypeHint == CorInfoReloc::ARM32_THUMB_BRANCH24; - } - return // If we are running the altjit for AOT, then assume we can use the "BL" instruction. // This matches the usual behavior for AOT, since we normally do generate "BL". - (!m_compiler->info.compMatchedVM && m_compiler->IsAot()); + (!m_compiler->info.compMatchedVM && m_compiler->IsAot()) || + (m_compiler->eeGetRelocTypeHint((void*)addr) == CorInfoReloc::ARM32_THUMB_BRANCH24); } #endif // TARGET_ARM diff --git a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs index 8fc1eed9871f3e..8fe1e21be92cae 100644 --- a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs +++ b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs @@ -407,7 +407,7 @@ private static unsafe int GetArm64Rel28(uint* pCode) return imm28; } - public static bool FitsInArm64Rel28(long imm28) + private static bool FitsInArm64Rel28(long imm28) { return (imm28 >= -0x08000000L) && (imm28 < 0x08000000L); } diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/PEObjectWriter.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/PEObjectWriter.cs index 912dbbf21c1521..ad67397800d1ea 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/PEObjectWriter.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/PEObjectWriter.cs @@ -913,27 +913,11 @@ private unsafe void ResolveRelocations(int sectionIndex, List= (nuint)_handleToObject.Count) - { - return false; - } - - obj = _handleToObject[(int)index]; - return true; - } - private MethodDesc HandleToObject(CORINFO_METHOD_STRUCT_* method) => (MethodDesc)HandleToObject((void*)method); private CORINFO_METHOD_STRUCT_* ObjectToHandle(MethodDesc method) => (CORINFO_METHOD_STRUCT_*)ObjectToHandle((object)method); private TypeDesc HandleToObject(CORINFO_CLASS_STRUCT_* type) => (TypeDesc)HandleToObject((void*)type); @@ -4377,15 +4349,6 @@ private CorInfoReloc getRelocTypeHint(void* target) #if READYTORUN case TargetArchitecture.ARM: - // Direct Thumb branches may not reach across large composite images. - // Force exact local method body calls through a relocatable movw/movt sequence. - if (_compilation.CompilationModuleGroup.IsCompositeBuildMode && - TryHandleToObject(target, out object targetObject) && - targetObject is MethodWithGCInfo) - { - return CorInfoReloc.ARM32_THUMB_MOV32; - } - return CorInfoReloc.ARM32_THUMB_BRANCH24; #endif From 8562d8959e66fca10f0ba567dac7a7e15dd8edc9 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Mon, 18 May 2026 15:59:05 -0700 Subject: [PATCH 4/5] Avoid out-of-range ARM branches in composite R2R Use a non-branch relocation hint for exact composite method bodies on ARM so crossgen2 emits an address-load sequence instead of a Thumb BL that may exceed its immediate range. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/coreclr/jit/instr.cpp | 9 +++-- .../tools/Common/JitInterface/CorInfoImpl.cs | 35 +++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/instr.cpp b/src/coreclr/jit/instr.cpp index 8e7451a9bc1a86..292c4791f27d3e 100644 --- a/src/coreclr/jit/instr.cpp +++ b/src/coreclr/jit/instr.cpp @@ -1885,11 +1885,16 @@ bool CodeGen::arm_Valid_Imm_For_Add_SP(target_ssize_t imm) bool CodeGenInterface::validImmForBL(ssize_t addr) { + CorInfoReloc relocTypeHint = m_compiler->eeGetRelocTypeHint((void*)addr); + if (relocTypeHint != CorInfoReloc::NONE) + { + return relocTypeHint == CorInfoReloc::ARM32_THUMB_BRANCH24; + } + return // If we are running the altjit for AOT, then assume we can use the "BL" instruction. // This matches the usual behavior for AOT, since we normally do generate "BL". - (!m_compiler->info.compMatchedVM && m_compiler->IsAot()) || - (m_compiler->eeGetRelocTypeHint((void*)addr) == CorInfoReloc::ARM32_THUMB_BRANCH24); + (!m_compiler->info.compMatchedVM && m_compiler->IsAot()); } #endif // TARGET_ARM diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 6d8853ac86f244..fe9a69c1dcf45c 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -774,6 +774,34 @@ private object HandleToObject(void* handle) return _handleToObject[index]; } + private bool TryHandleToObject(void* handle, out object obj) + { + obj = null; + if (handle == null) + { + return false; + } + +#if DEBUG + handle = (void*)(~s_handleHighBitSet & (nint)handle); +#endif + nint handleValue = (nint)handle; + nint indexValue = handleValue - handleBase; + if ((indexValue < 0) || ((indexValue % handleMultiplier) != 0)) + { + return false; + } + + nint index = indexValue / handleMultiplier; + if ((nuint)index >= (nuint)_handleToObject.Count) + { + return false; + } + + obj = _handleToObject[(int)index]; + return true; + } + private MethodDesc HandleToObject(CORINFO_METHOD_STRUCT_* method) => (MethodDesc)HandleToObject((void*)method); private CORINFO_METHOD_STRUCT_* ObjectToHandle(MethodDesc method) => (CORINFO_METHOD_STRUCT_*)ObjectToHandle((object)method); private TypeDesc HandleToObject(CORINFO_CLASS_STRUCT_* type) => (TypeDesc)HandleToObject((void*)type); @@ -4349,6 +4377,13 @@ private CorInfoReloc getRelocTypeHint(void* target) #if READYTORUN case TargetArchitecture.ARM: + if (_compilation.CompilationModuleGroup.IsCompositeBuildMode && + TryHandleToObject(target, out object targetObject) && + targetObject is MethodWithGCInfo) + { + return CorInfoReloc.ARM32_THUMB_MOV32; + } + return CorInfoReloc.ARM32_THUMB_BRANCH24; #endif From 88ee57faa721d5164907c88883de2929a61fd6b7 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Mon, 18 May 2026 17:43:43 -0700 Subject: [PATCH 5/5] Remove broad ARM relocation hint workaround Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/coreclr/jit/instr.cpp | 9 ++--- .../tools/Common/JitInterface/CorInfoImpl.cs | 35 ------------------- 2 files changed, 2 insertions(+), 42 deletions(-) diff --git a/src/coreclr/jit/instr.cpp b/src/coreclr/jit/instr.cpp index 292c4791f27d3e..8e7451a9bc1a86 100644 --- a/src/coreclr/jit/instr.cpp +++ b/src/coreclr/jit/instr.cpp @@ -1885,16 +1885,11 @@ bool CodeGen::arm_Valid_Imm_For_Add_SP(target_ssize_t imm) bool CodeGenInterface::validImmForBL(ssize_t addr) { - CorInfoReloc relocTypeHint = m_compiler->eeGetRelocTypeHint((void*)addr); - if (relocTypeHint != CorInfoReloc::NONE) - { - return relocTypeHint == CorInfoReloc::ARM32_THUMB_BRANCH24; - } - return // If we are running the altjit for AOT, then assume we can use the "BL" instruction. // This matches the usual behavior for AOT, since we normally do generate "BL". - (!m_compiler->info.compMatchedVM && m_compiler->IsAot()); + (!m_compiler->info.compMatchedVM && m_compiler->IsAot()) || + (m_compiler->eeGetRelocTypeHint((void*)addr) == CorInfoReloc::ARM32_THUMB_BRANCH24); } #endif // TARGET_ARM diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index fe9a69c1dcf45c..6d8853ac86f244 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -774,34 +774,6 @@ private object HandleToObject(void* handle) return _handleToObject[index]; } - private bool TryHandleToObject(void* handle, out object obj) - { - obj = null; - if (handle == null) - { - return false; - } - -#if DEBUG - handle = (void*)(~s_handleHighBitSet & (nint)handle); -#endif - nint handleValue = (nint)handle; - nint indexValue = handleValue - handleBase; - if ((indexValue < 0) || ((indexValue % handleMultiplier) != 0)) - { - return false; - } - - nint index = indexValue / handleMultiplier; - if ((nuint)index >= (nuint)_handleToObject.Count) - { - return false; - } - - obj = _handleToObject[(int)index]; - return true; - } - private MethodDesc HandleToObject(CORINFO_METHOD_STRUCT_* method) => (MethodDesc)HandleToObject((void*)method); private CORINFO_METHOD_STRUCT_* ObjectToHandle(MethodDesc method) => (CORINFO_METHOD_STRUCT_*)ObjectToHandle((object)method); private TypeDesc HandleToObject(CORINFO_CLASS_STRUCT_* type) => (TypeDesc)HandleToObject((void*)type); @@ -4377,13 +4349,6 @@ private CorInfoReloc getRelocTypeHint(void* target) #if READYTORUN case TargetArchitecture.ARM: - if (_compilation.CompilationModuleGroup.IsCompositeBuildMode && - TryHandleToObject(target, out object targetObject) && - targetObject is MethodWithGCInfo) - { - return CorInfoReloc.ARM32_THUMB_MOV32; - } - return CorInfoReloc.ARM32_THUMB_BRANCH24; #endif