From bb981448876132fad047af543dc95aad4ca2b5c5 Mon Sep 17 00:00:00 2001 From: adamperlin Date: Fri, 27 Mar 2026 13:37:35 -0700 Subject: [PATCH 01/15] Implement relocation resolution for WASM_MEMORY_ADDR, WASM_TABLE_INDEX, WASM_FUNCTION_INDEX type relocs --- .../Compiler/DependencyAnalysis/Relocation.cs | 6 +++ .../Compiler/ObjectWriter/WasmObjectWriter.cs | 53 ++++++++++++++----- 2 files changed, 47 insertions(+), 12 deletions(-) diff --git a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs index 861c9bbd7bbe55..1375f67ef98f6a 100644 --- a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs +++ b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs @@ -656,6 +656,12 @@ public static unsafe void WriteValue(RelocType relocType, void* location, long v case RelocType.WASM_MEMORY_ADDR_SLEB: DwarfHelper.WritePaddedSLEB128(new Span((byte*)location, WASM_PADDED_RELOC_SIZE_32), value); return; + case RelocType.WASM_TABLE_INDEX_U32: + *(uint*)location = checked((uint)value); + return; + case RelocType.WASM_TABLE_INDEX_U64: + *(ulong*)location = checked((ulong)value); + return; default: Debug.Fail("Invalid RelocType: " + relocType); diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs index 36c1c8462cf11e..0334b7b4eaa0a5 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs @@ -714,18 +714,18 @@ private unsafe void ResolveRelocations(int sectionIndex, MemoryStream sectionStr { byte[] relocScratchBuffer = new byte[Relocation.MaxSize]; - WebcilSection? webcilSection = null; + WebcilSection? curSectionAsWebcil = null; uint webcilVirtualStart = 0; if (_sections[sectionIndex] is WebcilSection curSection) { - webcilSection = curSection; + curSectionAsWebcil = curSection; webcilVirtualStart = curSection.Header.VirtualAddress; } // If we have a webcil section, we expect it to have a nonzero section start. This is because for webcil, // we should have written the webcil header and each of the section headers (always non-zero size) before any // section contents - Debug.Assert(webcilSection is null || sectionStart != 0); + Debug.Assert(curSectionAsWebcil is null || sectionStart != 0); foreach (SymbolicRelocation reloc in relocs) { @@ -739,23 +739,22 @@ private unsafe void ResolveRelocations(int sectionIndex, MemoryStream sectionStr // The virtual address of the relocation we are resolving uint virtualRelocOffset = 0; + if (curSectionAsWebcil is not null) + { + virtualRelocOffset = webcilVirtualStart + (uint)reloc.Offset; + Debug.Assert(IsWithinSection(virtualRelocOffset, curSectionAsWebcil)); + } // The virtual address of the symbol this relocation refers to uint virtualSymbolImageOffset = 0; - WebcilSection? symbolWebcilSection = null; // TODO-Wasm: Enforce the below boolean as an assert once we are emitting proper Wasm code // relocs for all code containing nodes // ---> bool betweenWebcilSections = false; - if (webcilSection is not null && _sections[definedSymbol.SectionIndex] is WebcilSection targetSection) + if (_sections[definedSymbol.SectionIndex] is WebcilSection targetSection) { - // ---> betweenWebcilSections = true; symbolWebcilSection = targetSection; - - virtualRelocOffset = webcilVirtualStart + (uint)reloc.Offset; - Debug.Assert(IsWithinSection(virtualRelocOffset, webcilSection)); - virtualSymbolImageOffset = symbolWebcilSection.Header.VirtualAddress + (uint)definedSymbol.Value; Debug.Assert(IsWithinSection(virtualSymbolImageOffset, symbolWebcilSection)); } @@ -813,12 +812,42 @@ private unsafe void ResolveRelocations(int sectionIndex, MemoryStream sectionStr break; case RelocType.WASM_MEMORY_ADDR_SLEB: { - // WASM-TODO actually implement this + // These relocs should be for cases of the form: + // global.get __image_base + // i32.const + // i32.add + // so reloc represents an offset relative to image base. + Relocation.WriteValue(reloc.Type, pData, virtualSymbolImageOffset); break; } case RelocType.WASM_TABLE_INDEX_U32: + case RelocType.WASM_TABLE_INDEX_U64: + case RelocType.WASM_TABLE_INDEX_SLEB: + { + if (_uniqueSymbols.TryGetValue(reloc.SymbolName.ToString(), out int index)) + { + // Here, we are effectively writing a table offset relative to the table_base. + // These will need to be fixed up by the runtime after load by adding __image_function_pointer_base + Relocation.WriteValue(reloc.Type, pData, index); + } + else + { + throw new InvalidDataException($"Table index for signature symbol definition '{reloc.SymbolName}' not found"); + } + break; + } + case RelocType.WASM_FUNCTION_INDEX_LEB: { - // WASM-TODO actually implement this + if (_uniqueSymbols.TryGetValue(reloc.SymbolName.ToString(), out int index)) + { + // These are module-local function pointer indices, so we can simply write out the assigned function index + // for this particular symbol + Relocation.WriteValue(reloc.Type, pData, index); + } + else + { + throw new InvalidDataException($"Table index for signature symbol definition '{reloc.SymbolName}' not found"); + } break; } default: From 2c5e0a6704cc154ed2fd45d6853b8b2ae37983ae Mon Sep 17 00:00:00 2001 From: adamperlin Date: Fri, 27 Mar 2026 13:52:57 -0700 Subject: [PATCH 02/15] Add TODO --- .../tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs index 0334b7b4eaa0a5..a97b2ca2106d02 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs @@ -828,6 +828,7 @@ private unsafe void ResolveRelocations(int sectionIndex, MemoryStream sectionStr { // Here, we are effectively writing a table offset relative to the table_base. // These will need to be fixed up by the runtime after load by adding __image_function_pointer_base + // TODO-WASM: We need to emit these for fixup with an addend at runtime Relocation.WriteValue(reloc.Type, pData, index); } else From 6ef5a194e2c2c7a909960a7471ff4470a36fc479 Mon Sep 17 00:00:00 2001 From: adamperlin Date: Fri, 27 Mar 2026 13:56:50 -0700 Subject: [PATCH 03/15] Remove exceptions in favor of asserts --- .../Compiler/ObjectWriter/WasmObjectWriter.cs | 34 +++++++------------ 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs index a97b2ca2106d02..b034587288c3b1 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs @@ -817,6 +817,7 @@ private unsafe void ResolveRelocations(int sectionIndex, MemoryStream sectionStr // i32.const // i32.add // so reloc represents an offset relative to image base. + Debug.Assert(virtualSymbolImageOffset != 0); Relocation.WriteValue(reloc.Type, pData, virtualSymbolImageOffset); break; } @@ -824,31 +825,22 @@ private unsafe void ResolveRelocations(int sectionIndex, MemoryStream sectionStr case RelocType.WASM_TABLE_INDEX_U64: case RelocType.WASM_TABLE_INDEX_SLEB: { - if (_uniqueSymbols.TryGetValue(reloc.SymbolName.ToString(), out int index)) - { - // Here, we are effectively writing a table offset relative to the table_base. - // These will need to be fixed up by the runtime after load by adding __image_function_pointer_base - // TODO-WASM: We need to emit these for fixup with an addend at runtime - Relocation.WriteValue(reloc.Type, pData, index); - } - else - { - throw new InvalidDataException($"Table index for signature symbol definition '{reloc.SymbolName}' not found"); - } + bool exists = _uniqueSymbols.TryGetValue(reloc.SymbolName.ToString(), out int index); + Debug.Assert(exists, $"Table index for signature symbol definition '{reloc.SymbolName}' not found"); + + // Here, we are effectively writing a table offset relative to the table_base. + // These will need to be fixed up by the runtime after load by adding __image_function_pointer_base + // TODO-WASM: We need to emit these for fixup with an addend at runtime + Relocation.WriteValue(reloc.Type, pData, index); break; } case RelocType.WASM_FUNCTION_INDEX_LEB: { - if (_uniqueSymbols.TryGetValue(reloc.SymbolName.ToString(), out int index)) - { - // These are module-local function pointer indices, so we can simply write out the assigned function index - // for this particular symbol - Relocation.WriteValue(reloc.Type, pData, index); - } - else - { - throw new InvalidDataException($"Table index for signature symbol definition '{reloc.SymbolName}' not found"); - } + bool exists = _uniqueSymbols.TryGetValue(reloc.SymbolName.ToString(), out int index); + Debug.Assert(exists, $"Table index for signature symbol definition '{reloc.SymbolName}' not found"); + // These are module-local function pointer indices, so we can simply write out the assigned function index + // for this particular symbol + Relocation.WriteValue(reloc.Type, pData, index); break; } default: From 89ebe362c3e10dfbb980af045a2a4046557d548e Mon Sep 17 00:00:00 2001 From: adamperlin Date: Fri, 27 Mar 2026 14:33:42 -0700 Subject: [PATCH 04/15] Also handle WASM_MEMORY_ADDR_LEB and add additional comment --- .../tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs index b034587288c3b1..7be1b724ef901f 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs @@ -810,13 +810,18 @@ private unsafe void ResolveRelocations(int sectionIndex, MemoryStream sectionStr long fileOffset = symbolWebcilSection.Header.PointerToRawData + definedSymbol.Value; Relocation.WriteValue(reloc.Type, pData, fileOffset + addend); break; + case RelocType.WASM_MEMORY_ADDR_LEB: case RelocType.WASM_MEMORY_ADDR_SLEB: { // These relocs should be for cases of the form: // global.get __image_base // i32.const // i32.add - // so reloc represents an offset relative to image base. + // i32.load 0 + // OR: + // global.get __image_base + // i32.load memidx=<>, + // So, the relocated address value should always represent an offset relative to image base. Debug.Assert(virtualSymbolImageOffset != 0); Relocation.WriteValue(reloc.Type, pData, virtualSymbolImageOffset); break; From 67f4dc7ec27156a125714c668534220f45050026 Mon Sep 17 00:00:00 2001 From: adamperlin Date: Fri, 27 Mar 2026 15:19:35 -0700 Subject: [PATCH 05/15] Additional comment --- .../tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs index 7be1b724ef901f..db2a3aa332c1cb 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs @@ -822,6 +822,8 @@ private unsafe void ResolveRelocations(int sectionIndex, MemoryStream sectionStr // global.get __image_base // i32.load memidx=<>, // So, the relocated address value should always represent an offset relative to image base. + // This offset should ALWAYS be equal to the actual offset from image base at runtime, due to Webcil's + // flag mapping Debug.Assert(virtualSymbolImageOffset != 0); Relocation.WriteValue(reloc.Type, pData, virtualSymbolImageOffset); break; From fbd857386a3b1bc1502dfebcb34fe5e79a70f929 Mon Sep 17 00:00:00 2001 From: adamperlin Date: Fri, 27 Mar 2026 15:26:31 -0700 Subject: [PATCH 06/15] Fix missed accounting for addend in RelocType.WASM_MEMORY_ADDR relocs --- .../tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs index db2a3aa332c1cb..53b9ae8e78ffdd 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs @@ -825,7 +825,7 @@ private unsafe void ResolveRelocations(int sectionIndex, MemoryStream sectionStr // This offset should ALWAYS be equal to the actual offset from image base at runtime, due to Webcil's // flag mapping Debug.Assert(virtualSymbolImageOffset != 0); - Relocation.WriteValue(reloc.Type, pData, virtualSymbolImageOffset); + Relocation.WriteValue(reloc.Type, pData, virtualSymbolImageOffset + addend); break; } case RelocType.WASM_TABLE_INDEX_U32: From ab7a7cc2b2cd117140c1aae6a64b3e37304c48e6 Mon Sep 17 00:00:00 2001 From: adamperlin Date: Mon, 30 Mar 2026 10:29:42 -0700 Subject: [PATCH 07/15] Address some review feedback; Change ADDR_SLEB -> ADDR_REL_SLEB to make relocation intent clearer. Also, rename relocs to be more in line with Wasm linking conventions. --- src/coreclr/inc/corinfo.h | 2 ++ src/coreclr/jit/emitwasm.cpp | 4 +++- .../DependencyAnalysis/ObjectDataBuilder.cs | 2 +- .../Compiler/DependencyAnalysis/Relocation.cs | 24 +++++++++++-------- .../Compiler/ObjectWriter/WasmObjectWriter.cs | 7 +++--- .../tools/Common/JitInterface/CorInfoImpl.cs | 1 + .../tools/Common/JitInterface/CorInfoTypes.cs | 2 ++ .../WasmImportThunkPortableEntrypoint.cs | 2 +- 8 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 6af4f84172a6be..7cc5561660a5d1 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -924,6 +924,8 @@ enum class CorInfoReloc // e.g. directly loading from or storing to a C++ global. WASM_MEMORY_ADDR_SLEB, // Wasm: a linear memory index encoded as a 5-byte varint32. Used for the immediate argument of a i32.const instruction, // e.g. taking the address of a C++ global. + WASM_MEMORY_ADDR_REL_SLEB, // Wasm: a relative linear memory index encoded as a 5-byte varint32. Used as the immediate argument of an i32.const instruction, + // e.g. in R2R scenarios as an offset from __image__base WASM_TYPE_INDEX_LEB, // Wasm: a type index encoded as a 5-byte varuint32, e.g. the type immediate in a call_indirect. WASM_GLOBAL_INDEX_LEB, // Wasm: a global index encoded as a 5-byte varuint32, e.g. the index immediate in a get_global. }; diff --git a/src/coreclr/jit/emitwasm.cpp b/src/coreclr/jit/emitwasm.cpp index 9beaee4dc17bdb..3969bce7a529af 100644 --- a/src/coreclr/jit/emitwasm.cpp +++ b/src/coreclr/jit/emitwasm.cpp @@ -721,7 +721,9 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp) case IF_MEMADDR: { dst += emitOutputOpcode(dst, ins); - dst += emitOutputConstant(dst, id, SIGNED, CorInfoReloc::WASM_MEMORY_ADDR_SLEB); + // TODO-WASM: The below reloc we're emitting here is specific to R2R and assumes the address we want + // is an offset from __image_base + dst += emitOutputConstant(dst, id, SIGNED, CorInfoReloc::WASM_MEMORY_ADDR_REL_SLEB); break; } case IF_FUNCPTR: diff --git a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/ObjectDataBuilder.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/ObjectDataBuilder.cs index 21e33900f0c76b..6018d69f5dda0e 100644 --- a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/ObjectDataBuilder.cs +++ b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/ObjectDataBuilder.cs @@ -267,7 +267,7 @@ public void EmitReloc(ISymbolNode symbol, RelocType relocType, int delta = 0) // And add space for the reloc switch (relocType) { - case RelocType.WASM_TABLE_INDEX_U32: + case RelocType.WASM_TABLE_INDEX_I32: case RelocType.IMAGE_REL_BASED_REL32: case RelocType.IMAGE_REL_BASED_RELPTR32: case RelocType.IMAGE_REL_BASED_ABSOLUTE: diff --git a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs index 1375f67ef98f6a..99b8f96614aff1 100644 --- a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs +++ b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs @@ -47,11 +47,14 @@ public enum RelocType // e.g. directly loading from or storing to a C++ global. WASM_MEMORY_ADDR_SLEB = 0x203, // Wasm: a linear memory index encoded as a 5-byte varint32. Used for the immediate argument of a i32.const instruction, // e.g. taking the address of a C++ global. - WASM_TYPE_INDEX_LEB = 0x204, // Wasm: a type index encoded as a 5-byte varuint32, e.g. the type immediate in a call_indirect. - WASM_GLOBAL_INDEX_LEB = 0x205, // Wasm: a global index encoded as a 5-byte varuint32, e.g. the index immediate in a get_global. + WASM_MEMORY_ADDR_REL_SLEB = 0x204, // Wasm: a relative linear memory index encoded as a 5-byte varint32. Used as the immediate argument of an i32.const instruction, + // e.g. in R2R scenarios, encoding an offset from __image__base + WASM_TYPE_INDEX_LEB = 0x205, // Wasm: a type index encoded as a 5-byte varuint32, e.g. the type immediate in a call_indirect. - WASM_TABLE_INDEX_U32 = 0x206, // Wasm: a table index encoded as a 4-byte uint32, e.g. for storing the "address" of a function into linear memory - WASM_TABLE_INDEX_U64 = 0x207, // Wasm: a table index encoded as a 8-byte uint64, e.g. for storing the "address" of a function into linear memory + WASM_GLOBAL_INDEX_LEB = 0x206, // Wasm: a global index encoded as a 5-byte varuint32, e.g. the index immediate in a get_global. + + WASM_TABLE_INDEX_I32 = 0x207, // Wasm: a table index encoded as a 4-byte uint32, e.g. for storing the "address" of a function into linear memory + WASM_TABLE_INDEX_I64 = 0x208, // Wasm: a table index encoded as a 8-byte uint64, e.g. for storing the "address" of a function into linear memory // // Relocation operators related to TLS access @@ -656,10 +659,10 @@ public static unsafe void WriteValue(RelocType relocType, void* location, long v case RelocType.WASM_MEMORY_ADDR_SLEB: DwarfHelper.WritePaddedSLEB128(new Span((byte*)location, WASM_PADDED_RELOC_SIZE_32), value); return; - case RelocType.WASM_TABLE_INDEX_U32: + case RelocType.WASM_TABLE_INDEX_I32: *(uint*)location = checked((uint)value); return; - case RelocType.WASM_TABLE_INDEX_U64: + case RelocType.WASM_TABLE_INDEX_I64: *(ulong*)location = checked((ulong)value); return; @@ -702,8 +705,9 @@ public static int GetSize(RelocType relocType) RelocType.WASM_GLOBAL_INDEX_LEB => WASM_PADDED_RELOC_SIZE_32, RelocType.WASM_MEMORY_ADDR_LEB => WASM_PADDED_RELOC_SIZE_32, RelocType.WASM_MEMORY_ADDR_SLEB => WASM_PADDED_RELOC_SIZE_32, - RelocType.WASM_TABLE_INDEX_U32 => 4, - RelocType.WASM_TABLE_INDEX_U64 => 8, + RelocType.WASM_MEMORY_ADDR_REL_SLEB => WASM_PADDED_RELOC_SIZE_32, + RelocType.WASM_TABLE_INDEX_I32 => 4, + RelocType.WASM_TABLE_INDEX_I64 => 8, _ => throw new NotSupportedException(), }; @@ -766,8 +770,8 @@ public static unsafe long ReadValue(RelocType relocType, void* location) return GetRiscV64AuipcCombo((uint*)location, isStype); case RelocType.WASM_FUNCTION_INDEX_LEB: case RelocType.WASM_TABLE_INDEX_SLEB: - case RelocType.WASM_TABLE_INDEX_U32: - case RelocType.WASM_TABLE_INDEX_U64: + case RelocType.WASM_TABLE_INDEX_I32: + case RelocType.WASM_TABLE_INDEX_I64: case RelocType.WASM_TYPE_INDEX_LEB: case RelocType.WASM_GLOBAL_INDEX_LEB: // These wasm relocs do not have offsets, just targets diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs index 53b9ae8e78ffdd..4e592239ce045a 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs @@ -810,8 +810,7 @@ private unsafe void ResolveRelocations(int sectionIndex, MemoryStream sectionStr long fileOffset = symbolWebcilSection.Header.PointerToRawData + definedSymbol.Value; Relocation.WriteValue(reloc.Type, pData, fileOffset + addend); break; - case RelocType.WASM_MEMORY_ADDR_LEB: - case RelocType.WASM_MEMORY_ADDR_SLEB: + case RelocType.WASM_MEMORY_ADDR_REL_SLEB: { // These relocs should be for cases of the form: // global.get __image_base @@ -828,8 +827,8 @@ private unsafe void ResolveRelocations(int sectionIndex, MemoryStream sectionStr Relocation.WriteValue(reloc.Type, pData, virtualSymbolImageOffset + addend); break; } - case RelocType.WASM_TABLE_INDEX_U32: - case RelocType.WASM_TABLE_INDEX_U64: + case RelocType.WASM_TABLE_INDEX_I32: + case RelocType.WASM_TABLE_INDEX_I64: case RelocType.WASM_TABLE_INDEX_SLEB: { bool exists = _uniqueSymbols.TryGetValue(reloc.SymbolName.ToString(), out int index); diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index a8d0f13e5cde23..593240475b501a 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -4250,6 +4250,7 @@ private RelocType GetRelocType(CorInfoReloc reloc) CorInfoReloc.WASM_TABLE_INDEX_SLEB => RelocType.WASM_TABLE_INDEX_SLEB, CorInfoReloc.WASM_MEMORY_ADDR_LEB => RelocType.WASM_MEMORY_ADDR_LEB, CorInfoReloc.WASM_MEMORY_ADDR_SLEB => RelocType.WASM_MEMORY_ADDR_SLEB, + CorInfoReloc.WASM_MEMORY_ADDR_REL_SLEB => RelocType.WASM_MEMORY_ADDR_REL_SLEB, CorInfoReloc.WASM_TYPE_INDEX_LEB => RelocType.WASM_TYPE_INDEX_LEB, CorInfoReloc.WASM_GLOBAL_INDEX_LEB => RelocType.WASM_GLOBAL_INDEX_LEB, _ => throw new ArgumentException("Unsupported relocation type: " + reloc), diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index 718fde04a9a65b..50c5f4bf448b0c 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -514,6 +514,8 @@ public enum CorInfoReloc // e.g. directly loading from or storing to a C++ global. WASM_MEMORY_ADDR_SLEB, // Wasm: a linear memory index encoded as a 5-byte varint32. Used for the immediate argument of a i32.const instruction, // e.g. taking the address of a C++ global. + WASM_MEMORY_ADDR_REL_SLEB, // Wasm: a relative linear memory index encoded as a 5-byte varint32. Used as the immediate argument of an i32.const instruction, + // e.g. in R2R scenarios, encoding an offset from __image__base WASM_TYPE_INDEX_LEB, // Wasm: a type index encoded as a 5-byte varuint32, e.g. the type immediate in a call_indirect. WASM_GLOBAL_INDEX_LEB, // Wasm: a global index encoded as a 5-byte varuint32, e.g. the index immediate in a get_global. } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/WasmImportThunkPortableEntrypoint.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/WasmImportThunkPortableEntrypoint.cs index 7cb42b327e4f19..3a0faf084a0d38 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/WasmImportThunkPortableEntrypoint.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/WasmImportThunkPortableEntrypoint.cs @@ -64,7 +64,7 @@ public override ObjectData GetData(NodeFactory factory, System.Boolean relocsOnl builder.AddSymbol(this); WasmTypeNode typeNode; - RelocType tableIndexPointerRelocType = factory.Target.PointerSize == 4 ? RelocType.WASM_TABLE_INDEX_U32 : RelocType.WASM_TABLE_INDEX_U64; + RelocType tableIndexPointerRelocType = factory.Target.PointerSize == 4 ? RelocType.WASM_TABLE_INDEX_I32 : RelocType.WASM_TABLE_INDEX_I64; if (_import.Signature is GenericLookupSignature) { From 807114ccdf1ffd4158e80959e33d9f053ab322dd Mon Sep 17 00:00:00 2001 From: adamperlin Date: Mon, 30 Mar 2026 11:01:58 -0700 Subject: [PATCH 08/15] Address PR review feedback: replace Debug.Assert with proper throws using localizable error messages - Replace Debug.Assert with deterministic throws for WASM_TABLE_INDEX, WASM_FUNCTION_INDEX_LEB, and WASM_MEMORY_ADDR_REL_SLEB relocation lookups so Release builds fail explicitly instead of silently emitting incorrect values. - Fix WASM_FUNCTION_INDEX_LEB error message to say 'Function index' instead of 'Table index'. - Validate symbolWebcilSection is not null (not virtualSymbolImageOffset != 0) for WASM_MEMORY_ADDR_REL_SLEB since offset 0 can be valid. - Cache reloc.SymbolName.ToString() in a local to avoid repeated allocations per relocation. - Add Resources.resx to ILCompiler.ReadyToRun for localizable error messages, following the crossgen2 SR pattern. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Compiler/DependencyAnalysis/Relocation.cs | 2 + .../Compiler/ObjectWriter/WasmObjectWriter.cs | 26 ++-- .../ILCompiler.ReadyToRun.csproj | 7 + .../Properties/Resources.resx | 129 ++++++++++++++++++ 4 files changed, 155 insertions(+), 9 deletions(-) create mode 100644 src/coreclr/tools/aot/ILCompiler.ReadyToRun/Properties/Resources.resx diff --git a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs index 99b8f96614aff1..11f65253869e8a 100644 --- a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs +++ b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs @@ -657,6 +657,7 @@ public static unsafe void WriteValue(RelocType relocType, void* location, long v case RelocType.WASM_TABLE_INDEX_SLEB: case RelocType.WASM_MEMORY_ADDR_SLEB: + case RelocType.WASM_MEMORY_ADDR_REL_SLEB: DwarfHelper.WritePaddedSLEB128(new Span((byte*)location, WASM_PADDED_RELOC_SIZE_32), value); return; case RelocType.WASM_TABLE_INDEX_I32: @@ -781,6 +782,7 @@ public static unsafe long ReadValue(RelocType relocType, void* location) return checked((long)DwarfHelper.ReadULEB128(new ReadOnlySpan(location, WASM_PADDED_RELOC_SIZE_32))); case RelocType.WASM_MEMORY_ADDR_SLEB: + case RelocType.WASM_MEMORY_ADDR_REL_SLEB: return DwarfHelper.ReadSLEB128(new ReadOnlySpan(location, WASM_PADDED_RELOC_SIZE_32)); default: diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs index 4e592239ce045a..a911f77de4bfeb 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs @@ -816,14 +816,15 @@ private unsafe void ResolveRelocations(int sectionIndex, MemoryStream sectionStr // global.get __image_base // i32.const // i32.add - // i32.load 0 - // OR: - // global.get __image_base - // i32.load memidx=<>, + // i32.load 0 // So, the relocated address value should always represent an offset relative to image base. // This offset should ALWAYS be equal to the actual offset from image base at runtime, due to Webcil's // flag mapping - Debug.Assert(virtualSymbolImageOffset != 0); + if (symbolWebcilSection is null) + { + throw new InvalidDataException(string.Format(SR.WasmMemoryRelocTargetNotInWebcilSection, reloc.SymbolName)); + } + Relocation.WriteValue(reloc.Type, pData, virtualSymbolImageOffset + addend); break; } @@ -831,8 +832,11 @@ private unsafe void ResolveRelocations(int sectionIndex, MemoryStream sectionStr case RelocType.WASM_TABLE_INDEX_I64: case RelocType.WASM_TABLE_INDEX_SLEB: { - bool exists = _uniqueSymbols.TryGetValue(reloc.SymbolName.ToString(), out int index); - Debug.Assert(exists, $"Table index for signature symbol definition '{reloc.SymbolName}' not found"); + string symbolName = reloc.SymbolName.ToString(); + if (!_uniqueSymbols.TryGetValue(symbolName, out int index)) + { + throw new InvalidOperationException(string.Format(SR.WasmTableIndexSymbolNotFound, symbolName)); + } // Here, we are effectively writing a table offset relative to the table_base. // These will need to be fixed up by the runtime after load by adding __image_function_pointer_base @@ -842,8 +846,12 @@ private unsafe void ResolveRelocations(int sectionIndex, MemoryStream sectionStr } case RelocType.WASM_FUNCTION_INDEX_LEB: { - bool exists = _uniqueSymbols.TryGetValue(reloc.SymbolName.ToString(), out int index); - Debug.Assert(exists, $"Table index for signature symbol definition '{reloc.SymbolName}' not found"); + string symbolName = reloc.SymbolName.ToString(); + if (!_uniqueSymbols.TryGetValue(symbolName, out int index)) + { + throw new InvalidOperationException(string.Format(SR.WasmFunctionIndexSymbolNotFound, symbolName)); + } + // These are module-local function pointer indices, so we can simply write out the assigned function index // for this particular symbol Relocation.WriteValue(reloc.Type, pData, index); diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj index e021d5d7afc985..a50c4a55f9ef1a 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj @@ -20,6 +20,13 @@ $(NoWarn);CS8524 + + + true + System.SR + + + diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Properties/Resources.resx b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Properties/Resources.resx new file mode 100644 index 00000000000000..d475844840ea93 --- /dev/null +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Properties/Resources.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + WASM memory address relocation target '{0}' did not resolve into a Webcil section + + + Table index for symbol definition '{0}' not found + + + Function index for symbol definition '{0}' not found + + From 892a7e3b26cc880fe7fe609c9e3f66503e52927c Mon Sep 17 00:00:00 2001 From: adamperlin Date: Mon, 30 Mar 2026 12:11:48 -0700 Subject: [PATCH 09/15] Update emitted RVA reloc in WasmInstructions.cs to use REL type reloc --- .../tools/Common/Compiler/ObjectWriter/WasmInstructions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmInstructions.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmInstructions.cs index f584cbe68cc574..a95c2bdb96e1e7 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmInstructions.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmInstructions.cs @@ -415,7 +415,7 @@ public override int Encode(Span buffer) break; case RelocType.WASM_TABLE_INDEX_SLEB: - case RelocType.WASM_MEMORY_ADDR_SLEB: + case RelocType.WASM_MEMORY_ADDR_REL_SLEB: DwarfHelper.WritePaddedSLEB128(buffer.Slice(pos, relocSize), 0); break; @@ -566,7 +566,7 @@ public static WasmExpr Const(long value) } public static WasmExpr ConstRVA(ISymbolNode symbolNode) { - return new WasmLEBConstantReloc(WasmExprKind.I32Const, symbolNode, RelocType.WASM_MEMORY_ADDR_SLEB); + return new WasmLEBConstantReloc(WasmExprKind.I32Const, symbolNode, RelocType.WASM_MEMORY_ADDR_REL_SLEB); } public static WasmExpr Add => new WasmBinaryExpr(WasmExprKind.I32Add); From 484744ef7e4e36183bafcf19f33f6096db5ce227 Mon Sep 17 00:00:00 2001 From: Adam Perlin Date: Mon, 30 Mar 2026 12:12:37 -0700 Subject: [PATCH 10/15] Update src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index 50c5f4bf448b0c..9969f75ef2db0b 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -515,7 +515,7 @@ public enum CorInfoReloc WASM_MEMORY_ADDR_SLEB, // Wasm: a linear memory index encoded as a 5-byte varint32. Used for the immediate argument of a i32.const instruction, // e.g. taking the address of a C++ global. WASM_MEMORY_ADDR_REL_SLEB, // Wasm: a relative linear memory index encoded as a 5-byte varint32. Used as the immediate argument of an i32.const instruction, - // e.g. in R2R scenarios, encoding an offset from __image__base + // e.g. in R2R scenarios, encoding an offset from __image_base WASM_TYPE_INDEX_LEB, // Wasm: a type index encoded as a 5-byte varuint32, e.g. the type immediate in a call_indirect. WASM_GLOBAL_INDEX_LEB, // Wasm: a global index encoded as a 5-byte varuint32, e.g. the index immediate in a get_global. } From c195c26c381c3fcbaf1e4a6762a35ee50084655a Mon Sep 17 00:00:00 2001 From: Adam Perlin Date: Mon, 30 Mar 2026 12:12:46 -0700 Subject: [PATCH 11/15] Update src/coreclr/inc/corinfo.h Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/coreclr/inc/corinfo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 7cc5561660a5d1..319aaeb23d82cb 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -925,7 +925,7 @@ enum class CorInfoReloc WASM_MEMORY_ADDR_SLEB, // Wasm: a linear memory index encoded as a 5-byte varint32. Used for the immediate argument of a i32.const instruction, // e.g. taking the address of a C++ global. WASM_MEMORY_ADDR_REL_SLEB, // Wasm: a relative linear memory index encoded as a 5-byte varint32. Used as the immediate argument of an i32.const instruction, - // e.g. in R2R scenarios as an offset from __image__base + // e.g. in R2R scenarios as an offset from __image_base WASM_TYPE_INDEX_LEB, // Wasm: a type index encoded as a 5-byte varuint32, e.g. the type immediate in a call_indirect. WASM_GLOBAL_INDEX_LEB, // Wasm: a global index encoded as a 5-byte varuint32, e.g. the index immediate in a get_global. }; From ef71e7931b6d23d4d8893a30d1cdd41ae3e383cf Mon Sep 17 00:00:00 2001 From: Adam Perlin Date: Mon, 30 Mar 2026 12:12:54 -0700 Subject: [PATCH 12/15] Update src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../tools/Common/Compiler/DependencyAnalysis/Relocation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs index 11f65253869e8a..912c17928b6e27 100644 --- a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs +++ b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs @@ -48,7 +48,7 @@ public enum RelocType WASM_MEMORY_ADDR_SLEB = 0x203, // Wasm: a linear memory index encoded as a 5-byte varint32. Used for the immediate argument of a i32.const instruction, // e.g. taking the address of a C++ global. WASM_MEMORY_ADDR_REL_SLEB = 0x204, // Wasm: a relative linear memory index encoded as a 5-byte varint32. Used as the immediate argument of an i32.const instruction, - // e.g. in R2R scenarios, encoding an offset from __image__base + // e.g. in R2R scenarios, encoding an offset from __image_base WASM_TYPE_INDEX_LEB = 0x205, // Wasm: a type index encoded as a 5-byte varuint32, e.g. the type immediate in a call_indirect. WASM_GLOBAL_INDEX_LEB = 0x206, // Wasm: a global index encoded as a 5-byte varuint32, e.g. the index immediate in a get_global. From cdaf2ea4b829825fe4b62c74485e576c8f0c4ff4 Mon Sep 17 00:00:00 2001 From: adamperlin Date: Mon, 30 Mar 2026 15:48:30 -0700 Subject: [PATCH 13/15] Remove resources file and localized error messages in WasmObjectWriter --- .../Compiler/ObjectWriter/WasmObjectWriter.cs | 6 +- .../Properties/Resources.resx | 129 ------------------ 2 files changed, 3 insertions(+), 132 deletions(-) delete mode 100644 src/coreclr/tools/aot/ILCompiler.ReadyToRun/Properties/Resources.resx diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs index a911f77de4bfeb..ff288651cb0a4a 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs @@ -822,7 +822,7 @@ private unsafe void ResolveRelocations(int sectionIndex, MemoryStream sectionStr // flag mapping if (symbolWebcilSection is null) { - throw new InvalidDataException(string.Format(SR.WasmMemoryRelocTargetNotInWebcilSection, reloc.SymbolName)); + throw new InvalidDataException(); } Relocation.WriteValue(reloc.Type, pData, virtualSymbolImageOffset + addend); @@ -835,7 +835,7 @@ private unsafe void ResolveRelocations(int sectionIndex, MemoryStream sectionStr string symbolName = reloc.SymbolName.ToString(); if (!_uniqueSymbols.TryGetValue(symbolName, out int index)) { - throw new InvalidOperationException(string.Format(SR.WasmTableIndexSymbolNotFound, symbolName)); + throw new InvalidOperationException(); } // Here, we are effectively writing a table offset relative to the table_base. @@ -849,7 +849,7 @@ private unsafe void ResolveRelocations(int sectionIndex, MemoryStream sectionStr string symbolName = reloc.SymbolName.ToString(); if (!_uniqueSymbols.TryGetValue(symbolName, out int index)) { - throw new InvalidOperationException(string.Format(SR.WasmFunctionIndexSymbolNotFound, symbolName)); + throw new InvalidOperationException(); } // These are module-local function pointer indices, so we can simply write out the assigned function index diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Properties/Resources.resx b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Properties/Resources.resx deleted file mode 100644 index d475844840ea93..00000000000000 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Properties/Resources.resx +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - WASM memory address relocation target '{0}' did not resolve into a Webcil section - - - Table index for symbol definition '{0}' not found - - - Function index for symbol definition '{0}' not found - - From 71643cc34544d33a1fb5cd351523a6a31bd968b3 Mon Sep 17 00:00:00 2001 From: adamperlin Date: Mon, 30 Mar 2026 15:53:07 -0700 Subject: [PATCH 14/15] Revert changes to ILCompiler.ReadyToRun.csproj --- .../aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj index a50c4a55f9ef1a..e021d5d7afc985 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj @@ -20,13 +20,6 @@ $(NoWarn);CS8524 - - - true - System.SR - - - From eb8c89fb5e3e3e150881b9fb8a6fe18128c956ab Mon Sep 17 00:00:00 2001 From: adamperlin Date: Mon, 30 Mar 2026 16:38:37 -0700 Subject: [PATCH 15/15] Remove extra exception handling around lookup in _uniqueSymbols --- .../Common/Compiler/ObjectWriter/WasmObjectWriter.cs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs index ff288651cb0a4a..91aa2abedd1c09 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs @@ -833,11 +833,7 @@ private unsafe void ResolveRelocations(int sectionIndex, MemoryStream sectionStr case RelocType.WASM_TABLE_INDEX_SLEB: { string symbolName = reloc.SymbolName.ToString(); - if (!_uniqueSymbols.TryGetValue(symbolName, out int index)) - { - throw new InvalidOperationException(); - } - + int index = _uniqueSymbols[symbolName]; // Here, we are effectively writing a table offset relative to the table_base. // These will need to be fixed up by the runtime after load by adding __image_function_pointer_base // TODO-WASM: We need to emit these for fixup with an addend at runtime @@ -847,10 +843,7 @@ private unsafe void ResolveRelocations(int sectionIndex, MemoryStream sectionStr case RelocType.WASM_FUNCTION_INDEX_LEB: { string symbolName = reloc.SymbolName.ToString(); - if (!_uniqueSymbols.TryGetValue(symbolName, out int index)) - { - throw new InvalidOperationException(); - } + int index = _uniqueSymbols[symbolName]; // These are module-local function pointer indices, so we can simply write out the assigned function index // for this particular symbol