diff --git a/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunReader.cs b/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunReader.cs index 08b2faee48f947..6a2f549627ae38 100644 --- a/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunReader.cs +++ b/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunReader.cs @@ -1559,7 +1559,9 @@ private void EnsureImportSectionsImpl() for (int i = 0; i < entryCount; i++) { int entryOffset = sectionOffset - startOffset; - long section = ImageReader.ReadInt64(ref sectionOffset); + long section = entrySize == 4 + ? ImageReader.ReadInt32(ref sectionOffset) + : ImageReader.ReadInt64(ref sectionOffset); uint sigRva = ImageReader.ReadUInt32(ref signatureOffset); int sigOffset = GetOffset((int)sigRva); ReadyToRunSignature signature = MetadataNameFormatter.FormatSignature(_assemblyResolver, this, sigOffset); diff --git a/src/coreclr/tools/r2rdump/Program.cs b/src/coreclr/tools/r2rdump/Program.cs index 78467ba5bd81fb..deb9dd6c82ebe6 100644 --- a/src/coreclr/tools/r2rdump/Program.cs +++ b/src/coreclr/tools/r2rdump/Program.cs @@ -466,7 +466,7 @@ public int Run() // parse the ReadyToRun image ReadyToRunReader r2r = new(model, filename); r2r.ValidateDebugInfo = Get(_command.ValidateDebugInfo); - if (disasm) + if (disasm && !(r2r.CompositeReader is WebcilImageReader)) { disassembler = new Disassembler(r2r, model); } diff --git a/src/coreclr/tools/r2rdump/TextDumper.cs b/src/coreclr/tools/r2rdump/TextDumper.cs index 13d30dd36f337a..676cebce50a0ea 100644 --- a/src/coreclr/tools/r2rdump/TextDumper.cs +++ b/src/coreclr/tools/r2rdump/TextDumper.cs @@ -316,10 +316,19 @@ private void DumpWasmDisasm(RuntimeFunction rtf) } _writer.WriteLine(); - var disasm = new WasmDisassembler(info.Image, info.InstructionOffset, info.InstructionLength); + var disasm = new WasmDisassembler(info.Image, info.InstructionOffset, info.InstructionLength, TryGetImportName); _writer.Write(disasm.Disassemble()); } + private string TryGetImportName(int rva) + { + if (_r2r.ImportSignatures.TryGetValue(rva, out ReadyToRunSignature signature)) + { + return signature.ToString(_model.SignatureFormattingOptions); + } + return null; + } + private static IEnumerable FormatValTypes(IReadOnlyList types) { foreach (byte t in types) diff --git a/src/coreclr/tools/r2rdump/WasmDisassembler.cs b/src/coreclr/tools/r2rdump/WasmDisassembler.cs index bb492bbb36555d..7f005faf731c96 100644 --- a/src/coreclr/tools/r2rdump/WasmDisassembler.cs +++ b/src/coreclr/tools/r2rdump/WasmDisassembler.cs @@ -20,13 +20,21 @@ internal sealed class WasmDisassembler private int _offset; private readonly int _baseOffset; private readonly int _endOffset; + private readonly Func _rvaToName; - public WasmDisassembler(ImmutableArray code, int offset, int length) + /// + /// Tracks whether the previous instruction was a global.get of the imageBase global (index 1). + /// When true, the next i32.const or memory load offset should be treated as an RVA. + /// + private bool _prevWasImageBaseGet; + + public WasmDisassembler(ImmutableArray code, int offset, int length, Func rvaToName = null) { _code = code; _baseOffset = offset; _offset = offset; _endOffset = offset + length; + _rvaToName = rvaToName; } /// @@ -40,23 +48,37 @@ public string Disassemble() while (_offset < _endOffset) { int instrOffset = _offset - _baseOffset; - string instr = DecodeInstruction(ref indent, out int postAdjust); + string instr = DecodeInstruction(ref indent, out int postAdjust, out bool isImageBaseGet, out int rva); + + string annotation = null; + if (rva >= 0 && _prevWasImageBaseGet && _rvaToName is not null) + { + annotation = _rvaToName(rva); + } + _prevWasImageBaseGet = isImageBaseGet; sb.Append($" {instrOffset:X4}: "); if (indent > 0) { sb.Append(' ', indent * 2); } - sb.AppendLine(instr); + sb.Append(instr); + if (annotation is not null) + { + sb.Append($" // {annotation}"); + } + sb.AppendLine(); indent += postAdjust; } return sb.ToString(); } - private string DecodeInstruction(ref int indent, out int postAdjust) + private string DecodeInstruction(ref int indent, out int postAdjust, out bool isImageBaseGet, out int rva) { postAdjust = 0; + isImageBaseGet = false; + rva = -1; byte opcode = ReadByte(); switch (opcode) @@ -185,7 +207,12 @@ private string DecodeInstruction(ref int indent, out int postAdjust) case 0x20: return $"local.get {ReadU32()}"; case 0x21: return $"local.set {ReadU32()}"; case 0x22: return $"local.tee {ReadU32()}"; - case 0x23: return $"global.get {ReadU32()}"; + case 0x23: + { + uint globalIdx = ReadU32(); + isImageBaseGet = globalIdx == 1; + return $"global.get {globalIdx}"; + } case 0x24: return $"global.set {ReadU32()}"; // Table instructions @@ -193,7 +220,13 @@ private string DecodeInstruction(ref int indent, out int postAdjust) case 0x26: return $"table.set {ReadU32()}"; // Memory instructions - case 0x28: return $"i32.load {ReadMemArg()}"; + case 0x28: + { + string memArg = ReadMemArg(out uint offset); + if (offset != 0) + rva = (int)offset; + return $"i32.load {memArg}"; + } case 0x29: return $"i64.load {ReadMemArg()}"; case 0x2A: return $"f32.load {ReadMemArg()}"; case 0x2B: return $"f64.load {ReadMemArg()}"; @@ -228,7 +261,13 @@ private string DecodeInstruction(ref int indent, out int postAdjust) } // Numeric instructions - constants - case 0x41: return $"i32.const {ReadI32()}"; + case 0x41: + { + int val = ReadI32(); + if (val >= 0) + rva = val; + return $"i32.const {val}"; + } case 0x42: return $"i64.const {ReadI64()}"; case 0x43: return $"f32.const {ReadF32()}"; case 0x44: return $"f64.const {ReadF64()}"; @@ -939,6 +978,11 @@ private double ReadF64() } private string ReadMemArg() + { + return ReadMemArg(out _); + } + + private string ReadMemArg(out uint offset) { uint align = ReadU32(); // Bit 6 indicates multi-memory (memory index follows) @@ -948,7 +992,7 @@ private string ReadMemArg() align &= ~0x40u; memIdx = ReadU32(); } - uint offset = ReadU32(); + offset = ReadU32(); if (memIdx != 0) return $"align={1u << (int)align} offset={offset} mem={memIdx}"; if (offset != 0)