diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 5f5c3db0412d1c..e7ae89444f2485 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -122,6 +122,10 @@ https://github.com/dotnet/runtime-assets cc70e46d909f35a576abe245219c1df31160bbd6 + + https://github.com/dotnet/runtime-assets + cc70e46d909f35a576abe245219c1df31160bbd6 + https://github.com/dotnet/llvm-project 30296e71234ffb3eb8da789d36adf4db146e6602 diff --git a/eng/Versions.props b/eng/Versions.props index 8d03f4097e4731..0dfda84df02888 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -126,6 +126,7 @@ 6.0.0-beta.21411.3 6.0.0-beta.21411.3 6.0.0-beta.21411.3 + 6.0.0-beta.21411.3 1.0.0-prerelease.21411.3 1.0.0-prerelease.21411.3 diff --git a/src/mono/nuget/Microsoft.NET.Runtime.MonoTargets.Sdk/Microsoft.NET.Runtime.MonoTargets.Sdk.pkgproj b/src/mono/nuget/Microsoft.NET.Runtime.MonoTargets.Sdk/Microsoft.NET.Runtime.MonoTargets.Sdk.pkgproj index adf1b80c2f3398..724b704f864b11 100644 --- a/src/mono/nuget/Microsoft.NET.Runtime.MonoTargets.Sdk/Microsoft.NET.Runtime.MonoTargets.Sdk.pkgproj +++ b/src/mono/nuget/Microsoft.NET.Runtime.MonoTargets.Sdk/Microsoft.NET.Runtime.MonoTargets.Sdk.pkgproj @@ -6,6 +6,7 @@ + @@ -14,6 +15,7 @@ + diff --git a/src/mono/nuget/Microsoft.NET.Runtime.MonoTargets.Sdk/Sdk/ILStripTask.props b/src/mono/nuget/Microsoft.NET.Runtime.MonoTargets.Sdk/Sdk/ILStripTask.props new file mode 100644 index 00000000000000..84c0dbf11afa87 --- /dev/null +++ b/src/mono/nuget/Microsoft.NET.Runtime.MonoTargets.Sdk/Sdk/ILStripTask.props @@ -0,0 +1,7 @@ + + + $(MSBuildThisFileDirectory)..\tasks\net6.0\ILStrip.dll + $(MSBuildThisFileDirectory)..\tasks\net472\ILStrip.dll + + + diff --git a/src/mono/nuget/Microsoft.NET.Runtime.MonoTargets.Sdk/Sdk/Sdk.props b/src/mono/nuget/Microsoft.NET.Runtime.MonoTargets.Sdk/Sdk/Sdk.props index d292fe15f274a2..8a7ede79242b1c 100644 --- a/src/mono/nuget/Microsoft.NET.Runtime.MonoTargets.Sdk/Sdk/Sdk.props +++ b/src/mono/nuget/Microsoft.NET.Runtime.MonoTargets.Sdk/Sdk/Sdk.props @@ -1,4 +1,5 @@ + diff --git a/src/tasks/ILStripTask/ILStrip.cs b/src/tasks/ILStripTask/ILStrip.cs new file mode 100644 index 00000000000000..7ce5a5ecc07cf1 --- /dev/null +++ b/src/tasks/ILStripTask/ILStrip.cs @@ -0,0 +1,277 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using Mono.Cecil; +using Mono.Cecil.Binary; +using Mono.Cecil.Cil; +using Mono.Cecil.Metadata; + +public class ILStrip : Microsoft.Build.Utilities.Task +{ + /// + /// Assemblies to be stripped. + /// The assemblies will be modified in place if OutputPath metadata is not set. + /// + [Required] + public ITaskItem[] Assemblies { get; set; } = Array.Empty(); + + /// + /// Disable parallel stripping + /// + public bool DisableParallelStripping { get; set; } + + public override bool Execute() + { + if (Assemblies.Length == 0) + { + throw new ArgumentException($"'{nameof(Assemblies)}' is required.", nameof(Assemblies)); + } + + if (DisableParallelStripping) + { + foreach (var assemblyItem in Assemblies) + { + if (!StripAssembly(assemblyItem)) + return !Log.HasLoggedErrors; + } + } + else + { + Parallel.ForEach(Assemblies, + new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }, + assemblyItem => StripAssembly(assemblyItem)); + } + + return !Log.HasLoggedErrors; + } + + private bool StripAssembly(ITaskItem assemblyItem) + { + string assemblyFile = assemblyItem.ItemSpec; + var outputPath = assemblyItem.GetMetadata("OutputPath"); + if (String.IsNullOrWhiteSpace(outputPath)) + { + outputPath = assemblyFile; + Log.LogMessage(MessageImportance.Low, $"[ILStrip] {assemblyFile}"); + } + else + { + Log.LogMessage(MessageImportance.Low, $"[ILStrip] {assemblyFile} to {outputPath}"); + } + + try + { + AssemblyDefinition assembly = AssemblyFactory.GetAssembly(assemblyFile); + AssemblyStripper.StripAssembly(assembly, outputPath); + } + catch (Exception ex) + { + Log.LogMessage(MessageImportance.Low, ex.ToString()); + Log.LogError($"ILStrip failed for {assemblyFile}: {ex.Message}"); + return false; + } + + return true; + } + + private class AssemblyStripper + { + AssemblyDefinition assembly; + BinaryWriter writer; + + Image original; + Image stripped; + + ReflectionWriter reflection_writer; + MetadataWriter metadata_writer; + + TablesHeap original_tables; + TablesHeap stripped_tables; + + AssemblyStripper(AssemblyDefinition assembly, BinaryWriter writer) + { + this.assembly = assembly; + this.writer = writer; + } + + void Strip() + { + FullLoad(); + ClearMethodBodies(); + CopyOriginalImage(); + PatchMethods(); + PatchFields(); + PatchResources(); + Write(); + } + + void FullLoad() + { + assembly.MainModule.FullLoad(); + } + + void ClearMethodBodies() + { + foreach (TypeDefinition type in assembly.MainModule.Types) + { + ClearMethodBodies(type.Constructors); + ClearMethodBodies(type.Methods); + } + } + + static void ClearMethodBodies(ICollection methods) + { + foreach (MethodDefinition method in methods) + { + if (!method.HasBody) + continue; + + MethodBody body = new MethodBody(method); + body.CilWorker.Emit(OpCodes.Ret); + + method.Body = body; + } + } + + void CopyOriginalImage() + { + original = assembly.MainModule.Image; + stripped = Image.CreateImage(); + + stripped.Accept(new CopyImageVisitor(original)); + + assembly.MainModule.Image = stripped; + + original_tables = original.MetadataRoot.Streams.TablesHeap; + stripped_tables = stripped.MetadataRoot.Streams.TablesHeap; + + TableCollection tables = original_tables.Tables; + foreach (IMetadataTable table in tables) + stripped_tables.Tables.Add(table); + + stripped_tables.Valid = original_tables.Valid; + stripped_tables.Sorted = original_tables.Sorted; + + reflection_writer = new ReflectionWriter(assembly.MainModule); + reflection_writer.StructureWriter = new StructureWriter(assembly, writer); + reflection_writer.CodeWriter.Stripped = true; + + metadata_writer = reflection_writer.MetadataWriter; + + PatchHeap(metadata_writer.StringWriter, original.MetadataRoot.Streams.StringsHeap); + PatchHeap(metadata_writer.GuidWriter, original.MetadataRoot.Streams.GuidHeap); + PatchHeap(metadata_writer.UserStringWriter, original.MetadataRoot.Streams.UserStringsHeap); + PatchHeap(metadata_writer.BlobWriter, original.MetadataRoot.Streams.BlobHeap); + + if (assembly.EntryPoint != null) + metadata_writer.EntryPointToken = assembly.EntryPoint.MetadataToken.ToUInt(); + } + + static void PatchHeap(MemoryBinaryWriter heap_writer, MetadataHeap heap) + { + if (heap == null) + return; + + heap_writer.BaseStream.Position = 0; + heap_writer.Write(heap.Data); + } + + void PatchMethods() + { + MethodTable methodTable = (MethodTable)stripped_tables[MethodTable.RId]; + if (methodTable == null) + return; + + RVA method_rva = RVA.Zero; + + for (int i = 0; i < methodTable.Rows.Count; i++) + { + MethodRow methodRow = methodTable[i]; + + methodRow.ImplFlags |= MethodImplAttributes.NoInlining; + + MetadataToken methodToken = MetadataToken.FromMetadataRow(TokenType.Method, i); + + MethodDefinition method = (MethodDefinition)assembly.MainModule.LookupByToken(methodToken); + + if (method.HasBody) + { + method_rva = method_rva != RVA.Zero + ? method_rva + : reflection_writer.CodeWriter.WriteMethodBody(method); + + methodRow.RVA = method_rva; + } + else + methodRow.RVA = RVA.Zero; + } + } + + void PatchFields() + { + FieldRVATable fieldRvaTable = (FieldRVATable)stripped_tables[FieldRVATable.RId]; + if (fieldRvaTable == null) + return; + + for (int i = 0; i < fieldRvaTable.Rows.Count; i++) + { + FieldRVARow fieldRvaRow = fieldRvaTable[i]; + + MetadataToken fieldToken = new MetadataToken(TokenType.Field, fieldRvaRow.Field); + + FieldDefinition field = (FieldDefinition)assembly.MainModule.LookupByToken(fieldToken); + + fieldRvaRow.RVA = metadata_writer.GetDataCursor(); + metadata_writer.AddData(field.InitialValue.Length + 3 & (~3)); + metadata_writer.AddFieldInitData(field.InitialValue); + } + } + + void PatchResources() + { + ManifestResourceTable resourceTable = (ManifestResourceTable)stripped_tables[ManifestResourceTable.RId]; + if (resourceTable == null) + return; + + for (int i = 0; i < resourceTable.Rows.Count; i++) + { + ManifestResourceRow resourceRow = resourceTable[i]; + + if (resourceRow.Implementation.RID != 0) + continue; + + foreach (Resource resource in assembly.MainModule.Resources) + { + EmbeddedResource er = resource as EmbeddedResource; + if (er == null) + continue; + + if (resource.Name != original.MetadataRoot.Streams.StringsHeap[resourceRow.Name]) + continue; + + resourceRow.Offset = metadata_writer.AddResource(er.Data); + } + } + } + + void Write() + { + stripped.MetadataRoot.Accept(metadata_writer); + } + + public static void StripAssembly(AssemblyDefinition assembly, string file) + { + using (FileStream fs = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None)) + { + new AssemblyStripper(assembly, new BinaryWriter(fs)).Strip(); + } + } + } +} diff --git a/src/tasks/ILStripTask/ILStrip.csproj b/src/tasks/ILStripTask/ILStrip.csproj new file mode 100644 index 00000000000000..879c56f26ae262 --- /dev/null +++ b/src/tasks/ILStripTask/ILStrip.csproj @@ -0,0 +1,32 @@ + + + $(TargetFrameworkForNETCoreTasks);$(TargetFrameworkForNETFrameworkTasks) + Library + true + false + $(NoWarn),CA1050,CS0618,CS0649,CS8604,CS8602,CS8632,SYSLIB0003 + false + + + + + + + + + + + + + + + + + + <_PublishFramework Remove="@(_PublishFramework)" /> + <_PublishFramework Include="$(TargetFrameworks)" /> + + + + + diff --git a/src/tasks/RuntimeConfigParser/RuntimeConfigParser.csproj b/src/tasks/RuntimeConfigParser/RuntimeConfigParser.csproj index c19669c373cb45..2fb35e649eed73 100644 --- a/src/tasks/RuntimeConfigParser/RuntimeConfigParser.csproj +++ b/src/tasks/RuntimeConfigParser/RuntimeConfigParser.csproj @@ -26,7 +26,7 @@ - + <_PublishFramework Remove="@(_PublishFramework)" />