diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 6af4f84172a6be..319aaeb23d82cb 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 861c9bbd7bbe55..912c17928b6e27 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 @@ -654,8 +657,15 @@ 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: + *(uint*)location = checked((uint)value); + return; + case RelocType.WASM_TABLE_INDEX_I64: + *(ulong*)location = checked((ulong)value); + return; default: Debug.Fail("Invalid RelocType: " + relocType); @@ -696,8 +706,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(), }; @@ -760,8 +771,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 @@ -771,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/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); diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs index 36c1c8462cf11e..91aa2abedd1c09 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)); } @@ -811,14 +810,44 @@ 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_SLEB: + case RelocType.WASM_MEMORY_ADDR_REL_SLEB: { - // WASM-TODO actually implement this + // These relocs should be for cases of the form: + // global.get __image_base + // i32.const + // i32.add + // 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 + if (symbolWebcilSection is null) + { + throw new InvalidDataException(); + } + + Relocation.WriteValue(reloc.Type, pData, virtualSymbolImageOffset + addend); break; } - case RelocType.WASM_TABLE_INDEX_U32: + case RelocType.WASM_TABLE_INDEX_I32: + case RelocType.WASM_TABLE_INDEX_I64: + case RelocType.WASM_TABLE_INDEX_SLEB: { - // WASM-TODO actually implement this + string symbolName = reloc.SymbolName.ToString(); + 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 + Relocation.WriteValue(reloc.Type, pData, index); + break; + } + case RelocType.WASM_FUNCTION_INDEX_LEB: + { + string symbolName = reloc.SymbolName.ToString(); + 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 + Relocation.WriteValue(reloc.Type, pData, index); break; } default: 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..9969f75ef2db0b 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) {