Skip to content

Commit

Permalink
Move Win32 resource emission to the compiler (#88464)
Browse files Browse the repository at this point in the history
Fixes #79634.

To generate Win32 resources, we'd first use an MSBuild task to dump Win32 resources from the input IL module into a `.res` file. We'd then pass the `.res` file to link.exe. Link.exe would then invoke cvtres.exe to convert the `.res` file to `.obj`. Link.exe then links the `.obj` into the final executable.

Skip all of this and instead generate the correct object data in the compiler directly. I'm reusing Win32 resource emission logic from crossgen2. It already mostly does the right thing - we just needed to split the `.rsrc` section into `.rsrc$01` and `.rsrc$02` that link.exe expects. The first part has the data directory. The second part has the actual resource data.

Contributes to #73931. The cvtres step was actually non-deterministic because it creates an object file in TEMP and embeds this temporary name into the object.
  • Loading branch information
MichalStrehovsky authored Jul 11, 2023
1 parent d2c5182 commit 4e48d2d
Show file tree
Hide file tree
Showing 19 changed files with 190 additions and 286 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ The .NET Foundation licenses this file to you under the MIT license.
<IlcArg Condition="$(IlcMaxVectorTBitWidth) != ''" Include="--max-vectort-bitwidth:$(IlcMaxVectorTBitWidth)" />
<IlcArg Condition="$(IlcSingleThreaded) == 'true'" Include="--parallelism:1" />
<IlcArg Condition="$(IlcSystemModule) != ''" Include="--systemmodule:$(IlcSystemModule)" />
<IlcArg Condition="'$(_targetOS)' == 'win' and $(IlcMultiModule) != 'true' and '$(IlcGenerateWin32Resources)' != 'false'" Include="--win32resourcemodule:%(ManagedBinary.Filename)" />
<IlcArg Condition="$(IlcDumpIL) == 'true'" Include="--ildump:$(NativeIntermediateOutputPath)%(ManagedBinary.Filename).il" />
<IlcArg Condition="$(NoWarn) != ''" Include='--nowarn:"$([MSBuild]::Escape($(NoWarn)))"' />
<IlcArg Condition="$(TrimmerSingleWarn) == 'true'" Include="--singlewarn" />
Expand Down Expand Up @@ -311,26 +312,10 @@ The .NET Foundation licenses this file to you under the MIT license.
<Copy SourceFiles="@(NativeObjects)" DestinationFolder="$(NativeOutputPath)" />
</Target>

<PropertyGroup>
<_Win32ResFile>$(NativeIntermediateOutputPath)$(TargetName).res</_Win32ResFile>
</PropertyGroup>

<UsingTask TaskName="DumpNativeResources" AssemblyFile="$(IlcBuildTasksPath)" />
<Target Name="GenerateResFile"
Inputs="$(IntermediateOutputPath)$(TargetName)$(TargetExt)"
Outputs="$(_Win32ResFile)"
Condition="'$(_targetOS)' == 'win'">

<DumpNativeResources
MainAssembly="$(IntermediateOutputPath)$(TargetName)$(TargetExt)"
ResourceFile="$(_Win32ResFile)" />

</Target>

<Target Name="LinkNative"
Inputs="$(NativeObject);@(NativeLibrary)"
Outputs="$(NativeBinary)"
DependsOnTargets="$(LinkNativeDependsOn);GenerateResFile">
DependsOnTargets="$(LinkNativeDependsOn)">

<ItemGroup>
<CustomLinkerArg Include="&quot;$(NativeObject)&quot;" />
Expand All @@ -341,7 +326,6 @@ The .NET Foundation licenses this file to you under the MIT license.
<CustomLinkerArg Include="-exported_symbols_list &quot;$(ExportsFile)&quot;" Condition="'$(_IsApplePlatform)' == 'true' and $(ExportsFile) != ''" />
<CustomLinkerArg Include="-Wl,--version-script=$(ExportsFile)" Condition="'$(_targetOS)' != 'win' and '$(_IsApplePlatform)' != 'true' and $(ExportsFile) != ''" />
<CustomLinkerArg Include="-Wl,--export-dynamic" Condition="'$(_targetOS)' != 'win' and '$(_IsApplePlatform)' != 'true' and '$(IlcExportUnmanagedEntrypoints)' == 'true' and '$(NativeLib)' == ''" />
<CustomLinkerArg Condition="Exists('$(_Win32ResFile)')" Include="&quot;$(_Win32ResFile)&quot;" />
<CustomLinkerArg Include="@(LinkerArg)" />
</ItemGroup>
<ItemGroup Condition="'$(_targetOS)' != 'win' and '$(_IsApplePlatform)' != 'true'">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public unsafe partial class ResourceData
private readonly SortedDictionary<ushort, ResType> _resTypeHeadID = new SortedDictionary<ushort, ResType>();
private readonly SortedDictionary<string, ResType> _resTypeHeadName = new SortedDictionary<string, ResType>(StringComparer.Ordinal);

private class ResLanguage
private sealed class ResLanguage
{
public ResLanguage(byte[] data)
{
Expand All @@ -22,12 +22,12 @@ public ResLanguage(byte[] data)
public byte[] DataEntry;
}

private class ResName
private sealed class ResName
{
public SortedDictionary<ushort, ResLanguage> Languages = new SortedDictionary<ushort, ResLanguage>();
}

private class ResType
private sealed class ResType
{
public SortedDictionary<string, ResName> NameHeadName = new SortedDictionary<string, ResName>(StringComparer.Ordinal);
public SortedDictionary<ushort, ResName> NameHeadID = new SortedDictionary<ushort, ResName>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public IMAGE_RESOURCE_DIRECTORY_ENTRY(ref BlobReader blobReader)
OffsetToData = blobReader.ReadUInt32();
}

public static ObjectDataBuilder.Reservation Write(ref ObjectDataBuilder dataBuilder, string name, IDictionary<string, List<ObjectDataBuilder.Reservation>> nameTable)
public static ObjectDataBuilder.Reservation Write(ref ObjectDataBuilder dataBuilder, string name, SortedDictionary<string, List<ObjectDataBuilder.Reservation>> nameTable)
{
List<ObjectDataBuilder.Reservation> relatedNameReferences;
if (!nameTable.TryGetValue(name, out relatedNameReferences))
Expand Down Expand Up @@ -84,7 +84,13 @@ public IMAGE_RESOURCE_DATA_ENTRY(ref BlobReader blobReader)

public static void Write(ref ObjectDataBuilder dataBuilder, ISymbolNode node, int offsetFromSymbol, int sizeOfData)
{
dataBuilder.EmitReloc(node, RelocType.IMAGE_REL_BASED_ADDR32NB, offsetFromSymbol);
dataBuilder.EmitReloc(node,
#if READYTORUN
RelocType.IMAGE_REL_BASED_ADDR32NB,
#else
RelocType.IMAGE_REL_BASED_ABSOLUTE,
#endif
offsetFromSymbol);
dataBuilder.EmitInt(sizeOfData);
dataBuilder.EmitInt(1252); // CODEPAGE = DEFAULT_CODEPAGE
dataBuilder.EmitInt(0); // RESERVED
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ public bool IsEmpty
}

public void WriteResources(ISymbolNode nodeAssociatedWithDataBuilder, ref ObjectDataBuilder dataBuilder)
{
WriteResources(nodeAssociatedWithDataBuilder, ref dataBuilder, ref dataBuilder);
}

public void WriteResources(ISymbolNode nodeAssociatedWithDataBuilder, ref ObjectDataBuilder dataBuilder, ref ObjectDataBuilder contentBuilder)
{
Debug.Assert(dataBuilder.CountBytes == 0);

Expand Down Expand Up @@ -145,9 +150,9 @@ public void WriteResources(ISymbolNode nodeAssociatedWithDataBuilder, ref Object
// Emit byte arrays of resource data, capture the offsets
foreach (Tuple<ResLanguage, ObjectDataBuilder.Reservation> language in resLanguages)
{
dataBuilder.PadAlignment(4); // Data in resource files is 4 byte aligned
dataEntryTable.Add(language.Item1, dataBuilder.CountBytes);
dataBuilder.EmitBytes(language.Item1.DataEntry);
contentBuilder.PadAlignment(4); // Data in resource files is 4 byte aligned
dataEntryTable.Add(language.Item1, contentBuilder.CountBytes);
contentBuilder.EmitBytes(language.Item1.DataEntry);
}

dataBuilder.PadAlignment(4); // resource data entries are 4 byte aligned
Expand Down
255 changes: 0 additions & 255 deletions src/coreclr/tools/aot/ILCompiler.Build.Tasks/DumpNativeResources.cs

This file was deleted.

Loading

0 comments on commit 4e48d2d

Please sign in to comment.