Skip to content

Commit e9db531

Browse files
jtschusterCopilot
andcommitted
Add WebCIL / WASM container support to the structural R2R reader
Port the runtime's WebcilImageReader (from dotnet/runtime#128423) to the standalone structural ReadyToRun reader, implementing IPlatformBinaryReader for raw .webcil images and WebCIL payloads embedded in WASM modules. - Wasm/WasmMachine.cs: Wasm32 = (Machine)0xFFFE placeholder machine value. - Webcil/WebcilFormat.cs: Webcil header/section structs and constants. - Webcil/WebcilImageReader.cs: header/section parsing, RVA->offset translation, R2R header location via the COR header ManagedNativeHeaderDirectory, pinned MetadataReader access, and WASM-wrapper detection (passive data segment scan). The r2rdump-only WASM disassembly helpers are intentionally omitted. - ReadyToRunReader.TargetPointerSize maps Wasm32 -> 4. - R2RAssertions.CreateCore detects WebCIL/WASM and selects the new reader. Regression tests build minimal hand-constructed WebCIL R2R images (raw and WASM-wrapped, v0 and v1 headers, single- and two-section layouts) and cover detection, machine/pointer size, header/section parsing, exact RVA byte mapping, ECMA-335 metadata reads, decoy WASM segments, and malformed-input error paths. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent cb09ba0 commit e9db531

7 files changed

Lines changed: 1196 additions & 0 deletions

File tree

src/ILCompiler.Reflection.ReadyToRun.Structural.Assertions/R2RAssertions.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,18 @@ private static R2RAssertions CreateCore(byte[] imageBytes, string filename, stri
7474
{
7575
bool isMachO = imageBytes.Length >= 4
7676
&& imageBytes[0] == 0xCF && imageBytes[1] == 0xFA && imageBytes[2] == 0xED && imageBytes[3] == 0xFE;
77+
bool isWebcil = !isMachO && Webcil.WebcilImageReader.IsWebcilImage(imageBytes);
7778

7879
PEReader peReader = null;
7980
IPlatformBinaryReader imageReader;
8081
if (isMachO)
8182
{
8283
imageReader = new MachO.MachOImageReader(imageBytes);
8384
}
85+
else if (isWebcil)
86+
{
87+
imageReader = new Webcil.WebcilImageReader(imageBytes);
88+
}
8489
else
8590
{
8691
peReader = new PEReader(new MemoryStream(imageBytes));

src/ILCompiler.Reflection.ReadyToRun.Structural/ReadyToRunReader.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ public int TargetPointerSize
8181
{
8282
Machine.I386 or Machine.Arm or Machine.Thumb or Machine.ArmThumb2 => 4,
8383
Machine.Amd64 or Machine.Arm64 or Machine.LoongArch64 or Machine.RiscV64 => 8,
84+
WasmMachine.Wasm32 => 4,
8485
_ => throw new NotImplementedException(Machine.ToString()),
8586
};
8687
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Reflection.PortableExecutable;
5+
6+
namespace System.Reflection.Metadata.ReadyToRun
7+
{
8+
/// <summary>
9+
/// WebAssembly does not have a dedicated <see cref="Machine"/> value, so ReadyToRun images
10+
/// produced for wasm targets use a placeholder. This mirrors <c>WasmMachine.Wasm32</c> in the
11+
/// runtime's <c>ILCompiler.Reflection.ReadyToRun</c>.
12+
/// </summary>
13+
public static class WasmMachine
14+
{
15+
/// <summary>Placeholder <see cref="Machine"/> value used for 32-bit WebAssembly images.</summary>
16+
public const Machine Wasm32 = (Machine)0xFFFE;
17+
}
18+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace System.Reflection.Metadata.ReadyToRun.Webcil
5+
{
6+
/// <summary>
7+
/// Constants describing the Webcil container format.
8+
/// Mirrors <c>WebcilConstants</c> in <c>src/coreclr/tools/Common/Wasm/Webcil.cs</c>.
9+
/// </summary>
10+
internal static class WebcilConstants
11+
{
12+
public const int WC_VERSION_MAJOR = 1;
13+
public const int WC_VERSION_MINOR = 0;
14+
15+
/// <summary>
16+
/// 'WbIL' magic bytes interpreted as a little-endian uint32.
17+
/// </summary>
18+
public const uint WEBCIL_MAGIC = 0x4c496257;
19+
20+
/// <summary>Size of a v0 Webcil header in bytes.</summary>
21+
public const int V0HeaderSize = 28;
22+
23+
/// <summary>Size of a v1 Webcil header in bytes (adds <see cref="WebcilHeader.TableBase"/>).</summary>
24+
public const int V1HeaderSize = 32;
25+
26+
/// <summary>Size of a single Webcil section header in bytes.</summary>
27+
public const int SectionHeaderSize = 16;
28+
}
29+
30+
/// <summary>
31+
/// The header of a Webcil file. The header is a subset of the PE, COFF and CLI headers that are
32+
/// needed by the runtime to load managed assemblies.
33+
/// Mirrors <c>WebcilHeader</c> in <c>src/coreclr/tools/Common/Wasm/Webcil.cs</c>.
34+
/// </summary>
35+
internal struct WebcilHeader
36+
{
37+
public uint Id;
38+
public ushort VersionMajor;
39+
public ushort VersionMinor;
40+
41+
public ushort CoffSections;
42+
#pragma warning disable CS0649 // Reserved0 mirrors the on-disk layout but is never read.
43+
public ushort Reserved0;
44+
#pragma warning restore CS0649
45+
46+
public uint PeCliHeaderRva;
47+
public uint PeCliHeaderSize;
48+
49+
public uint PeDebugRva;
50+
public uint PeDebugSize;
51+
52+
// Present only in v1 headers.
53+
public uint TableBase;
54+
}
55+
56+
/// <summary>
57+
/// Represents a section header in a Webcil file. This is the Webcil analog of
58+
/// <see cref="System.Reflection.PortableExecutable.SectionHeader"/>, but with fewer fields.
59+
/// </summary>
60+
internal readonly struct WebcilSectionHeader
61+
{
62+
public readonly uint VirtualSize;
63+
public readonly uint VirtualAddress;
64+
public readonly uint SizeOfRawData;
65+
public readonly uint PointerToRawData;
66+
67+
public WebcilSectionHeader(uint virtualSize, uint virtualAddress, uint sizeOfRawData, uint pointerToRawData)
68+
{
69+
VirtualSize = virtualSize;
70+
VirtualAddress = virtualAddress;
71+
SizeOfRawData = sizeOfRawData;
72+
PointerToRawData = pointerToRawData;
73+
}
74+
}
75+
}

0 commit comments

Comments
 (0)