Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 35 additions & 24 deletions docs/design/mono/webcil.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# WebCIL assembly format
# Webcil assembly format

## Version

Expand All @@ -12,7 +12,7 @@ customers that certain users are unable to use their apps because firewalls and
may prevent browsers from downloading or caching assemblies with a .DLL extension and PE contents.

This document defines a new container format for ECMA-335 assemblies that uses the `.wasm` extension
and uses a new WebCIL metadata payload format wrapped in a WebAssembly module.
and uses a new Webcil metadata payload format wrapped in a WebAssembly module.
Comment thread
pavelsavara marked this conversation as resolved.


## Specification
Expand Down Expand Up @@ -111,21 +111,21 @@ The Webcil headers consist of a Webcil header followed by a sequence of section

``` c
struct WebcilHeader {
uint8_t id[4]; // 'W' 'b' 'I' 'L'
// 4 bytes
uint16_t version_major; // 0
uint16_t version_minor; // 0
// 8 bytes
uint16_t coff_sections;
uint16_t reserved0; // 0
// 12 bytes

uint32_t pe_cli_header_rva;
uint32_t pe_cli_header_size;
// 20 bytes

uint32_t pe_debug_rva;
uint32_t pe_debug_size;
uint8_t Id[4]; // 'W' 'b' 'I' 'L'
// 4 bytes
uint16_t VersionMajor; // 0
uint16_t VersionMinor; // 0
// 8 bytes
uint16_t CoffSections;
uint16_t Reserved0; // 0
// 12 bytes

uint32_t PeCliHeaderRva;
uint32_t PeCliHeaderSize;
// 20 bytes

uint32_t PeDebugRva;
uint32_t PeDebugSize;
// 28 bytes
};
```
Expand All @@ -139,26 +139,37 @@ of the CLI header, as well as the directory entry for the PE debug directory.

#### Section header table

