Skip to content

Commit fa39d85

Browse files
pavelsavaraCopilot
authored andcommitted
[browser][coreCLR] Loading WebCIL (#124904)
1 parent 94e4dff commit fa39d85

File tree

34 files changed

+2802
-478
lines changed

34 files changed

+2802
-478
lines changed

docs/design/datacontracts/Loader.md

Lines changed: 87 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ IReadOnlyDictionary<string, TargetPointer> GetLoaderAllocatorHeaps(TargetPointer
130130
| `PEImageLayout` | `Base` | Base address of the image layout |
131131
| `PEImageLayout` | `Size` | Size of the image layout |
132132
| `PEImageLayout` | `Flags` | Flags associated with the PEImageLayout |
133+
| `PEImageLayout` | `Format` | Format discriminator (PE or Webcil) for the image layout |
133134
| `CGrowableSymbolStream` | `Buffer` | Pointer to the raw symbol stream buffer start |
134135
| `CGrowableSymbolStream` | `Size` | Size of the raw symbol stream buffer |
135136
| `AppDomain` | `RootAssembly` | Pointer to the root assembly |
@@ -168,6 +169,11 @@ IReadOnlyDictionary<string, TargetPointer> GetLoaderAllocatorHeaps(TargetPointer
168169
| `DynamicILBlobTable` | `EntrySize` | Size of each table entry |
169170
| `DynamicILBlobTable` | `EntryMethodToken` | Offset of each entry method token from entry address |
170171
| `DynamicILBlobTable` | `EntryIL` | Offset of each entry IL from entry address |
172+
| `WebcilHeader` | `CoffSections` | Number of COFF sections in the Webcil image |
173+
| `WebcilSectionHeader` | `VirtualSize` | Virtual size of the section |
174+
| `WebcilSectionHeader` | `VirtualAddress` | RVA of the section |
175+
| `WebcilSectionHeader` | `SizeOfRawData` | Size of the section's raw data |
176+
| `WebcilSectionHeader` | `PointerToRawData` | File offset to the section's raw data |
171177

172178

173179

@@ -183,6 +189,7 @@ IReadOnlyDictionary<string, TargetPointer> GetLoaderAllocatorHeaps(TargetPointer
183189
| --- | --- | --- | --- |
184190
| `ASSEMBLY_NOTIFYFLAGS_PROFILER_NOTIFIED` | uint | Flag in Assembly NotifyFlags indicating the Assembly will notify profilers. | `0x1` |
185191
| `DefaultDomainFriendlyName` | string | Friendly name returned when `AppDomain.FriendlyName` is null (matches native `DEFAULT_DOMAIN_FRIENDLY_NAME`) | `"DefaultDomain"` |
192+
| `MaxWebcilSections` | ushort | Maximum number of COFF sections supported in a Webcil image (must stay in sync with native `WEBCIL_MAX_SECTIONS`) | `16` |
186193

187194
Contracts used:
188195
| Contract Name |
@@ -205,6 +212,13 @@ private enum PEImageFlags : uint
205212
{
206213
FLAG_MAPPED = 0x01, // the file is mapped/hydrated (vs. the raw disk layout)
207214
};
215+
216+
// Must stay in sync with native PEImageLayout::ImageFormat values.
217+
private enum ImageFormat : uint
218+
{
219+
PE = 0,
220+
Webcil = 1,
221+
}
208222
```
209223

210224
### Method Implementations
@@ -396,48 +410,90 @@ TargetPointer ILoader.GetILAddr(TargetPointer peAssemblyPtr, int rva)
396410
}
397411
else
398412
{
399-
// find NT headers using DOS header
400-
uint dosHeaderLfanew = target.Read<uint>(baseAddress + /* ImageDosHeader::LfanewOffset */);
401-
TargetPointer ntHeadersPtr = baseAddress + dosHeaderLfanew;
413+
offset = RvaToOffset(rva, peImageLayout);
414+
}
415+
return baseAddress + offset;
416+
}
402417

403-
TargetPointer optionalHeaderPtr = ntHeadersPtr + /* ImageNTHeaders::OptionalHeaderOffset */;
418+
uint RvaToOffset(int rva, Data.PEImageLayout imageLayout)
419+
{
420+
uint format = target.Read<uint>(imageLayout + /* PEImageLayout::Format offset */);
421+
if (format == (uint)ImageFormat.Webcil)
422+
return WebcilRvaToOffset(rva, imageLayout);
404423

405-
// Get number of sections from file header
406-
TargetPointer fileHeaderPtr = ntHeadersPtr + /* ImageNTHeaders::FileHeaderOffset */;
407-
uint numberOfSections = target.Read<uint>(fileHeaderPtr + /* ImageFileHeader::NumberOfSectionsOffset */);
424+
TargetPointer baseAddress = target.ReadPointer(imageLayout + /* PEImageLayout::Base offset */);
408425

409-
// Calculate first section address (after NT headers and optional header)
410-
uint imageFileHeaderSize = target.Read<ushort>(fileHeaderPtr + /* ImageFileHeader::SizeOfOptionalHeaderOffset */);
411-
TargetPointer firstSectionPtr = ntHeadersPtr + /* ImageNTHeaders::OptionalHeaderOffset */ + imageFileHeaderSize;
426+
// find NT headers using DOS header
427+
uint dosHeaderLfanew = target.Read<uint>(baseAddress + /* ImageDosHeader::LfanewOffset */);
428+
TargetPointer ntHeadersPtr = baseAddress + dosHeaderLfanew;
412429

413-
// Find the section containing this RVA
414-
TargetPointer sectionPtr = TargetPointer.Null;
415-
uint sectionHeaderSize = /* sizeof(ImageSectionHeader native struct) */;
430+
// Get number of sections from file header
431+
TargetPointer fileHeaderPtr = ntHeadersPtr + /* ImageNTHeaders::FileHeaderOffset */;
432+
uint numberOfSections = target.Read<uint>(fileHeaderPtr + /* ImageFileHeader::NumberOfSectionsOffset */);
416433

417-
for (uint i = 0; i < numberOfSections; i++)
418-
{
419-
TargetPointer currentSectionPtr = firstSectionPtr + (i * sectionHeaderSize);
420-
uint virtualAddress = target.Read<uint>(currentSectionPtr + /* ImageSectionHeader::VirtualAddressOffset */);
421-
uint sizeOfRawData = target.Read<uint>(currentSectionPtr + /* ImageSectionHeader::SizeOfRawDataOffset */);
434+
// Calculate first section address (after NT headers and optional header)
435+
uint imageFileHeaderSize = target.Read<ushort>(fileHeaderPtr + /* ImageFileHeader::SizeOfOptionalHeaderOffset */);
436+
TargetPointer firstSectionPtr = ntHeadersPtr + /* ImageNTHeaders::OptionalHeaderOffset */ + imageFileHeaderSize;
422437

423-
if (rva >= VirtualAddress && rva < VirtualAddress + SizeOfRawData)
424-
{
425-
sectionPtr = currentSectionPtr;
426-
}
427-
}
428-
if (sectionPtr == TargetPointer.Null)
438+
// Find the section containing this RVA
439+
TargetPointer sectionPtr = TargetPointer.Null;
440+
uint sectionHeaderSize = /* sizeof(ImageSectionHeader native struct) */;
441+
442+
for (uint i = 0; i < numberOfSections; i++)
443+
{
444+
TargetPointer currentSectionPtr = firstSectionPtr + (i * sectionHeaderSize);
445+
uint virtualAddress = target.Read<uint>(currentSectionPtr + /* ImageSectionHeader::VirtualAddressOffset */);
446+
uint sizeOfRawData = target.Read<uint>(currentSectionPtr + /* ImageSectionHeader::SizeOfRawDataOffset */);
447+
448+
if (rva >= virtualAddress && rva < virtualAddress + sizeOfRawData)
429449
{
430-
throw new InvalidOperationException("Failed to read from image.");
450+
sectionPtr = currentSectionPtr;
431451
}
432-
else
452+
}
453+
if (sectionPtr == TargetPointer.Null)
454+
{
455+
throw new InvalidOperationException("Failed to read from image.");
456+
}
457+
458+
// Convert RVA to file offset using section information
459+
uint sectionVirtualAddress = target.Read<uint>(sectionPtr + /* ImageSectionHeader::VirtualAddressOffset */);
460+
uint sectionPointerToRawData = target.Read<uint>(sectionPtr + /* ImageSectionHeader::PointerToRawDataOffset */);
461+
return (rva - sectionVirtualAddress) + sectionPointerToRawData;
462+
}
463+
464+
uint WebcilRvaToOffset(int rva, Data.PEImageLayout imageLayout)
465+
{
466+
if (rva < 0)
467+
throw new InvalidOperationException("Negative RVA in Webcil image.");
468+
469+
TargetPointer headerBase = imageLayout.Base;
470+
Data.WebcilHeader webcilHeader = // read WebcilHeader at headerBase
471+
uint webcilHeaderSize = /* sizeof(WebcilHeader) from type info */;
472+
uint webcilSectionSize = /* sizeof(WebcilSectionHeader) from type info */;
473+
474+
ushort numSections = webcilHeader.CoffSections;
475+
if (numSections == 0 || numSections > MaxWebcilSections)
476+
throw new InvalidOperationException("Invalid Webcil section count.");
477+
478+
TargetPointer sectionTableBase = headerBase + webcilHeaderSize;
479+
480+
for (int i = 0; i < numSections; i++)
481+
{
482+
TargetPointer sectionPtr = sectionTableBase + (uint)(i * (int)webcilSectionSize);
483+
Data.WebcilSectionHeader section = // read WebcilSectionHeader at sectionPtr
484+
485+
uint rvaUnsigned = (uint)rva;
486+
if (rvaUnsigned >= section.VirtualAddress)
433487
{
434-
// Convert RVA to file offset using section information
435-
uint sectionVirtualAddress = target.Read<uint>(sectionPtr + /* ImageSectionHeader::VirtualAddressOffset */);
436-
uint sectionPointerToRawData = target.Read<uint>(sectionPtr + /* ImageSectionHeader::PointerToRawDataOffset */);
437-
offset = ((rva - sectionVirtualAddress) + sectionPointerToRawData);
488+
uint offset = rvaUnsigned - section.VirtualAddress;
489+
if (offset < section.VirtualSize && offset < section.SizeOfRawData)
490+
{
491+
return offset + section.PointerToRawData;
492+
}
438493
}
439494
}
440-
return baseAddress + offset;
495+
496+
throw new InvalidOperationException("Failed to resolve RVA in Webcil image.");
441497
}
442498

443499
bool TryGetSymbolStream(ModuleHandle handle, out TargetPointer buffer, out uint size)

eng/testing/tests.browser.targets

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,9 @@
5959
<WasmTestLogExitCode>true</WasmTestLogExitCode>
6060
</PropertyGroup>
6161

62-
<!-- TODO-WASM https://github.com/dotnet/runtime/issues/120248 (CoreCLR on wasm defaults) -->
62+
<!-- TODO-WASM https://github.com/dotnet/runtime/issues/120226 (CoreCLR on wasm defaults) -->
6363
<PropertyGroup Condition="'$(RuntimeFlavor)' == 'CoreCLR'">
6464
<InvariantGlobalization Condition="'$(InvariantGlobalization)' == ''">false</InvariantGlobalization>
65-
<WasmEnableWebcil>false</WasmEnableWebcil>
6665
</PropertyGroup>
6766

6867
<ItemGroup>

src/coreclr/clrdefinitions.cmake

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,10 @@ if(FEATURE_OBJCMARSHAL)
148148
add_compile_definitions(FEATURE_OBJCMARSHAL)
149149
endif()
150150

151+
if(FEATURE_WEBCIL)
152+
add_compile_definitions(FEATURE_WEBCIL)
153+
endif()
154+
151155
add_compile_definitions($<${FEATURE_JAVAMARSHAL}:FEATURE_JAVAMARSHAL>)
152156

153157
add_compile_definitions($<$<NOT:$<BOOL:$<TARGET_PROPERTY:DAC_COMPONENT>>>:FEATURE_PROFAPI_ATTACH_DETACH>)

src/coreclr/clrfeatures.cmake

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ if(CLR_CMAKE_TARGET_ARCH_WASM)
4343
set(FEATURE_PORTABLE_HELPERS 1)
4444
endif(CLR_CMAKE_TARGET_ARCH_WASM)
4545

46+
if(CLR_CMAKE_TARGET_BROWSER)
47+
set(FEATURE_WEBCIL 1)
48+
endif()
49+
4650
if(NOT DEFINED FEATURE_INTERPRETER)
4751
if(CLR_CMAKE_TARGET_ANDROID)
4852
set(FEATURE_INTERPRETER 0)

0 commit comments

Comments
 (0)