Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get default CorLib reference from DotNetRuntimeInfo #462

Merged
merged 5 commits into from
Jul 1, 2023
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
11 changes: 10 additions & 1 deletion docs/guides/dotnet/basics.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,16 @@ references in the `KnownCorLibs` class to target another version of the
library.

``` csharp
var module = new ModuleDefinition("MyModule.exe", KnownCorLibs.SystemRuntime_v4_2_2_0);
var module = new ModuleDefinition("MyModule.dll", KnownCorLibs.SystemRuntime_v4_2_2_0);
```

If you have a .NET runtime identifier as specified in the
`TargetFrameworkAttribute` of an assembly, you can use the `DotNetRuntimeInfo`
structure to get the corresponding default corlib:

``` csharp
var runtime = DotNetRuntimeInfo.Parse(".NETCoreApp,Version=v3.1");
var module = new ModuleDefinition("MyModule.dll", runtime.GetDefaultCorLib());
```

## Opening a .NET module
Expand Down
17 changes: 17 additions & 0 deletions src/AsmResolver.DotNet/DotNetRuntimeInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,16 @@ public Version Version
/// </summary>
public bool IsNetStandard => Name == NetStandard;

/// <summary>
/// Parses the framework name as provided in <see cref="TargetFrameworkAttribute"/>.
/// </summary>
/// <param name="frameworkName">The full runtime name.</param>
/// <returns>The parsed version info.</returns>
public static DotNetRuntimeInfo Parse(string frameworkName)
{
return TryParse(frameworkName, out var info) ? info : throw new FormatException();
}

/// <summary>
/// Attempts to parse the framework name as provided in <see cref="TargetFrameworkAttribute"/>.
/// </summary>
Expand All @@ -89,6 +99,13 @@ public static bool TryParse(string frameworkName, out DotNetRuntimeInfo info)
return true;
}

/// <summary>
/// Obtains a reference to the default core lib reference of this runtime.
/// </summary>
/// <returns>The reference to the default core lib.</returns>
/// <exception cref="ArgumentException">The runtime information is invalid or unsupported.</exception>
public AssemblyReference GetDefaultCorLib() => KnownCorLibs.FromRuntimeInfo(this);