Immediately following the Webcil header is a sequence (whose length is given by `coff_sections`
Immediately following the Webcil header is a sequence (whose length is given by `CoffSections`
above) of section headers giving their virtual address and virtual size, as well as the offset in
the Webcil payload and the size in the file. This is a subset of the PE section header that includes
enough information to correctly interpret the RVAs from the webcil header and from the .NET
metadata. Other information (such as the section names) are not included.

``` c
struct SectionHeader {
uint32_t st_virtual_size;
uint32_t st_virtual_address;
uint32_t st_raw_data_size;
uint32_t st_raw_data_ptr;
uint32_t VirtualSize;
uint32_t VirtualAddress;
uint32_t SizeOfRawData;
uint32_t PointerToRawData;
};
```

(**Note**: the `st_raw_data_ptr` member is an offset from the beginning of the Webcil payload, not from the beginning of the WebAssembly wrapper module.)
(**Note**: the `PointerToRawData` member is an offset from the beginning of the Webcil payload, not from the beginning of the WebAssembly wrapper module.)

#### Sections

Immediately following the section table are the sections. These are copied verbatim from the PE file.
The section data starts at the first 16-byte-aligned offset after the end of the
section header table. Any gap between the last section header and the first section's
raw data is filled with zero-valued padding bytes. Each subsequent section likewise
begins at a 16-byte-aligned offset. This alignment guarantees that RVA static fields
(such as those backing `ReadOnlySpan<T>` over types up to `Vector128<T>`) retain
their natural alignment when the payload is loaded into memory at a 16-byte-aligned
base address.

Because PE `SizeOfRawData` is normally a multiple of the PE `FileAlignment` (≥ 512),
the inter-section padding is almost always zero bytes. In the worst case a single
assembly may gain up to ~30 bytes of padding total (header-to-first-section plus
one boundary per additional section).

### Rationale

Expand Down
3 changes: 2 additions & 1 deletion src/mono/browser/debugger/BrowserDebugProxy/DebugStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -894,7 +894,7 @@ public void LoadInfoFromBytes(MonoProxy monoProxy, SessionId sessionId, Assembly
{
try
{
// First try to read it as a PE file, otherwise try it as a WebCIL file
// First try to read it as a PE file, otherwise try it as a Webcil file
var peReader = new PEReader(asmStream);
if (!peReader.HasMetadata)
throw new BadImageFormatException();
Expand Down Expand Up @@ -970,6 +970,7 @@ private void FromPEReader(MonoProxy monoProxy, SessionId sessionId, PEReader peR

LoadAssemblyInfo(peReader, name, asmMetadataReader, summary, logger);
}

private void FromWebcilReader(MonoProxy monoProxy, SessionId sessionId, WebcilReader wcReader, byte[] pdb, ILogger logger, CancellationToken token)
{
var debugProvider = new WebcilDebugMetadataProvider(wcReader);
Expand Down
2 changes: 1 addition & 1 deletion src/mono/cmake/config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -742,7 +742,7 @@
/* Enable System.WeakAttribute support */
#cmakedefine ENABLE_WEAK_ATTR 1

/* Enable WebCIL image loader */
/* Enable Webcil image loader */
#cmakedefine ENABLE_WEBCIL 1

/* define if clockgettime exists */
Expand Down
2 changes: 1 addition & 1 deletion src/mono/cmake/options.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ option (ENABLE_OVERRIDABLE_ALLOCATORS "Enable overridable allocator support")
option (ENABLE_SIGALTSTACK "Enable support for using sigaltstack for SIGSEGV and stack overflow handling, this doesn't work on some platforms")
option (USE_MALLOC_FOR_MEMPOOLS "Use malloc for each single mempool allocation, so tools like Valgrind can run better")
option (STATIC_COMPONENTS "Compile mono runtime components as static (not dynamic) libraries")
option (ENABLE_WEBCIL "Enable the WebCIL loader")
option (ENABLE_WEBCIL "Enable the Webcil loader")

set (MONO_GC "sgen" CACHE STRING "Garbage collector implementation (sgen or boehm). Default: sgen")
set (GC_SUSPEND "default" CACHE STRING "GC suspend method (default, preemptive, coop, hybrid)")
Expand Down
10 changes: 5 additions & 5 deletions src/mono/mono/metadata/webcil-loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ enum {
MONO_WEBCIL_VERSION_MINOR = 0,
};

typedef struct MonoWebCilHeader {
typedef struct MonoWebcilHeader {
uint8_t id[4]; // 'W' 'b' 'I' 'L'
// 4 bytes
uint16_t version_major; // 0
Expand All @@ -34,7 +34,7 @@ typedef struct MonoWebCilHeader {
uint32_t pe_debug_rva;
uint32_t pe_debug_size;
// 28 bytes
} MonoWebCilHeader;
} MonoWebcilHeader;

static gboolean
find_webcil_in_wasm (const uint8_t *ptr, const uint8_t *boundp, const uint8_t **webcil_payload_start);
Expand All @@ -43,7 +43,7 @@ static gboolean
webcil_image_match (MonoImage *image)
{
gboolean success = FALSE;
if (image->raw_data_len >= sizeof (MonoWebCilHeader)) {
if (image->raw_data_len >= sizeof (MonoWebcilHeader)) {
success = image->raw_data[0] == 'W' && image->raw_data[1] == 'b' && image->raw_data[2] == 'I' && image->raw_data[3] == 'L';

if (!success && mono_wasm_module_is_wasm ((const uint8_t*)image->raw_data, (const uint8_t*)image->raw_data + image->raw_data_len)) {
Expand All @@ -64,7 +64,7 @@ webcil_image_match (MonoImage *image)
static int32_t
do_load_header (const char *raw_data, uint32_t raw_data_len, int32_t offset, MonoDotNetHeader *header, int32_t *raw_data_rva_map_wasm_bump)
{
MonoWebCilHeader wcheader;
MonoWebcilHeader wcheader;
const uint8_t *raw_data_bound = (const uint8_t*)raw_data + raw_data_len;
*raw_data_rva_map_wasm_bump = 0;
if (mono_wasm_module_is_wasm ((const uint8_t*)raw_data, raw_data_bound)) {
Expand All @@ -79,7 +79,7 @@ do_load_header (const char *raw_data, uint32_t raw_data_len, int32_t offset, Mon
offset += offset_adjustment;
}

if (offset + sizeof (MonoWebCilHeader) > raw_data_len)
if (offset + sizeof (MonoWebcilHeader) > raw_data_len)
return -1;
memcpy (&wcheader, raw_data + offset, sizeof (wcheader));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ Copyright (c) .NET Foundation. All rights reserved.
<UsingTask TaskName="Microsoft.NET.Sdk.WebAssembly.GenerateWasmBootJson" AssemblyFile="$(_WebAssemblySdkTasksAssembly)" TaskFactory="TaskHostFactory" />
<UsingTask TaskName="Microsoft.NET.Sdk.WebAssembly.ComputeWasmBuildAssets" AssemblyFile="$(_WebAssemblySdkTasksAssembly)" TaskFactory="TaskHostFactory" />
<UsingTask TaskName="Microsoft.NET.Sdk.WebAssembly.ComputeWasmPublishAssets" AssemblyFile="$(_WebAssemblySdkTasksAssembly)" TaskFactory="TaskHostFactory" />
<UsingTask TaskName="Microsoft.NET.Sdk.WebAssembly.ConvertDllsToWebCil" AssemblyFile="$(_WebAssemblySdkTasksAssembly)" TaskFactory="TaskHostFactory" />
<UsingTask TaskName="Microsoft.NET.Sdk.WebAssembly.ConvertDllsToWebcil" AssemblyFile="$(_WebAssemblySdkTasksAssembly)" TaskFactory="TaskHostFactory" />

<PropertyGroup>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
Expand Down Expand Up @@ -348,15 +348,15 @@ Copyright (c) .NET Foundation. All rights reserved.
</ItemGroup>

<PropertyGroup>
<_WasmBuildWebCilPath>$([MSBuild]::NormalizeDirectory($(IntermediateOutputPath), 'webcil'))</_WasmBuildWebCilPath>
<_WasmBuildTmpWebCilPath>$([MSBuild]::NormalizeDirectory($(IntermediateOutputPath), 'tmp-webcil'))</_WasmBuildTmpWebCilPath>
<_WasmBuildWebcilPath>$([MSBuild]::NormalizeDirectory($(IntermediateOutputPath), 'webcil'))</_WasmBuildWebcilPath>
<_WasmBuildTmpWebcilPath>$([MSBuild]::NormalizeDirectory($(IntermediateOutputPath), 'tmp-webcil'))</_WasmBuildTmpWebcilPath>
<_WasmBuildOuputPath>$([MSBuild]::NormalizeDirectory('$(OutputPath)', 'wwwroot'))</_WasmBuildOuputPath>
</PropertyGroup>

<ConvertDllsToWebCil Candidates="@(_BuildAssetsCandidates)" IntermediateOutputPath="$(_WasmBuildTmpWebCilPath)" OutputPath="$(_WasmBuildWebCilPath)" IsEnabled="$(_WasmEnableWebcil)">
<Output TaskParameter="WebCilCandidates" ItemName="_WebCilAssetsCandidates" />
<ConvertDllsToWebcil Candidates="@(_BuildAssetsCandidates)" IntermediateOutputPath="$(_WasmBuildTmpWebcilPath)" OutputPath="$(_WasmBuildWebcilPath)" IsEnabled="$(_WasmEnableWebcil)">
<Output TaskParameter="WebcilCandidates" ItemName="_WebcilAssetsCandidates" />
<Output TaskParameter="FileWrites" ItemName="FileWrites" />
</ConvertDllsToWebCil>
</ConvertDllsToWebcil>

<ItemGroup>
<_WasmFingerprintPatterns Include="WasmFiles" Pattern="*.wasm" Expression="#[.{fingerprint}]!" />
Expand All @@ -367,7 +367,7 @@ Copyright (c) .NET Foundation. All rights reserved.
</ItemGroup>

<DefineStaticWebAssets
CandidateAssets="@(_WebCilAssetsCandidates)"
CandidateAssets="@(_WebcilAssetsCandidates)"
SourceId="$(PackageId)"
SourceType="Computed"
AssetKind="Build"
Expand Down Expand Up @@ -703,7 +703,7 @@ Copyright (c) .NET Foundation. All rights reserved.
EnableDiagnostics="$(_WasmEmitDiagnosticModulePublish)"
EmitSourceMap="$(_WasmEmitSourceMapPublish)"
EmitSymbolMap="$(WasmEmitSymbolMap)"
IsWebCilEnabled="$(_WasmEnableWebcil)"
IsWebcilEnabled="$(_WasmEnableWebcil)"
FingerprintAssets="$(_WasmFingerprintAssets)"
>
<Output TaskParameter="NewCandidates" ItemName="_NewWasmPublishStaticWebAssets" />
Expand All @@ -716,40 +716,40 @@ Copyright (c) .NET Foundation. All rights reserved.
</ItemGroup>

<PropertyGroup>
<_WasmPublishWebCilPath>$([MSBuild]::NormalizeDirectory($(IntermediateOutputPath), 'webcil', 'publish'))</_WasmPublishWebCilPath>
<_WasmPublishTmpWebCilPath>$([MSBuild]::NormalizeDirectory($(IntermediateOutputPath), 'tmp-webcil', 'publish'))</_WasmPublishTmpWebCilPath>
<_WasmPublishWebcilPath>$([MSBuild]::NormalizeDirectory($(IntermediateOutputPath), 'webcil', 'publish'))</_WasmPublishWebcilPath>
<_WasmPublishTmpWebcilPath>$([MSBuild]::NormalizeDirectory($(IntermediateOutputPath), 'tmp-webcil', 'publish'))</_WasmPublishTmpWebcilPath>
</PropertyGroup>

<ConvertDllsToWebCil Candidates="@(_NewWasmPublishStaticWebAssets)" IntermediateOutputPath="$(_WasmPublishTmpWebCilPath)" OutputPath="$(_WasmPublishWebCilPath)" IsEnabled="$(_WasmEnableWebcil)">
<Output TaskParameter="WebCilCandidates" ItemName="_NewWebCilPublishStaticWebAssetsCandidates" />
<ConvertDllsToWebcil Candidates="@(_NewWasmPublishStaticWebAssets)" IntermediateOutputPath="$(_WasmPublishTmpWebcilPath)" OutputPath="$(_WasmPublishWebcilPath)" IsEnabled="$(_WasmEnableWebcil)">
<Output TaskParameter="WebcilCandidates" ItemName="_NewWebcilPublishStaticWebAssetsCandidates" />
<Output TaskParameter="FileWrites" ItemName="FileWrites" />
</ConvertDllsToWebCil>
</ConvertDllsToWebcil>

<!-- _NewWebCilPublishStaticWebAssetsCandidates contain the `Fingerprint` and the `Integrity` from the old assets.
<!-- _NewWebcilPublishStaticWebAssetsCandidates contain the `Fingerprint` and the `Integrity` from the old assets.
Remove them and call DefineStaticWebAssets so that they can get re-computed appropriately.
-->
<ItemGroup>
<_NewWebCilPublishStaticWebAssetsCandidatesNoMetadata
Include="@(_NewWebCilPublishStaticWebAssetsCandidates)"
<_NewWebcilPublishStaticWebAssetsCandidatesNoMetadata
Include="@(_NewWebcilPublishStaticWebAssetsCandidates)"
RemoveMetadata="Integrity;Fingerprint" />
</ItemGroup>

<DefineStaticWebAssets CandidateAssets="@(_NewWebCilPublishStaticWebAssetsCandidatesNoMetadata);@(_PromotedWasmPublishStaticWebAssets)">
<Output TaskParameter="Assets" ItemName="_NewWebCilPublishStaticWebAssets" />
<DefineStaticWebAssets CandidateAssets="@(_NewWebcilPublishStaticWebAssetsCandidatesNoMetadata);@(_PromotedWasmPublishStaticWebAssets)">
<Output TaskParameter="Assets" ItemName="_NewWebcilPublishStaticWebAssets" />
</DefineStaticWebAssets>

<DefineStaticWebAssetEndpoints
CandidateAssets="@(_NewWebCilPublishStaticWebAssets)"
CandidateAssets="@(_NewWebcilPublishStaticWebAssets)"
ExistingEndpoints="@(StaticWebAssetEndpoint)"
ContentTypeMappings="@(StaticWebAssetContentTypeMapping)"
>
<Output TaskParameter="Endpoints" ItemName="_NewWebCilPublishStaticWebAssetsEndpoint" />
<Output TaskParameter="Endpoints" ItemName="_NewWebcilPublishStaticWebAssetsEndpoint" />
</DefineStaticWebAssetEndpoints>

<ItemGroup>
<ResolvedFileToPublish Remove="@(_PublishResolvedFilesToRemove)" />
<StaticWebAsset Include="@(_NewWebCilPublishStaticWebAssets)" />
<StaticWebAssetEndpoint Include="@(_NewWebCilPublishStaticWebAssetsEndpoint)" />
<StaticWebAsset Include="@(_NewWebcilPublishStaticWebAssets)" />
<StaticWebAssetEndpoint Include="@(_NewWebcilPublishStaticWebAssetsEndpoint)" />

<!-- TODO: Probably doesn't do anything as of now, original https://github.com/dotnet/aspnetcore/pull/34798 -->
<PublishBlazorBootStaticWebAsset
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ public BuildEnvironment()
if (!UseWebcil)
{
// Default is 'true'
EnvVars["WasmEnableWebCil"] = "false";
EnvVars["WasmEnableWebcil"] = "false";
}

if (!EnvironmentVariables.UseFingerprinting)
Expand Down
2 changes: 1 addition & 1 deletion src/mono/wasm/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ Note: You can replace the location of `AppBundle` directory by `<WasmAppDir>../
- `dotnet.boot.js` - contains list of all other assets and their integrity hash and also various configuration flags.
- `dotnet.native.wasm` - is the compiled binary of the dotnet (Mono) runtime.
- `System.Private.CoreLib.*` - is NET assembly with the core implementation of dotnet runtime and class library
- `*.wasm` - are .NET assemblies stored in `WebCIL` format (for better compatibility with firewalls and virus scanners).
- `*.wasm` - are .NET assemblies stored in `Webcil` format (for better compatibility with firewalls and virus scanners).
- `*.dll` - are .NET assemblies stored in Portable Executable format (only used when you use `<WasmEnableWebcil>false</WasmEnableWebcil>`).
- `dotnet.js.map` - is a source map file, for easier debugging of the runtime code. It's not included in the published applications.
- `dotnet.native.js.symbols` - are debug symbols which help to put `C` runtime method names back to the `.wasm` stack traces. To enable generating it, use `<WasmEmitSymbolMap>true</WasmEmitSymbolMap>`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public class ComputeWasmPublishAssets : Task

public bool EmitSymbolMap { get; set; }

public bool IsWebCilEnabled { get; set; }
public bool IsWebcilEnabled { get; set; }

public bool FingerprintAssets { get; set; }

Expand Down Expand Up @@ -454,7 +454,7 @@ private void ComputeUpdatedAssemblies(
var asset = kvp.Value;
var fileName = Path.GetFileName(GetItemSpecWithoutFingerprint(asset));
var assetToUpdateItemSpec = FingerprintAssets ? GetNonFingerprintedAssetItemSpec(asset) : asset.ItemSpec;
if (IsWebCilEnabled)
if (IsWebcilEnabled)
fileName = Path.ChangeExtension(fileName, ".dll");

if (resolvedAssembliesToPublish.TryGetValue(fileName, out var existing))
Expand Down Expand Up @@ -484,7 +484,7 @@ private void ComputeUpdatedAssemblies(
assetsToUpdate.Add(satelliteAssembly.ItemSpec, satelliteAssembly);
var culture = satelliteAssembly.GetMetadata("AssetTraitValue");
var fileName = Path.GetFileName(GetItemSpecWithoutFingerprint(satelliteAssembly));
if (IsWebCilEnabled)
if (IsWebcilEnabled)
fileName = Path.ChangeExtension(fileName, ".dll");

if (satelliteAssemblies.TryGetValue((culture, fileName), out var existing))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

namespace Microsoft.NET.Sdk.WebAssembly;

public class ConvertDllsToWebCil : Task
public class ConvertDllsToWebcil : Task
{
[Required]
public ITaskItem[] Candidates { get; set; }
Expand All @@ -25,7 +25,7 @@ public class ConvertDllsToWebCil : Task
public bool IsEnabled { get; set; }

[Output]
public ITaskItem[] WebCilCandidates { get; set; }
public ITaskItem[] WebcilCandidates { get; set; }

protected readonly List<string> _fileWrites = new();

Expand All @@ -34,11 +34,11 @@ public class ConvertDllsToWebCil : Task

public override bool Execute()
{
var webCilCandidates = new List<ITaskItem>();
var webcilCandidates = new List<ITaskItem>();

if (!IsEnabled)
{
WebCilCandidates = Candidates;
WebcilCandidates = Candidates;
return true;
}

Expand All @@ -56,14 +56,14 @@ public override bool Execute()

if (extension != ".dll")
{
webCilCandidates.Add(candidate);
webcilCandidates.Add(candidate);
continue;
}

try
{
TaskItem webcilItem = ConvertDll(tmpDir, candidate);
webCilCandidates.Add(webcilItem);
webcilCandidates.Add(webcilItem);
}
catch (Exception ex)
{
Expand All @@ -74,7 +74,7 @@ public override bool Execute()

Directory.Delete(tmpDir, true);

WebCilCandidates = webCilCandidates.ToArray();
WebcilCandidates = webcilCandidates.ToArray();
return true;
}

Expand Down
Loading
Loading