From d7b43170fb36acf4fe6357323484f3b37d45b7bd Mon Sep 17 00:00:00 2001 From: Maxim Menshikov Date: Mon, 4 May 2026 14:07:05 +0100 Subject: [PATCH 1/9] Experimental patch to split code and data Signed-off-by: Maxim Menshikov --- patches/bflat-runtime/20_splitcodedata.patch | 337 +++++++++++++++++++ 1 file changed, 337 insertions(+) create mode 100644 patches/bflat-runtime/20_splitcodedata.patch diff --git a/patches/bflat-runtime/20_splitcodedata.patch b/patches/bflat-runtime/20_splitcodedata.patch new file mode 100644 index 0000000..1c96a7d --- /dev/null +++ b/patches/bflat-runtime/20_splitcodedata.patch @@ -0,0 +1,337 @@ +diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h +index b0d0108a31d..e39b0a6a571 100644 +--- a/src/coreclr/inc/corinfo.h ++++ b/src/coreclr/inc/corinfo.h +@@ -3407,6 +3407,12 @@ public: + // RISCV64 relocation types + // + #define IMAGE_REL_RISCV64_PC 0x0003 ++// Paired pc-relative relocations for an auipc + addi/ld sequence that ++// loads the address of (or value at) a data symbol. Required when the ++// target lives in a separate section from the code (e.g. method roData ++// in .rodata) so the linker, not the JIT, supplies the displacement. ++#define IMAGE_REL_RISCV64_PCREL_HI20 0x0004 ++#define IMAGE_REL_RISCV64_PCREL_LO12_I 0x0005 + + /**********************************************************************************/ + #ifdef TARGET_64BIT +diff --git a/src/coreclr/jit/ee_il_dll.cpp b/src/coreclr/jit/ee_il_dll.cpp +index 9df0a0c29e5..b05bfbe99c6 100644 +--- a/src/coreclr/jit/ee_il_dll.cpp ++++ b/src/coreclr/jit/ee_il_dll.cpp +@@ -1140,7 +1140,13 @@ void Compiler::eeAllocMem(AllocMemArgs* args, const UNATIVE_OFFSET roDataSection + + #endif // DEBUG + +-#if defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) ++// RISCV64 intentionally excluded: keeping JIT roData adjacent to hot code ++// causes jump tables and constants to land inside the .text section in ++// the final ELF (because the AOT object writer sees one contiguous code ++// blob), which breaks Zisk's RomData prover constraints. By NOT inlining ++// the roData block here, the AOT pipeline emits roData as a separate ++// MethodReadOnlyDataNode that lands in .rodata as expected. ++#if defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) + + // For arm64/LoongArch64/RISCV64, we want to allocate JIT data always adjacent to code similar to what native + // compiler does. +@@ -1157,7 +1163,7 @@ void Compiler::eeAllocMem(AllocMemArgs* args, const UNATIVE_OFFSET roDataSection + args->hotCodeSize = roDataOffset + args->roDataSize; + args->roDataSize = 0; + +-#endif // defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) ++#endif // defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) + + info.compCompHnd->allocMem(args); + +@@ -1174,7 +1180,13 @@ void Compiler::eeAllocMem(AllocMemArgs* args, const UNATIVE_OFFSET roDataSection + + #endif // DEBUG + +-#if defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) ++// RISCV64 intentionally excluded: keeping JIT roData adjacent to hot code ++// causes jump tables and constants to land inside the .text section in ++// the final ELF (because the AOT object writer sees one contiguous code ++// blob), which breaks Zisk's RomData prover constraints. By NOT inlining ++// the roData block here, the AOT pipeline emits roData as a separate ++// MethodReadOnlyDataNode that lands in .rodata as expected. ++#if defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) + + // Fix up data section pointers. + assert(args->roDataBlock == nullptr); +@@ -1182,7 +1194,7 @@ void Compiler::eeAllocMem(AllocMemArgs* args, const UNATIVE_OFFSET roDataSection + args->roDataBlock = ((BYTE*)args->hotCodeBlock) + roDataOffset; + args->roDataBlockRW = ((BYTE*)args->hotCodeBlockRW) + roDataOffset; + +-#endif // defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) ++#endif // defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) + } + + void Compiler::eeReserveUnwindInfo(bool isFunclet, bool isColdCode, ULONG unwindSize) +diff --git a/src/coreclr/jit/emitriscv64.cpp b/src/coreclr/jit/emitriscv64.cpp +index c0c80413a33..5b676db1a48 100644 +--- a/src/coreclr/jit/emitriscv64.cpp ++++ b/src/coreclr/jit/emitriscv64.cpp +@@ -1045,9 +1045,13 @@ void emitter::emitIns_R_C( + id->idOpSize(EA_PTRSIZE); + } + +- // TODO-RISCV64: this maybe deleted. +- id->idSetIsBound(); // We won't patch address since we will know the exact distance +- // once JIT code and data are allocated together. ++ // RISC-V64 used to allocate JIT code and roData adjacent (see ++ // eeAllocMem) and therefore knew the exact code→roData distance at ++ // emit time. We now keep roData as a separate AOT blob (.rodata ++ // section) so the distance is only resolved at link time. Do NOT mark ++ // the instr as bound — emitOutputInstr_OptsRc will leave the auipc ++ // immediate at zero and record an IMAGE_REL_RISCV64_PC relocation ++ // against the roData symbol. + + assert(addrReg == REG_NA); // NOTE: for RISV64, not support addrReg != REG_NA. + +@@ -3008,13 +3012,21 @@ BYTE* emitter::emitOutputInstr_OptsRc(BYTE* dst, const instrDesc* id, instructio + const regNumber reg1 = id->idReg1(); + assert(reg1 != REG_ZERO); + assert(id->idCodeSize() == 2 * sizeof(code_t)); +- const ssize_t immediate = (emitConsBlock - dst) + offset; +- assert((immediate > 0) && ((immediate & 0x03) == 0)); +- assert(isValidSimm32(immediate)); + ++ // Emit auipc + (ld/addi) with zero immediates and record a paired ++ // PC-relative relocation: HI20 on the auipc and LO12_I on the ++ // following load/add. The linker substitutes the actual displacement ++ // between the auipc PC and the roData symbol once the .text and ++ // .rodata sections are laid out. ++ BYTE* const dstBase = dst; + const regNumber tempReg = isFloatReg(reg1) ? codeGen->rsGetRsvdReg() : reg1; +- dst += emitOutput_UTypeInstr(dst, INS_auipc, tempReg, UpperNBitsOfWordSignExtend<20>(immediate)); +- dst += emitOutput_ITypeInstr(dst, *ins, reg1, tempReg, LowerNBitsOfWord<12>(immediate)); ++ dst += emitOutput_UTypeInstr(dst, INS_auipc, tempReg, 0); ++ dst += emitOutput_ITypeInstr(dst, *ins, reg1, tempReg, 0); ++ ++ BYTE* const target = emitConsBlock + offset; ++ emitRecordRelocation(dstBase, target, IMAGE_REL_RISCV64_PCREL_HI20); ++ emitRecordRelocation(dstBase + 4, target, IMAGE_REL_RISCV64_PCREL_LO12_I); ++ + return dst; + } + +diff --git a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/ObjectDataBuilder.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/ObjectDataBuilder.cs +index 53e4671b57a..84ab0407493 100644 +--- a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/ObjectDataBuilder.cs ++++ b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/ObjectDataBuilder.cs +@@ -301,6 +301,8 @@ public void EmitReloc(ISymbolNode symbol, RelocType relocType, int delta = 0) + case RelocType.IMAGE_REL_BASED_LOONGARCH64_JIR: + + case RelocType.IMAGE_REL_BASED_RISCV64_PC: ++ case RelocType.IMAGE_REL_BASED_RISCV64_PCREL_HI20: ++ case RelocType.IMAGE_REL_BASED_RISCV64_PCREL_LO12_I: + Debug.Assert(delta == 0); + // Do not vacate space for this kind of relocation, because + // the space is embedded in the instruction. +diff --git a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs +index 91991a6882e..37755f42fd6 100644 +--- a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs ++++ b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs +@@ -30,6 +30,14 @@ public enum RelocType + IMAGE_REL_BASED_ARM64_PAGEOFFSET_12A = 0x82, // ADD/ADDS (immediate) with zero shift, for page offset + IMAGE_REL_BASED_ARM64_PAGEOFFSET_12L = 0x83, // LDR (indexed, unsigned immediate), for page offset + ++ // RISC-V PC-relative paired relocations for data references. ++ // Used for auipc + addi/ld pair where the destination is a data ++ // symbol (e.g. a per-method roData blob in .rodata) that is *not* ++ // adjacent to the code at link time. The HI20 reloc is recorded on ++ // the auipc and LO12_I on the following addi/ld. ++ IMAGE_REL_BASED_RISCV64_PCREL_HI20 = 0x84, // RISC-V: auipc (HI20 of pc-relative) ++ IMAGE_REL_BASED_RISCV64_PCREL_LO12_I = 0x85, // RISC-V: addi/ld (LO12 of pc-relative) ++ + // + // Relocation operators related to TLS access + // +@@ -488,6 +496,58 @@ private static unsafe void PutRiscV64PC(uint* pCode, long imm32) + Debug.Assert(GetRiscV64PC(pCode) == imm32); + } + ++ // Patch the HI20 of a single auipc with the upper 20 bits of imm32 ++ // (after rounding for the sign of the LO12 part). The lower 12 bits ++ // are emitted by the matching IMAGE_REL_BASED_RISCV64_PCREL_LO12_I ++ // relocation on the following instruction. ++ private static unsafe void PutRiscV64PcrelHi20(uint* pCode, long imm32) ++ { ++ Debug.Assert((imm32 >= (long)-0x80000000 - 0x800) && (imm32 < (long)0x80000000 - 0x800)); ++ ++ uint auipcInstr = *pCode; ++ Debug.Assert((auipcInstr & 0x7f) == 0x00000017); // auipc opcode ++ auipcInstr = (auipcInstr & 0x00000fff) | (uint)((imm32 + 0x800) & 0xfffff000); ++ *pCode = auipcInstr; ++ } ++ ++ private static unsafe int GetRiscV64PcrelHi20(uint* pCode) ++ { ++ uint auipcInstr = *pCode; ++ Debug.Assert((auipcInstr & 0x7f) == 0x00000017); ++ return (int)(auipcInstr & 0xfffff000); ++ } ++ ++ // Patch the LO12 of a single I-type instruction. Accepts the same ++ // forms as PutRiscV64PC (addi/jalr/ld) plus flw/fld since FP ++ // constants also flow through emitOutputInstr_OptsRc. ++ private static unsafe bool IsValidRiscV64Lo12Instr(uint instr) ++ { ++ uint masked = instr & 0x707f; ++ return masked == 0x00000013 // addi ++ || masked == 0x00000067 // jalr ++ || masked == 0x00003003 // ld ++ || masked == 0x00002007 // flw ++ || masked == 0x00003007; // fld ++ } ++ ++ private static unsafe void PutRiscV64PcrelLo12(uint* pCode, long imm32) ++ { ++ Debug.Assert((imm32 >= (long)-0x80000000 - 0x800) && (imm32 < (long)0x80000000 - 0x800)); ++ ++ int doff = (int)(imm32 & 0xfff); ++ uint instr = *pCode; ++ Debug.Assert(IsValidRiscV64Lo12Instr(instr)); ++ instr = (instr & 0x000fffff) | (uint)((doff & 0xfff) << 20); ++ *pCode = instr; ++ } ++ ++ private static unsafe int GetRiscV64PcrelLo12(uint* pCode) ++ { ++ uint instr = *pCode; ++ Debug.Assert(IsValidRiscV64Lo12Instr(instr)); ++ return ((int)instr) >> 20; ++ } ++ + public Relocation(RelocType relocType, int offset, ISymbolNode target) + { + RelocType = relocType; +@@ -548,6 +608,12 @@ public static unsafe void WriteValue(RelocType relocType, void* location, long v + case RelocType.IMAGE_REL_BASED_RISCV64_PC: + PutRiscV64PC((uint*)location, value); + break; ++ case RelocType.IMAGE_REL_BASED_RISCV64_PCREL_HI20: ++ PutRiscV64PcrelHi20((uint*)location, value); ++ break; ++ case RelocType.IMAGE_REL_BASED_RISCV64_PCREL_LO12_I: ++ PutRiscV64PcrelLo12((uint*)location, value); ++ break; + default: + Debug.Fail("Invalid RelocType: " + relocType); + break; +@@ -615,6 +681,10 @@ public static unsafe long ReadValue(RelocType relocType, void* location) + return (long)GetLoongArch64JIR((uint*)location); + case RelocType.IMAGE_REL_BASED_RISCV64_PC: + return (long)GetRiscV64PC((uint*)location); ++ case RelocType.IMAGE_REL_BASED_RISCV64_PCREL_HI20: ++ return (long)GetRiscV64PcrelHi20((uint*)location); ++ case RelocType.IMAGE_REL_BASED_RISCV64_PCREL_LO12_I: ++ return (long)GetRiscV64PcrelLo12((uint*)location); + default: + Debug.Fail("Invalid RelocType: " + relocType); + return 0; +diff --git a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Target_RiscV64/RiscV64Emitter.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Target_RiscV64/RiscV64Emitter.cs +index 380163ed2fb..b89e07fc3b8 100644 +--- a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Target_RiscV64/RiscV64Emitter.cs ++++ b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Target_RiscV64/RiscV64Emitter.cs +@@ -43,10 +43,17 @@ public void EmitMOV(Register regDst, Register regSrc) + + public void EmitMOV(Register regDst, ISymbolNode symbol) + { +- Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_RISCV64_PC); +- //auipc reg, off-hi-20bits ++ // Loading the address of a data symbol via auipc + addi. We ++ // emit a paired PC-relative relocation (HI20 on the auipc, ++ // LO12_I on the addi) so the linker resolves the immediate ++ // when .text and the symbol's section are placed; using ++ // IMAGE_REL_BASED_RISCV64_PC (which maps to R_RISCV_CALL_PLT) ++ // here would route data references through the PLT. ++ Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_RISCV64_PCREL_HI20); ++ // auipc reg, off-hi-20bits + EmitPC(regDst); +- //addi reg, reg, off-lo-12bits ++ Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_RISCV64_PCREL_LO12_I); ++ // addi reg, reg, off-lo-12bits + EmitADDI(regDst, regDst, 0); + } + +diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +index e6fd0d4f7f8..b4d486a2727 100644 +--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs ++++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +@@ -4050,11 +4050,17 @@ private static RelocType GetRelocType(TargetArchitecture targetArchitecture, ush + case TargetArchitecture.RiscV64: + { + const ushort IMAGE_REL_RISCV64_PC = 3; ++ const ushort IMAGE_REL_RISCV64_PCREL_HI20 = 4; ++ const ushort IMAGE_REL_RISCV64_PCREL_LO12_I = 5; + + switch (fRelocType) + { + case IMAGE_REL_RISCV64_PC: + return RelocType.IMAGE_REL_BASED_RISCV64_PC; ++ case IMAGE_REL_RISCV64_PCREL_HI20: ++ return RelocType.IMAGE_REL_BASED_RISCV64_PCREL_HI20; ++ case IMAGE_REL_RISCV64_PCREL_LO12_I: ++ return RelocType.IMAGE_REL_BASED_RISCV64_PCREL_LO12_I; + default: + Debug.Fail("Invalid RelocType: " + fRelocType); + return 0; +diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/ElfObjectWriter.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/ElfObjectWriter.cs +index 5204eb587c6..cc0b7943f7f 100644 +--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/ElfObjectWriter.cs ++++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/ElfObjectWriter.cs +@@ -561,6 +561,8 @@ private void EmitRelocationsRiscV64(int sectionIndex, List r + IMAGE_REL_BASED_HIGHLOW => R_RISCV_32, + IMAGE_REL_BASED_RELPTR32 => R_RISCV_32_PCREL, + IMAGE_REL_BASED_RISCV64_PC => R_RISCV_CALL_PLT, ++ IMAGE_REL_BASED_RISCV64_PCREL_HI20 => R_RISCV_PCREL_HI20, ++ IMAGE_REL_BASED_RISCV64_PCREL_LO12_I => R_RISCV_PCREL_LO12_I, + _ => throw new NotSupportedException("Unknown relocation type: " + symbolicRelocation.Type) + }; + +diff --git a/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp b/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp +index e878cd59d82..8f51e019435 100644 +--- a/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp ++++ b/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp +@@ -926,6 +926,18 @@ void CompileResult::applyRelocs(RelocContext* rc, unsigned char* block1, ULONG b + } + break; + ++ case IMAGE_REL_RISCV64_PCREL_HI20: ++ case IMAGE_REL_RISCV64_PCREL_LO12_I: ++ { ++ // Paired pc-relative data load relocs are resolved at ++ // link time by the host's ObjectWriter. SuperPMI does ++ // not link, so we can leave the immediates at zero ++ // here — what matters for SPMI replay is the JIT ++ // emission, not the final patched bytes. ++ wasRelocHandled = true; ++ } ++ break; ++ + default: + break; + } +diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp +index 74bab557b44..b6de7b09843 100644 +--- a/src/coreclr/vm/jitinterface.cpp ++++ b/src/coreclr/vm/jitinterface.cpp +@@ -11930,6 +11930,17 @@ void CEEJitInfo::recordRelocation(void * location, + } + break; + ++ case IMAGE_REL_RISCV64_PCREL_HI20: ++ case IMAGE_REL_RISCV64_PCREL_LO12_I: ++ { ++ // Paired pc-relative relocs are only used by the AOT compiler, ++ // where they are resolved at link time. The runtime JIT keeps ++ // code+roData adjacent, so it never needs to patch a partial ++ // half here. Treat as no-op so VM doesn't assert. ++ _ASSERTE(addlDelta == 0); ++ } ++ break; ++ + #endif // TARGET_RISCV64 + + default: From e0b6c47c36540233453df6ea8db7c9ac19ec862b Mon Sep 17 00:00:00 2001 From: Maxim Menshikov Date: Mon, 4 May 2026 15:22:36 +0100 Subject: [PATCH 2/9] Experimental patch to split code and data [2] Signed-off-by: Maxim Menshikov --- patches/bflat-runtime/20_splitcodedata.patch | 43 ++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/patches/bflat-runtime/20_splitcodedata.patch b/patches/bflat-runtime/20_splitcodedata.patch index 1c96a7d..9a2edd1 100644 --- a/patches/bflat-runtime/20_splitcodedata.patch +++ b/patches/bflat-runtime/20_splitcodedata.patch @@ -290,6 +290,49 @@ index 5204eb587c6..cc0b7943f7f 100644 _ => throw new NotSupportedException("Unknown relocation type: " + symbolicRelocation.Type) }; +diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/RelocationHelper.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/RelocationHelper.cs +index 6a2501482ab..1d45561ee69 100644 +--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/RelocationHelper.cs ++++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/RelocationHelper.cs +@@ -240,6 +240,27 @@ public void ProcessRelocation(RelocType relocationType, int sourceRVA, int targe + break; + } + ++ case RelocType.IMAGE_REL_BASED_RISCV64_PCREL_HI20: ++ { ++ // HI20 patches a single auipc instruction. The ++ // displacement is taken from the auipc PC itself ++ // (which is the source RVA of this reloc). ++ relocationLength = 4; ++ delta = targetRVA - sourceRVA; ++ break; ++ } ++ ++ case RelocType.IMAGE_REL_BASED_RISCV64_PCREL_LO12_I: ++ { ++ // LO12_I patches the addi/ld immediate; the value ++ // is the lower 12 bits of (target - auipc_PC), ++ // and the auipc lives one instruction (4 bytes) ++ // before this LO12 source RVA. ++ relocationLength = 4; ++ delta = targetRVA - (sourceRVA - 4); ++ break; ++ } ++ + default: + throw new NotSupportedException(); + } +@@ -257,7 +278,9 @@ public void ProcessRelocation(RelocType relocationType, int sourceRVA, int targe + (relocationType == RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12A) || + (relocationType == RelocType.IMAGE_REL_BASED_LOONGARCH64_PC) || + (relocationType == RelocType.IMAGE_REL_BASED_LOONGARCH64_JIR) || +- (relocationType == RelocType.IMAGE_REL_BASED_RISCV64_PC) ++ (relocationType == RelocType.IMAGE_REL_BASED_RISCV64_PC) || ++ (relocationType == RelocType.IMAGE_REL_BASED_RISCV64_PCREL_HI20) || ++ (relocationType == RelocType.IMAGE_REL_BASED_RISCV64_PCREL_LO12_I) + ) && (value != 0)) + { + throw new NotSupportedException(); diff --git a/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp b/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp index e878cd59d82..8f51e019435 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp From 537ce2c7c6774082956c8458fc5009fdff8b72ef Mon Sep 17 00:00:00 2001 From: Maxim Menshikov Date: Mon, 4 May 2026 20:07:34 +0100 Subject: [PATCH 3/9] Experimental patch to split code and data [3] Signed-off-by: Maxim Menshikov --- patches/bflat-runtime/20_splitcodedata.patch | 23 +++++++++++--------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/patches/bflat-runtime/20_splitcodedata.patch b/patches/bflat-runtime/20_splitcodedata.patch index 9a2edd1..9a5c042 100644 --- a/patches/bflat-runtime/20_splitcodedata.patch +++ b/patches/bflat-runtime/20_splitcodedata.patch @@ -291,7 +291,7 @@ index 5204eb587c6..cc0b7943f7f 100644 }; diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/RelocationHelper.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/RelocationHelper.cs -index 6a2501482ab..1d45561ee69 100644 +index 6a2501482ab..1c1e48fbe37 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/RelocationHelper.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/RelocationHelper.cs @@ -240,6 +240,27 @@ public void ProcessRelocation(RelocType relocationType, int sourceRVA, int targe @@ -322,17 +322,20 @@ index 6a2501482ab..1d45561ee69 100644 default: throw new NotSupportedException(); } -@@ -257,7 +278,9 @@ public void ProcessRelocation(RelocType relocationType, int sourceRVA, int targe +@@ -253,6 +274,13 @@ public void ProcessRelocation(RelocType relocationType, int sourceRVA, int targe + { + long value = Relocation.ReadValue(relocationType, bufferContent); + // Supporting non-zero values for ARM64 would require refactoring this function ++ // Non-zero addends carried in the instruction ++ // immediate are fine for the RISC-V PCREL_HI20 / ++ // PCREL_LO12_I pair: each helper patches only its ++ // own instruction, and value+delta produces the ++ // full target-relative displacement (target - ++ // auipc_PC). The other entries in this guard list ++ // do not have this property and still throw. + if (((relocationType == RelocType.IMAGE_REL_BASED_ARM64_PAGEBASE_REL21) || (relocationType == RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12A) || (relocationType == RelocType.IMAGE_REL_BASED_LOONGARCH64_PC) || - (relocationType == RelocType.IMAGE_REL_BASED_LOONGARCH64_JIR) || -- (relocationType == RelocType.IMAGE_REL_BASED_RISCV64_PC) -+ (relocationType == RelocType.IMAGE_REL_BASED_RISCV64_PC) || -+ (relocationType == RelocType.IMAGE_REL_BASED_RISCV64_PCREL_HI20) || -+ (relocationType == RelocType.IMAGE_REL_BASED_RISCV64_PCREL_LO12_I) - ) && (value != 0)) - { - throw new NotSupportedException(); diff --git a/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp b/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp index e878cd59d82..8f51e019435 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp From 639d3ec29e7e666058337d07acea29be446f5ed3 Mon Sep 17 00:00:00 2001 From: Maxim Menshikov Date: Tue, 5 May 2026 10:24:15 +0100 Subject: [PATCH 4/9] Update patch Signed-off-by: Maxim Menshikov --- patches/bflat-runtime/20_splitcodedata.patch | 23 ++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/patches/bflat-runtime/20_splitcodedata.patch b/patches/bflat-runtime/20_splitcodedata.patch index 9a5c042..65825a7 100644 --- a/patches/bflat-runtime/20_splitcodedata.patch +++ b/patches/bflat-runtime/20_splitcodedata.patch @@ -68,7 +68,7 @@ index 9df0a0c29e5..b05bfbe99c6 100644 void Compiler::eeReserveUnwindInfo(bool isFunclet, bool isColdCode, ULONG unwindSize) diff --git a/src/coreclr/jit/emitriscv64.cpp b/src/coreclr/jit/emitriscv64.cpp -index c0c80413a33..5b676db1a48 100644 +index c0c80413a33..6fe308d3993 100644 --- a/src/coreclr/jit/emitriscv64.cpp +++ b/src/coreclr/jit/emitriscv64.cpp @@ -1045,9 +1045,13 @@ void emitter::emitIns_R_C( @@ -88,7 +88,26 @@ index c0c80413a33..5b676db1a48 100644 assert(addrReg == REG_NA); // NOTE: for RISV64, not support addrReg != REG_NA. -@@ -3008,13 +3012,21 @@ BYTE* emitter::emitOutputInstr_OptsRc(BYTE* dst, const instrDesc* id, instructio +@@ -2990,7 +2994,17 @@ BYTE* emitter::emitOutputInstr_OptsReloc(BYTE* dst, const instrDesc* id, instruc + + dst += emitOutput_ITypeInstr(dst, *ins, reg1, reg1, 0); + +- emitRecordRelocation(dstBase, id->idAddr()->iiaAddr, IMAGE_REL_RISCV64_PC); ++ // Use paired PC-relative relocations against the data target so the ++ // linker resolves auipc+addi (take address of) / auipc+ld (load value ++ // at address) cross-section. Emitting a single ++ // IMAGE_REL_BASED_RISCV64_PC (R_RISCV_CALL_PLT) here would force the ++ // linker to keep the target adjacent to the auipc — which causes ++ // helper-pointer slots, jump-table entries and other AOT data nodes ++ // to bleed into .text. HI20/LO12_I lets each side patch its own ++ // immediate independently and lets the target live in .rodata/.data. ++ BYTE* const target = id->idAddr()->iiaAddr; ++ emitRecordRelocation(dstBase, target, IMAGE_REL_RISCV64_PCREL_HI20); ++ emitRecordRelocation(dstBase + 4, target, IMAGE_REL_RISCV64_PCREL_LO12_I); + + return dst; + } +@@ -3008,13 +3022,21 @@ BYTE* emitter::emitOutputInstr_OptsRc(BYTE* dst, const instrDesc* id, instructio const regNumber reg1 = id->idReg1(); assert(reg1 != REG_ZERO); assert(id->idCodeSize() == 2 * sizeof(code_t)); From 397de617988850c6e6afcb519badc9c8f4705edf Mon Sep 17 00:00:00 2001 From: Maxim Menshikov Date: Tue, 5 May 2026 13:36:02 +0100 Subject: [PATCH 5/9] Support more relocations Signed-off-by: Maxim Menshikov --- patches/bflat-runtime/20_splitcodedata.patch | 51 ++++++++++++++------ 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/patches/bflat-runtime/20_splitcodedata.patch b/patches/bflat-runtime/20_splitcodedata.patch index 65825a7..d67ad72 100644 --- a/patches/bflat-runtime/20_splitcodedata.patch +++ b/patches/bflat-runtime/20_splitcodedata.patch @@ -68,10 +68,10 @@ index 9df0a0c29e5..b05bfbe99c6 100644 void Compiler::eeReserveUnwindInfo(bool isFunclet, bool isColdCode, ULONG unwindSize) diff --git a/src/coreclr/jit/emitriscv64.cpp b/src/coreclr/jit/emitriscv64.cpp -index c0c80413a33..6fe308d3993 100644 +index c0c80413a33..95c29054bbb 100644 --- a/src/coreclr/jit/emitriscv64.cpp +++ b/src/coreclr/jit/emitriscv64.cpp -@@ -1045,9 +1045,13 @@ void emitter::emitIns_R_C( +@@ -1045,9 +1045,14 @@ void emitter::emitIns_R_C( id->idOpSize(EA_PTRSIZE); } @@ -82,13 +82,14 @@ index c0c80413a33..6fe308d3993 100644 + // eeAllocMem) and therefore knew the exact code→roData distance at + // emit time. We now keep roData as a separate AOT blob (.rodata + // section) so the distance is only resolved at link time. Do NOT mark -+ // the instr as bound — emitOutputInstr_OptsRc will leave the auipc -+ // immediate at zero and record an IMAGE_REL_RISCV64_PC relocation -+ // against the roData symbol. ++ // the instr as bound — emitOutputInstr_OptsRc will leave both the ++ // auipc and addi/ld immediates at zero and record paired ++ // IMAGE_REL_RISCV64_PCREL_HI20 / IMAGE_REL_RISCV64_PCREL_LO12_I ++ // relocations against the roData symbol. assert(addrReg == REG_NA); // NOTE: for RISV64, not support addrReg != REG_NA. -@@ -2990,7 +2994,17 @@ BYTE* emitter::emitOutputInstr_OptsReloc(BYTE* dst, const instrDesc* id, instruc +@@ -2990,7 +2995,17 @@ BYTE* emitter::emitOutputInstr_OptsReloc(BYTE* dst, const instrDesc* id, instruc dst += emitOutput_ITypeInstr(dst, *ins, reg1, reg1, 0); @@ -107,7 +108,7 @@ index c0c80413a33..6fe308d3993 100644 return dst; } -@@ -3008,13 +3022,21 @@ BYTE* emitter::emitOutputInstr_OptsRc(BYTE* dst, const instrDesc* id, instructio +@@ -3008,13 +3023,21 @@ BYTE* emitter::emitOutputInstr_OptsRc(BYTE* dst, const instrDesc* id, instructio const regNumber reg1 = id->idReg1(); assert(reg1 != REG_ZERO); assert(id->idCodeSize() == 2 * sizeof(code_t)); @@ -297,10 +298,15 @@ index e6fd0d4f7f8..b4d486a2727 100644 Debug.Fail("Invalid RelocType: " + fRelocType); return 0; diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/ElfObjectWriter.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/ElfObjectWriter.cs -index 5204eb587c6..cc0b7943f7f 100644 +index 5204eb587c6..033f8841da0 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/ElfObjectWriter.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/ElfObjectWriter.cs -@@ -561,6 +561,8 @@ private void EmitRelocationsRiscV64(int sectionIndex, List r +@@ -557,10 +557,13 @@ private void EmitRelocationsRiscV64(int sectionIndex, List r + uint symbolIndex = _symbolNameToIndex[symbolicRelocation.SymbolName]; + uint type = symbolicRelocation.Type switch + { ++ IMAGE_REL_BASED_ABSOLUTE => R_RISCV_NONE, + IMAGE_REL_BASED_DIR64 => R_RISCV_64, IMAGE_REL_BASED_HIGHLOW => R_RISCV_32, IMAGE_REL_BASED_RELPTR32 => R_RISCV_32_PCREL, IMAGE_REL_BASED_RISCV64_PC => R_RISCV_CALL_PLT, @@ -379,21 +385,36 @@ index e878cd59d82..8f51e019435 100644 break; } diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp -index 74bab557b44..b6de7b09843 100644 +index 74bab557b44..9e20e17ca96 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp -@@ -11930,6 +11930,17 @@ void CEEJitInfo::recordRelocation(void * location, +@@ -11930,6 +11930,32 @@ void CEEJitInfo::recordRelocation(void * location, } break; + case IMAGE_REL_RISCV64_PCREL_HI20: ++ { ++ // Patch the auipc upper-20 immediate. The matching LO12_I ++ // reloc patches the following addi/ld independently. The ++ // displacement (target - auipc_PC) is rounded by +0x800 so ++ // that the signed 12-bit LO12 immediate produces the correct ++ // sum after auipc sign-extends the upper 20. ++ _ASSERTE(addlDelta == 0); ++ INT64 offset = (INT64)target - (INT64)location; ++ UINT32 *p = (UINT32 *)locationRW; ++ *p = (*p & 0x00000fffu) | (UINT32)((offset + 0x800) & 0xfffff000u); ++ } ++ break; ++ + case IMAGE_REL_RISCV64_PCREL_LO12_I: + { -+ // Paired pc-relative relocs are only used by the AOT compiler, -+ // where they are resolved at link time. The runtime JIT keeps -+ // code+roData adjacent, so it never needs to patch a partial -+ // half here. Treat as no-op so VM doesn't assert. ++ // Patch the addi/ld imm[11:0]. The auipc is 4 bytes before ++ // this location; recompute the displacement from there so it ++ // matches the auipc's HI20 calculation exactly. + _ASSERTE(addlDelta == 0); ++ INT64 offset = (INT64)target - (INT64)((BYTE*)location - 4); ++ UINT32 *p = (UINT32 *)locationRW; ++ *p = (*p & 0x000fffffu) | (UINT32)((offset & 0xfff) << 20); + } + break; + From 73ccfbf7a50529b9e5c22aeaf1b453aba0e85b7d Mon Sep 17 00:00:00 2001 From: Maxim Menshikov Date: Tue, 5 May 2026 23:07:05 +0100 Subject: [PATCH 6/9] Update code and data patch Signed-off-by: Maxim Menshikov --- patches/bflat-runtime/20_splitcodedata.patch | 99 ++++++++++++++------ 1 file changed, 68 insertions(+), 31 deletions(-) diff --git a/patches/bflat-runtime/20_splitcodedata.patch b/patches/bflat-runtime/20_splitcodedata.patch index d67ad72..a5b2ba0 100644 --- a/patches/bflat-runtime/20_splitcodedata.patch +++ b/patches/bflat-runtime/20_splitcodedata.patch @@ -1,8 +1,7 @@ diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h -index b0d0108a31d..e39b0a6a571 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h -@@ -3407,6 +3407,12 @@ public: +@@ -3407,6 +3407,12 @@ // RISCV64 relocation types // #define IMAGE_REL_RISCV64_PC 0x0003 @@ -16,10 +15,9 @@ index b0d0108a31d..e39b0a6a571 100644 /**********************************************************************************/ #ifdef TARGET_64BIT diff --git a/src/coreclr/jit/ee_il_dll.cpp b/src/coreclr/jit/ee_il_dll.cpp -index 9df0a0c29e5..b05bfbe99c6 100644 --- a/src/coreclr/jit/ee_il_dll.cpp +++ b/src/coreclr/jit/ee_il_dll.cpp -@@ -1140,7 +1140,13 @@ void Compiler::eeAllocMem(AllocMemArgs* args, const UNATIVE_OFFSET roDataSection +@@ -1140,7 +1140,13 @@ #endif // DEBUG @@ -34,7 +32,7 @@ index 9df0a0c29e5..b05bfbe99c6 100644 // For arm64/LoongArch64/RISCV64, we want to allocate JIT data always adjacent to code similar to what native // compiler does. -@@ -1157,7 +1163,7 @@ void Compiler::eeAllocMem(AllocMemArgs* args, const UNATIVE_OFFSET roDataSection +@@ -1157,7 +1163,7 @@ args->hotCodeSize = roDataOffset + args->roDataSize; args->roDataSize = 0; @@ -43,7 +41,7 @@ index 9df0a0c29e5..b05bfbe99c6 100644 info.compCompHnd->allocMem(args); -@@ -1174,7 +1180,13 @@ void Compiler::eeAllocMem(AllocMemArgs* args, const UNATIVE_OFFSET roDataSection +@@ -1174,7 +1180,13 @@ #endif // DEBUG @@ -58,7 +56,7 @@ index 9df0a0c29e5..b05bfbe99c6 100644 // Fix up data section pointers. assert(args->roDataBlock == nullptr); -@@ -1182,7 +1194,7 @@ void Compiler::eeAllocMem(AllocMemArgs* args, const UNATIVE_OFFSET roDataSection +@@ -1182,7 +1194,7 @@ args->roDataBlock = ((BYTE*)args->hotCodeBlock) + roDataOffset; args->roDataBlockRW = ((BYTE*)args->hotCodeBlockRW) + roDataOffset; @@ -68,10 +66,9 @@ index 9df0a0c29e5..b05bfbe99c6 100644 void Compiler::eeReserveUnwindInfo(bool isFunclet, bool isColdCode, ULONG unwindSize) diff --git a/src/coreclr/jit/emitriscv64.cpp b/src/coreclr/jit/emitriscv64.cpp -index c0c80413a33..95c29054bbb 100644 --- a/src/coreclr/jit/emitriscv64.cpp +++ b/src/coreclr/jit/emitriscv64.cpp -@@ -1045,9 +1045,14 @@ void emitter::emitIns_R_C( +@@ -1045,9 +1045,14 @@ id->idOpSize(EA_PTRSIZE); } @@ -89,7 +86,7 @@ index c0c80413a33..95c29054bbb 100644 assert(addrReg == REG_NA); // NOTE: for RISV64, not support addrReg != REG_NA. -@@ -2990,7 +2995,17 @@ BYTE* emitter::emitOutputInstr_OptsReloc(BYTE* dst, const instrDesc* id, instruc +@@ -3016,7 +3021,17 @@ dst += emitOutput_ITypeInstr(dst, *ins, reg1, reg1, 0); @@ -108,7 +105,7 @@ index c0c80413a33..95c29054bbb 100644 return dst; } -@@ -3008,13 +3023,21 @@ BYTE* emitter::emitOutputInstr_OptsRc(BYTE* dst, const instrDesc* id, instructio +@@ -3034,13 +3049,21 @@ const regNumber reg1 = id->idReg1(); assert(reg1 != REG_ZERO); assert(id->idCodeSize() == 2 * sizeof(code_t)); @@ -136,10 +133,9 @@ index c0c80413a33..95c29054bbb 100644 } diff --git a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/ObjectDataBuilder.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/ObjectDataBuilder.cs -index 53e4671b57a..84ab0407493 100644 --- a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/ObjectDataBuilder.cs +++ b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/ObjectDataBuilder.cs -@@ -301,6 +301,8 @@ public void EmitReloc(ISymbolNode symbol, RelocType relocType, int delta = 0) +@@ -301,6 +301,8 @@ case RelocType.IMAGE_REL_BASED_LOONGARCH64_JIR: case RelocType.IMAGE_REL_BASED_RISCV64_PC: @@ -149,10 +145,9 @@ index 53e4671b57a..84ab0407493 100644 // Do not vacate space for this kind of relocation, because // the space is embedded in the instruction. diff --git a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs -index 91991a6882e..37755f42fd6 100644 --- a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs +++ b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs -@@ -30,6 +30,14 @@ public enum RelocType +@@ -30,6 +30,14 @@ IMAGE_REL_BASED_ARM64_PAGEOFFSET_12A = 0x82, // ADD/ADDS (immediate) with zero shift, for page offset IMAGE_REL_BASED_ARM64_PAGEOFFSET_12L = 0x83, // LDR (indexed, unsigned immediate), for page offset @@ -167,7 +162,7 @@ index 91991a6882e..37755f42fd6 100644 // // Relocation operators related to TLS access // -@@ -488,6 +496,58 @@ private static unsafe void PutRiscV64PC(uint* pCode, long imm32) +@@ -488,6 +496,58 @@ Debug.Assert(GetRiscV64PC(pCode) == imm32); } @@ -226,7 +221,7 @@ index 91991a6882e..37755f42fd6 100644 public Relocation(RelocType relocType, int offset, ISymbolNode target) { RelocType = relocType; -@@ -548,6 +608,12 @@ public static unsafe void WriteValue(RelocType relocType, void* location, long v +@@ -548,6 +608,12 @@ case RelocType.IMAGE_REL_BASED_RISCV64_PC: PutRiscV64PC((uint*)location, value); break; @@ -239,7 +234,7 @@ index 91991a6882e..37755f42fd6 100644 default: Debug.Fail("Invalid RelocType: " + relocType); break; -@@ -615,6 +681,10 @@ public static unsafe long ReadValue(RelocType relocType, void* location) +@@ -615,6 +681,10 @@ return (long)GetLoongArch64JIR((uint*)location); case RelocType.IMAGE_REL_BASED_RISCV64_PC: return (long)GetRiscV64PC((uint*)location); @@ -251,10 +246,9 @@ index 91991a6882e..37755f42fd6 100644 Debug.Fail("Invalid RelocType: " + relocType); return 0; diff --git a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Target_RiscV64/RiscV64Emitter.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Target_RiscV64/RiscV64Emitter.cs -index 380163ed2fb..b89e07fc3b8 100644 --- a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Target_RiscV64/RiscV64Emitter.cs +++ b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Target_RiscV64/RiscV64Emitter.cs -@@ -43,10 +43,17 @@ public void EmitMOV(Register regDst, Register regSrc) +@@ -43,10 +43,17 @@ public void EmitMOV(Register regDst, ISymbolNode symbol) { @@ -276,10 +270,9 @@ index 380163ed2fb..b89e07fc3b8 100644 } diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs -index e6fd0d4f7f8..b4d486a2727 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs -@@ -4050,11 +4050,17 @@ private static RelocType GetRelocType(TargetArchitecture targetArchitecture, ush +@@ -4050,11 +4050,17 @@ case TargetArchitecture.RiscV64: { const ushort IMAGE_REL_RISCV64_PC = 3; @@ -298,10 +291,57 @@ index e6fd0d4f7f8..b4d486a2727 100644 Debug.Fail("Invalid RelocType: " + fRelocType); return 0; diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/ElfObjectWriter.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/ElfObjectWriter.cs -index 5204eb587c6..033f8841da0 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/ElfObjectWriter.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/ElfObjectWriter.cs -@@ -557,10 +557,13 @@ private void EmitRelocationsRiscV64(int sectionIndex, List r +@@ -45,6 +45,14 @@ + // Symbol table + private readonly Dictionary _symbolNameToIndex = new(); + ++ // Local labels emitted at every R_RISCV_PCREL_HI20 site so the matching ++ // R_RISCV_PCREL_LO12_I can reference them. lld and GNU ld implement the ++ // RISC-V psABI's "the LO12 reloc's symbol must point at the auipc that ++ // owns the matching HI20" rule strictly; targeting the data symbol ++ // directly with the LO12 reloc produces "without an associated ++ // R_RISCV_PCREL_HI20" link errors. ++ private readonly HashSet _riscv64PcrelHiLabels = new(StringComparer.Ordinal); ++ + private Dictionary _armUnwindSections; + private static readonly ObjectNodeSection ArmUnwindIndexSection = new ObjectNodeSection(".ARM.exidx", SectionType.UnwindData); + private static readonly ObjectNodeSection ArmUnwindTableSection = new ObjectNodeSection(".ARM.extab", SectionType.ReadOnly); +@@ -250,6 +258,32 @@ + } + } + ++ if (_machine == EM_RISCV) ++ { ++ if (relocType == IMAGE_REL_BASED_RISCV64_PCREL_HI20) ++ { ++ // Emit a local STT_NOTYPE label at this auipc PC. The ++ // matching LO12_I reloc will reference this label rather ++ // than the data target, satisfying the linker's pairing ++ // requirement. ++ string label = $".LRISCVPCRELHI_{sectionIndex}_{offset:x}"; ++ if (_riscv64PcrelHiLabels.Add(label)) ++ { ++ EmitSymbolDefinition(sectionIndex, label, offset); ++ } ++ } ++ else if (relocType == IMAGE_REL_BASED_RISCV64_PCREL_LO12_I) ++ { ++ // Retarget the LO12_I to the local label at the matching ++ // auipc (4 bytes earlier in the same section). The linker ++ // walks back to that label to find the HI20 reloc whose ++ // S+A-P determines the displacement; LO12 is then the ++ // lower 12 bits of that displacement. ++ symbolName = $".LRISCVPCRELHI_{sectionIndex}_{(offset - 4):x}"; ++ addend = 0; ++ } ++ } ++ + base.EmitRelocation(sectionIndex, offset, data, relocType, symbolName, addend); + } + +@@ -557,10 +591,13 @@ uint symbolIndex = _symbolNameToIndex[symbolicRelocation.SymbolName]; uint type = symbolicRelocation.Type switch { @@ -316,10 +356,9 @@ index 5204eb587c6..033f8841da0 100644 }; diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/RelocationHelper.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/RelocationHelper.cs -index 6a2501482ab..1c1e48fbe37 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/RelocationHelper.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/RelocationHelper.cs -@@ -240,6 +240,27 @@ public void ProcessRelocation(RelocType relocationType, int sourceRVA, int targe +@@ -240,6 +240,27 @@ break; } @@ -347,7 +386,7 @@ index 6a2501482ab..1c1e48fbe37 100644 default: throw new NotSupportedException(); } -@@ -253,6 +274,13 @@ public void ProcessRelocation(RelocType relocationType, int sourceRVA, int targe +@@ -253,6 +274,13 @@ { long value = Relocation.ReadValue(relocationType, bufferContent); // Supporting non-zero values for ARM64 would require refactoring this function @@ -362,10 +401,9 @@ index 6a2501482ab..1c1e48fbe37 100644 (relocationType == RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12A) || (relocationType == RelocType.IMAGE_REL_BASED_LOONGARCH64_PC) || diff --git a/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp b/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp -index e878cd59d82..8f51e019435 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp -@@ -926,6 +926,18 @@ void CompileResult::applyRelocs(RelocContext* rc, unsigned char* block1, ULONG b +@@ -926,6 +926,18 @@ } break; @@ -385,10 +423,9 @@ index e878cd59d82..8f51e019435 100644 break; } diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp -index 74bab557b44..9e20e17ca96 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp -@@ -11930,6 +11930,32 @@ void CEEJitInfo::recordRelocation(void * location, +@@ -11930,6 +11930,32 @@ } break; From 461ff7e07eb81a417dac4230e6db62f05e684803 Mon Sep 17 00:00:00 2001 From: Maxim Menshikov Date: Sun, 10 May 2026 19:36:26 +0100 Subject: [PATCH 7/9] Fix addend Signed-off-by: Maxim Menshikov --- patches/bflat-runtime/21_pcrel_addend.patch | 73 +++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 patches/bflat-runtime/21_pcrel_addend.patch diff --git a/patches/bflat-runtime/21_pcrel_addend.patch b/patches/bflat-runtime/21_pcrel_addend.patch new file mode 100644 index 0000000..9172bcb --- /dev/null +++ b/patches/bflat-runtime/21_pcrel_addend.patch @@ -0,0 +1,73 @@ +diff --git a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs +--- a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs ++++ b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs +@@ -81,6 +81,7 @@ + public readonly RelocType RelocType; + public readonly int Offset; + public readonly ISymbolNode Target; ++ public readonly int Addend; + + //***************************************************************************** + // Extract the 16-bit immediate from ARM Thumb2 Instruction (format T2_N) +@@ -554,10 +555,16 @@ + } + + public Relocation(RelocType relocType, int offset, ISymbolNode target) ++ : this(relocType, offset, target, 0) ++ { ++ } ++ ++ public Relocation(RelocType relocType, int offset, ISymbolNode target, int addend) + { + RelocType = relocType; + Offset = offset; + Target = target; ++ Addend = addend; + } + + public static unsafe void WriteValue(RelocType relocType, void* location, long value) +diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs ++++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +@@ -4133,12 +4133,26 @@ + + TargetArchitecture targetArchitecture = _compilation.TypeSystemContext.Target.Architecture; + RelocType relocType = GetRelocType(targetArchitecture, fRelocType); +- // relocDelta is stored as the value +- Relocation.WriteValue(relocType, location, relocDelta); ++ ++ // RISC-V64 paired PC-relative data relocations cannot round-trip ++ // addends through the auipc U-imm (it can only encode values ++ // aligned to 4 KiB). Carry the addend explicitly via the ++ // Relocation record instead of patching it into the instruction. ++ int relocAddend = 0; ++ if (relocType == RelocType.IMAGE_REL_BASED_RISCV64_PCREL_HI20 || ++ relocType == RelocType.IMAGE_REL_BASED_RISCV64_PCREL_LO12_I) ++ { ++ relocAddend = relocDelta; ++ } ++ else ++ { ++ // relocDelta is stored as the value ++ Relocation.WriteValue(relocType, location, relocDelta); ++ } + + if (sourceBlock.Count == 0) + sourceBlock.EnsureCapacity(length / 32 + 1); +- sourceBlock.Add(new Relocation(relocType, relocOffset, relocTarget)); ++ sourceBlock.Add(new Relocation(relocType, relocOffset, relocTarget, relocAddend)); + } + + private ushort getRelocTypeHint(void* target) +diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/ObjectWriter.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/ObjectWriter.cs +--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/ObjectWriter.cs ++++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/ObjectWriter.cs +@@ -488,7 +488,7 @@ + blockToRelocate.Data.AsSpan(reloc.Offset), + reloc.RelocType, + relocSymbolName, +- relocTarget.Offset); ++ relocTarget.Offset + reloc.Addend); + + if (_options.HasFlag(ObjectWritingOptions.ControlFlowGuard) && + relocTarget is IMethodNode or AssemblyStubNode or AddressTakenExternFunctionSymbolNode) From 3e0e1a79f9bd8aae054da7df9a862609fa233f85 Mon Sep 17 00:00:00 2001 From: Maxim Menshikov Date: Sat, 16 May 2026 22:06:35 +0100 Subject: [PATCH 8/9] Add patch to fix interface dispatch Signed-off-by: Maxim Menshikov --- patches/bflat-runtime/22_stubdispatch.patch | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 patches/bflat-runtime/22_stubdispatch.patch diff --git a/patches/bflat-runtime/22_stubdispatch.patch b/patches/bflat-runtime/22_stubdispatch.patch new file mode 100644 index 0000000..c681da7 --- /dev/null +++ b/patches/bflat-runtime/22_stubdispatch.patch @@ -0,0 +1,15 @@ +diff --git a/src/coreclr/runtime/riscv64/StubDispatch.S b/src/coreclr/runtime/riscv64/StubDispatch.S +index 01ddd05a0fe..265b6d2cbd1 100644 +--- a/src/coreclr/runtime/riscv64/StubDispatch.S ++++ b/src/coreclr/runtime/riscv64/StubDispatch.S +@@ -107,7 +107,9 @@ + // t1: parameter of the thunk's target + PREPARE_EXTERNAL_VAR RhpCidResolve, t0 + mv t1, t5 +- tail C_FUNC(RhpUniversalTransitionTailCall) ++1: ++ auipc t2, %pcrel_hi(C_FUNC(RhpUniversalTransitionTailCall)) ++ jalr x0, t2, %pcrel_lo(1b) + LEAF_END RhpInterfaceDispatchSlow, _TEXT + + #endif // FEATURE_CACHED_INTERFACE_DISPATCH From 1e6289080d6188fb2e7eedcb4882c0c77f537f99 Mon Sep 17 00:00:00 2001 From: Maxim Menshikov Date: Sat, 16 May 2026 22:18:21 +0100 Subject: [PATCH 9/9] Update interface dispatch patch Signed-off-by: Maxim Menshikov --- patches/bflat-runtime/22_stubdispatch.patch | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/patches/bflat-runtime/22_stubdispatch.patch b/patches/bflat-runtime/22_stubdispatch.patch index c681da7..db46099 100644 --- a/patches/bflat-runtime/22_stubdispatch.patch +++ b/patches/bflat-runtime/22_stubdispatch.patch @@ -1,14 +1,14 @@ diff --git a/src/coreclr/runtime/riscv64/StubDispatch.S b/src/coreclr/runtime/riscv64/StubDispatch.S -index 01ddd05a0fe..265b6d2cbd1 100644 +index 4dafc370c95..c855e20f244 100644 --- a/src/coreclr/runtime/riscv64/StubDispatch.S +++ b/src/coreclr/runtime/riscv64/StubDispatch.S @@ -107,7 +107,9 @@ // t1: parameter of the thunk's target PREPARE_EXTERNAL_VAR RhpCidResolve, t0 mv t1, t5 -- tail C_FUNC(RhpUniversalTransitionTailCall) +- tail C_FUNC(RhpUniversalTransition_DebugStepTailCall) +1: -+ auipc t2, %pcrel_hi(C_FUNC(RhpUniversalTransitionTailCall)) ++ auipc t2, %pcrel_hi(C_FUNC(RhpUniversalTransition_DebugStepTailCall)) + jalr x0, t2, %pcrel_lo(1b) LEAF_END RhpInterfaceDispatchSlow, _TEXT