/// <inheritdoc />
public override string ToString() => $"{Name},Version=v{Version}";
}
Expand Down
146 changes: 128 additions & 18 deletions src/AsmResolver.DotNet/KnownCorLibs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public static class KnownCorLibs
/// References mscorlib.dll, Version=2.0.0.0, PublicKeyToken=B77A5C561934E089. This is used by .NET assemblies
/// targeting the .NET Framework 2.0, 3.0 and 3.5.
/// </summary>
public static readonly AssemblyReference MsCorLib_v2_0_0_0 = new AssemblyReference("mscorlib",
public static readonly AssemblyReference MsCorLib_v2_0_0_0 = new("mscorlib",
new Version(2, 0, 0, 0), false, new byte[]
{
0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89
Expand All @@ -34,7 +34,7 @@ public static class KnownCorLibs
/// References mscorlib.dll, Version=4.0.0.0, PublicKeyToken=B77A5C561934E089. This is used by .NET assemblies
/// targeting the .NET Framework 4.0 and later.
/// </summary>
public static readonly AssemblyReference MsCorLib_v4_0_0_0 = new AssemblyReference("mscorlib",
public static readonly AssemblyReference MsCorLib_v4_0_0_0 = new("mscorlib",
new Version(4, 0, 0, 0), false, new byte[]
{
0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89
Expand All @@ -44,7 +44,7 @@ public static class KnownCorLibs
/// References System.Private.CoreLib.dll, Version=4.0.0.0, PublicKeyToken=7CEC85D7BEA7798E. This is used by .NET
/// assemblies targeting .NET Core 1.0 and later.
/// </summary>
public static readonly AssemblyReference SystemPrivateCoreLib_v4_0_0_0 = new AssemblyReference("System.Private.CoreLib",
public static readonly AssemblyReference SystemPrivateCoreLib_v4_0_0_0 = new("System.Private.CoreLib",
new Version(4, 0, 0, 0), false, new byte[]
{
0x7C, 0xEC, 0x85, 0xD7, 0xBE, 0xA7, 0x79, 0x8E
Expand All @@ -54,7 +54,7 @@ public static class KnownCorLibs
/// References System.Private.CoreLib.dll, Version=5.0.0.0, PublicKeyToken=7CEC85D7BEA7798E. This is used by .NET
/// assemblies targeting .NET 5.0.
/// </summary>
public static readonly AssemblyReference SystemPrivateCoreLib_v5_0_0_0 = new AssemblyReference("System.Private.CoreLib",
public static readonly AssemblyReference SystemPrivateCoreLib_v5_0_0_0 = new("System.Private.CoreLib",
new Version(5, 0, 0, 0), false, new byte[]
{
0x7C, 0xEC, 0x85, 0xD7, 0xBE, 0xA7, 0x79, 0x8E
Expand All @@ -64,7 +64,7 @@ public static class KnownCorLibs
/// References System.Private.CoreLib.dll, Version=6.0.0.0, PublicKeyToken=7CEC85D7BEA7798E. This is used by .NET
/// assemblies targeting .NET 6.0.
/// </summary>
public static readonly AssemblyReference SystemPrivateCoreLib_v6_0_0_0 = new AssemblyReference("System.Private.CoreLib",
public static readonly AssemblyReference SystemPrivateCoreLib_v6_0_0_0 = new("System.Private.CoreLib",
new Version(6, 0, 0, 0), false, new byte[]
{
0x7C, 0xEC, 0x85, 0xD7, 0xBE, 0xA7, 0x79, 0x8E
Expand All @@ -74,37 +74,77 @@ public static class KnownCorLibs
/// References System.Private.CoreLib.dll, Version=7.0.0.0, PublicKeyToken=7CEC85D7BEA7798E. This is used by .NET
/// assemblies targeting .NET 7.0.
/// </summary>
public static readonly AssemblyReference SystemPrivateCoreLib_v7_0_0_0 = new AssemblyReference("System.Private.CoreLib",
public static readonly AssemblyReference SystemPrivateCoreLib_v7_0_0_0 = new("System.Private.CoreLib",
new Version(7, 0, 0, 0), false, new byte[]
{
0x7C, 0xEC, 0x85, 0xD7, 0xBE, 0xA7, 0x79, 0x8E
});

/// <summary>
/// References System.Private.CoreLib.dll, Version=8.0.0.0, PublicKeyToken=7CEC85D7BEA7798E. This is used by .NET
/// assemblies targeting .NET 8.0.
/// </summary>
public static readonly AssemblyReference SystemPrivateCoreLib_v8_0_0_0 = new("System.Private.CoreLib",
new Version(8, 0, 0, 0), false, new byte[]
{
0x7C, 0xEC, 0x85, 0xD7, 0xBE, 0xA7, 0x79, 0x8E
});

/// <summary>
/// References System.Runtime.dll, Version=4.0.0.0, PublicKeyToken=B03F5F7F11D50A3A. This is used by .NET
/// assemblies targeting .NET standard 1.0 and 1.1.
/// </summary>
public static readonly AssemblyReference SystemRuntime_v4_0_0_0 = new("System.Runtime",
new Version(4, 0, 0, 0), false, new byte[]
{
0xB0, 0x3F, 0x5F, 0x7F, 0x11, 0xD5, 0x0A, 0x3A
});

/// <summary>
/// References System.Runtime.dll, Version=4.0.0.0, PublicKeyToken=B03F5F7F11D50A3A. This is used by .NET
/// assemblies targeting .NET standard 1.2.
/// </summary>
public static readonly AssemblyReference SystemRuntime_v4_0_10_0 = new("System.Runtime",
new Version(4, 0, 0, 0), false, new byte[]
Washi1337 marked this conversation as resolved.
Show resolved Hide resolved
{
0xB0, 0x3F, 0x5F, 0x7F, 0x11, 0xD5, 0x0A, 0x3A
});

/// <summary>
/// References System.Runtime.dll, Version=4.0.20.0, PublicKeyToken=B03F5F7F11D50A3A. This is used by .NET
/// assemblies targeting .NET standard 1.3 and 1.4.
/// </summary>
public static readonly AssemblyReference SystemRuntime_v4_0_20_0 = new AssemblyReference("System.Runtime",
public static readonly AssemblyReference SystemRuntime_v4_0_20_0 = new("System.Runtime",
new Version(4, 0, 20, 0), false, new byte[]
{
0xB0, 0x3F, 0x5F, 0x7F, 0x11, 0xD5, 0x0A, 0x3A
});

/// <summary>
/// References System.Runtime.dll, Version=4.0.0.0, PublicKeyToken=B03F5F7F11D50A3A. This is used by .NET
/// assemblies targeting .NET standard 1.5, 1.6 and 1.7.
/// assemblies targeting .NET standard 1.5, 1.6 and 1.7, and .NET Core 1.0 and 1.1.
/// </summary>
public static readonly AssemblyReference SystemRuntime_v4_1_0_0 = new AssemblyReference("System.Runtime",
public static readonly AssemblyReference SystemRuntime_v4_1_0_0 = new("System.Runtime",
new Version(4, 1, 0, 0), false, new byte[]
{
0xB0, 0x3F, 0x5F, 0x7F, 0x11, 0xD5, 0x0A, 0x3A
});

/// <summary>
/// References System.Runtime.dll, Version=4.2.0.0, PublicKeyToken=B03F5F7F11D50A3A. This is used by .NET
/// assemblies targeting .NET Core 2.0.
/// </summary>
public static readonly AssemblyReference SystemRuntime_v4_2_0_0 = new("System.Runtime",
new Version(4, 2, 0, 0), false, new byte[]
{
0xB0, 0x3F, 0x5F, 0x7F, 0x11, 0xD5, 0x0A, 0x3A
});

/// <summary>
/// References System.Runtime.dll, Version=4.2.1.0, PublicKeyToken=B03F5F7F11D50A3A. This is used by .NET
/// assemblies targeting .NET Core 2.1.
/// assemblies targeting .NET Core 2.1 and 3.0.
/// </summary>
public static readonly AssemblyReference SystemRuntime_v4_2_1_0 = new AssemblyReference("System.Runtime",
public static readonly AssemblyReference SystemRuntime_v4_2_1_0 = new("System.Runtime",
new Version(4, 2, 1, 0), false, new byte[]
{
0xB0, 0x3F, 0x5F, 0x7F, 0x11, 0xD5, 0x0A, 0x3A
Expand All @@ -114,7 +154,7 @@ public static class KnownCorLibs
/// References System.Runtime.dll, Version=4.2.2.0, PublicKeyToken=B03F5F7F11D50A3A. This is used by .NET
/// assemblies targeting .NET Core 3.1.
/// </summary>
public static readonly AssemblyReference SystemRuntime_v4_2_2_0 = new AssemblyReference("System.Runtime",
public static readonly AssemblyReference SystemRuntime_v4_2_2_0 = new("System.Runtime",
new Version(4, 2, 2, 0), false, new byte[]
{
0xB0, 0x3F, 0x5F, 0x7F, 0x11, 0xD5, 0x0A, 0x3A
Expand All @@ -124,7 +164,7 @@ public static class KnownCorLibs
/// References System.Runtime.dll, Version=5.0.0.0, PublicKeyToken=B03F5F7F11D50A3A. This is used by .NET
/// assemblies targeting .NET 5.0.
/// </summary>
public static readonly AssemblyReference SystemRuntime_v5_0_0_0 = new AssemblyReference("System.Runtime",
public static readonly AssemblyReference SystemRuntime_v5_0_0_0 = new("System.Runtime",
new Version(5, 0, 0, 0), false, new byte[]
{
0xB0, 0x3F, 0x5F, 0x7F, 0x11, 0xD5, 0x0A, 0x3A
Expand All @@ -134,7 +174,7 @@ public static class KnownCorLibs
/// References System.Runtime.dll, Version=6.0.0.0, PublicKeyToken=B03F5F7F11D50A3A. This is used by .NET
/// assemblies targeting .NET 6.0.
/// </summary>
public static readonly AssemblyReference SystemRuntime_v6_0_0_0 = new AssemblyReference("System.Runtime",
public static readonly AssemblyReference SystemRuntime_v6_0_0_0 = new("System.Runtime",
new Version(6, 0, 0, 0), false, new byte[]
{
0xB0, 0x3F, 0x5F, 0x7F, 0x11, 0xD5, 0x0A, 0x3A
Expand All @@ -144,17 +184,27 @@ public static class KnownCorLibs
/// References System.Runtime.dll, Version=7.0.0.0, PublicKeyToken=B03F5F7F11D50A3A. This is used by .NET
/// assemblies targeting .NET 7.0.
/// </summary>
public static readonly AssemblyReference SystemRuntime_v7_0_0_0 = new AssemblyReference("System.Runtime",
public static readonly AssemblyReference SystemRuntime_v7_0_0_0 = new("System.Runtime",
new Version(7, 0, 0, 0), false, new byte[]
{
0xB0, 0x3F, 0x5F, 0x7F, 0x11, 0xD5, 0x0A, 0x3A
});

/// <summary>
/// References System.Runtime.dll, Version=8.0.0.0, PublicKeyToken=B03F5F7F11D50A3A. This is used by .NET
/// assemblies targeting .NET 8.0.
/// </summary>
public static readonly AssemblyReference SystemRuntime_v8_0_0_0 = new("System.Runtime",
new Version(8, 0, 0, 0), false, new byte[]
{
0xB0, 0x3F, 0x5F, 0x7F, 0x11, 0xD5, 0x0A, 0x3A
});

/// <summary>
/// References netstandard.dll, Version=2.0.0.0, PublicKeyToken=CC7B13FFCD2DDD51. This is used by .NET
/// assemblies targeting .NET standard 2.0.
/// </summary>
public static readonly AssemblyReference NetStandard_v2_0_0_0 = new AssemblyReference("netstandard",
public static readonly AssemblyReference NetStandard_v2_0_0_0 = new("netstandard",
new Version(2, 0, 0, 0), false, new byte[]
{
0xCC, 0x7B, 0x13, 0xFF, 0xCD, 0x2D, 0xDD, 0x51
Expand All @@ -164,7 +214,7 @@ public static class KnownCorLibs
/// References netstandard.dll, Version=2.1.0.0, PublicKeyToken=CC7B13FFCD2DDD51. This is used by .NET
/// assemblies targeting .NET standard 2.1.
/// </summary>
public static readonly AssemblyReference NetStandard_v2_1_0_0 = new AssemblyReference("netstandard",
public static readonly AssemblyReference NetStandard_v2_1_0_0 = new("netstandard",
new Version(2, 1, 0, 0), false, new byte[]
{
0xCC, 0x7B, 0x13, 0xFF, 0xCD, 0x2D, 0xDD, 0x51
Expand All @@ -178,20 +228,80 @@ static KnownCorLibs()
NetStandard_v2_1_0_0,
MsCorLib_v2_0_0_0,
MsCorLib_v4_0_0_0,
SystemRuntime_v4_0_0_0,
SystemRuntime_v4_0_10_0,
SystemRuntime_v4_0_20_0,
SystemRuntime_v4_1_0_0,
SystemRuntime_v4_2_0_0,
SystemRuntime_v4_2_1_0,
SystemRuntime_v4_2_2_0,
SystemRuntime_v5_0_0_0,
SystemRuntime_v6_0_0_0,
SystemRuntime_v7_0_0_0,
SystemRuntime_v8_0_0_0,
SystemPrivateCoreLib_v4_0_0_0,
SystemPrivateCoreLib_v5_0_0_0,
SystemPrivateCoreLib_v6_0_0_0,
SystemPrivateCoreLib_v7_0_0_0
SystemPrivateCoreLib_v7_0_0_0,
SystemPrivateCoreLib_v8_0_0_0,
};

KnownCorLibNames = new HashSet<string>(KnownCorLibReferences.Select(r => r.Name!.Value));
}

/// <summary>
/// Obtains a reference to the default core lib reference for the provided .NET target runtime.
/// </summary>
/// <param name="runtimeInfo">The runtime to target.</param>
/// <returns>The reference to the default core lib.</returns>
/// <exception cref="ArgumentException">The runtime information is invalid or unsupported.</exception>
public static AssemblyReference FromRuntimeInfo(DotNetRuntimeInfo runtimeInfo)
{
if (runtimeInfo.IsNetFramework)
return SelectFrameworkCorLib(runtimeInfo.Version);

if (runtimeInfo.IsNetStandard)
return SelectNetStandardCorLib(runtimeInfo.Version);

if (runtimeInfo.IsNetCoreApp)
return SelectNetCoreCorLib(runtimeInfo.Version);

throw new ArgumentException($"Invalid or unsupported runtime version {runtimeInfo}.");
}

private static AssemblyReference SelectFrameworkCorLib(Version version) => version.Major < 4
? MsCorLib_v2_0_0_0
: MsCorLib_v4_0_0_0;

private static AssemblyReference SelectNetStandardCorLib(Version version)
{
return (version.Major, version.Minor) switch
{
(1, 0 or 1) => SystemRuntime_v4_0_0_0,
(1, 2) => SystemRuntime_v4_0_10_0,
(1, 3 or 4) => SystemRuntime_v4_0_20_0,
(1, 5 or 6 or 7) => SystemRuntime_v4_1_0_0,
(2, 0) => NetStandard_v2_0_0_0,
(2, 1) => NetStandard_v2_1_0_0,
_ => throw new ArgumentException($"Invalid or unsupported .NET standard version {version}.")
};
}

private static AssemblyReference SelectNetCoreCorLib(Version version)
{
return (version.Major, version.Minor) switch
{
(1, 0 or 1) => SystemRuntime_v4_1_0_0,
(2, 0) => SystemRuntime_v4_2_0_0,
(2, 1) or (3, 0) => SystemRuntime_v4_2_1_0,
(3, 1) => SystemRuntime_v4_2_2_0,
(5, 0) => SystemRuntime_v5_0_0_0,
(6, 0) => SystemRuntime_v6_0_0_0,
(7, 0) => SystemRuntime_v7_0_0_0,
(8, 0) => SystemRuntime_v8_0_0_0,
_ => throw new ArgumentException($"Invalid or unsupported .NET or .NET Core version {version}.")
};
}

}
}
16 changes: 14 additions & 2 deletions src/AsmResolver.DotNet/ReflectionAssemblyDescriptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,21 @@ namespace AsmResolver.DotNet
/// </summary>
public class ReflectionAssemblyDescriptor : AssemblyDescriptor
{
private readonly ModuleDefinition _parentModule;
private readonly ModuleDefinition? _parentModule;
private readonly AssemblyName _assemblyName;

/// <summary>
/// Creates a new instance of the <see cref="ReflectionAssemblyDescriptor"/> class.
/// </summary>
/// <param name="assemblyName">The assembly name to import.</param>
public ReflectionAssemblyDescriptor(AssemblyName assemblyName)
: base(new MetadataToken(TableIndex.AssemblyRef, 0))
{
_parentModule = null;
_assemblyName = assemblyName;
Version = assemblyName.Version ?? new Version();
}

/// <summary>
/// Creates a new instance of the <see cref="ReflectionAssemblyDescriptor"/> class.
/// </summary>
Expand Down Expand Up @@ -46,6 +58,6 @@ public override AssemblyReference ImportWith(ReferenceImporter importer) =>
public override byte[]? GetPublicKeyToken() => _assemblyName.GetPublicKeyToken();

/// <inheritdoc />
public override AssemblyDefinition? Resolve() => _parentModule.MetadataResolver.AssemblyResolver.Resolve(this);
public override AssemblyDefinition? Resolve() => _parentModule?.MetadataResolver.AssemblyResolver.Resolve(this);
}
}
25 changes: 25 additions & 0 deletions test/AsmResolver.DotNet.Tests/DotNetRuntimeInfoTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System.Reflection;
using AsmResolver.DotNet.Signatures;
using Xunit;

namespace AsmResolver.DotNet.Tests
{
public class DotNetRuntimeInfoTest
{
[Theory]
[InlineData(".NETFramework,Version=v2.0", "mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
[InlineData(".NETFramework,Version=v3.5", "mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
[InlineData(".NETFramework,Version=v4.0", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
[InlineData(".NETStandard,Version=v1.0", "System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
[InlineData(".NETStandard,Version=v2.0", "netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51")]
[InlineData(".NETCoreApp,Version=v2.0", "System.Runtime, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
[InlineData(".NETCoreApp,Version=v5.0", "System.Runtime, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
public void DefaultCorLib(string name, string expectedCorLib)
{
Assert.Equal(
new ReflectionAssemblyDescriptor(new AssemblyName(expectedCorLib)),
(AssemblyDescriptor) DotNetRuntimeInfo.Parse(name).GetDefaultCorLib(),
SignatureComparer.Default);
}
}
}