Skip to content

Commit

Permalink
Merge pull request #524 from Washi1337/development
Browse files Browse the repository at this point in the history
5.5.1
  • Loading branch information
Washi1337 authored Feb 27, 2024
2 parents 6f0a383 + 6b12ace commit 78ce89a
Show file tree
Hide file tree
Showing 59 changed files with 541 additions and 183 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ x64/
build/
[Bb]in/
[Oo]bj/
artifacts/

# MSTest test Results
[Tt]est[Rr]esult*/
Expand Down
6 changes: 6 additions & 0 deletions AsmResolver.sln
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,14 @@ Microsoft Visual Studio Solution File, Format Version 12.00
VisualStudioVersion = 17.0.31919.166
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{34A95168-A162-4F6A-803B-B6F221FE9EA6}"
ProjectSection(SolutionItems) = preProject
src\Directory.Build.props = src\Directory.Build.props
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{786C1732-8C96-45DD-97BB-639C9AA7F45B}"
ProjectSection(SolutionItems) = preProject
test\Directory.Build.props = test\Directory.Build.props
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsmResolver", "src\AsmResolver\AsmResolver.csproj", "{4EA3F800-1A1B-4465-931F-4E9949C3373B}"
EndProject
Expand Down
5 changes: 3 additions & 2 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
<Project>

<PropertyGroup>
<Copyright>Copyright © Washi 2016-2023</Copyright>
<Copyright>Copyright © Washi 2016-2024</Copyright>
<PackageProjectUrl>https://github.com/Washi1337/AsmResolver</PackageProjectUrl>
<PackageLicense>https://github.com/Washi1337/AsmResolver/LICENSE.md</PackageLicense>
<RepositoryUrl>https://github.com/Washi1337/AsmResolver</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<LangVersion>10</LangVersion>
<Version>5.5.0</Version>
<Version>5.5.1</Version>
<Deterministic>true</Deterministic>
<UseArtifactsOutput>true</UseArtifactsOutput>
</PropertyGroup>

</Project>
8 changes: 4 additions & 4 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
- master

image: Visual Studio 2022
version: 5.5.0-master-build.{build}
version: 5.5.1-master-build.{build}
configuration: Release

skip_commits:
Expand All @@ -18,7 +18,7 @@
verbosity: minimal

artifacts:
- path: '**\*.nupkg'
- path: 'artifacts\package\release\*.nupkg'

deploy:
provider: NuGet
Expand All @@ -33,7 +33,7 @@
- development

image: Visual Studio 2022
version: 5.5.0-dev-build.{build}
version: 5.5.1-dev-build.{build}
configuration: Release

skip_commits:
Expand All @@ -47,4 +47,4 @@
verbosity: minimal

artifacts:
- path: '**\*.nupkg'
- path: 'artifacts\package\release\*.nupkg'
10 changes: 10 additions & 0 deletions docs/guides/dotnet/importing.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,16 @@ imported through reflection include:
is created).
- Generic parameters.
- Generic type instantiations.
- Function pointer types (.NET 8.0+ only. TFM doesn't matter for this, the runtime used at runtime is all that matters.) (!!WARNING!! )

> [!WARNING]
> Function pointer `Type` instances lose their calling conventions unless attained with
> `GetModified(Field/Property/Parameter)Type`. This includes `typeof`!
> `typeof(delegate*unmanaged[Cdecl]<void>)` is the same as `typeof(delegate*managed<void>)`.
> `Import(Field/Method)` will also strip the calling conventions from function pointers
> that are the types of fields or in method signatures.
> If you need to handle this, manually set the types in the resulting
> `IMethodDefOrRef` or `MemberReference` to the appropriate type from `ImportType`.
Instantiations of generic methods are also supported.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@
<Title>AsmResolver.DotNet.Dynamic</Title>
<Description>Dynamic method support for the AsmResolver executable file inspection toolsuite.</Description>
<PackageTags>exe pe directories imports exports resources dotnet cil inspection manipulation assembly disassembly dynamic</PackageTags>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<NoWarn>1701;1702;NU5105</NoWarn>
<TargetFrameworks>net6.0;netcoreapp3.1;netstandard2.0;netstandard2.1</TargetFrameworks>
<Nullable>enable</Nullable>
</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
Expand All @@ -23,9 +20,9 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Nullable" Version="1.3.1">
<PrivateAssets>all</PrivateAssets>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public DynamicCilOperandResolver(SerializedModuleDefinition contextModule, CilMe
case TableIndex.TypeDef:
object? type = _tokens[(int)token.Rid];
if (type is RuntimeTypeHandle runtimeTypeHandle)
return _importer.ImportType(Type.GetTypeFromHandle(runtimeTypeHandle));
return _importer.ImportType(Type.GetTypeFromHandle(runtimeTypeHandle)!);
break;

case TableIndex.Field:
Expand Down
5 changes: 4 additions & 1 deletion src/AsmResolver.DotNet.Dynamic/DynamicMethodDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,10 @@ private static CilMethodBody CreateDynamicMethodBody(MethodDefinition method, ob
// if the DynamicMethod code is not flushed yet into the resolver (e.g., it hasn't been invoked yet).
object? dynamicILInfo = null;
if (FieldReader.TryReadField<MethodBase>(resolver, "m_method", out var m) && m is not null)
FieldReader.TryReadField(m, "m_DynamicILInfo", out dynamicILInfo);
{
if (!FieldReader.TryReadField(m, "m_DynamicILInfo", out dynamicILInfo))
FieldReader.TryReadField(m, "_dynamicILInfo", out dynamicILInfo);
}

// Extract all required information to construct the body.
byte[]? code;
Expand Down
6 changes: 4 additions & 2 deletions src/AsmResolver.DotNet.Dynamic/DynamicMethodHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@ public static object ResolveDynamicResolver(object dynamicMethodObj)

if (dynamicMethodObj.GetType().FullName == "System.Reflection.Emit.DynamicMethod")
{
object? resolver = FieldReader.ReadField<object>(dynamicMethodObj, "m_resolver");
object? resolver =
FieldReader.ReadField<object>(dynamicMethodObj, "m_resolver")
?? FieldReader.ReadField<object>(dynamicMethodObj, "_resolver");
if (resolver != null)
dynamicMethodObj = resolver;
}
Expand All @@ -115,7 +117,7 @@ public static object ResolveDynamicResolver(object dynamicMethodObj)
object? ilGenerator = dynamicMethodObj
.GetType()
.GetRuntimeMethods()
.First(q => q.Name == "GetILGenerator")
.First(q => q.Name == "GetILGenerator" && q.GetParameters().Length == 0)
.Invoke(dynamicMethodObj, null);

//Create instance of dynamicResolver
Expand Down
9 changes: 3 additions & 6 deletions src/AsmResolver.DotNet/AsmResolver.DotNet.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@
<Title>AsmResolver.DotNet</Title>
<Description>High level .NET image models for the AsmResolver executable file inspection toolsuite.</Description>
<PackageTags>exe pe directories imports exports resources dotnet cil inspection manipulation assembly disassembly</PackageTags>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<NoWarn>1701;1702;NU5105</NoWarn>
<Nullable>enable</Nullable>
<TargetFrameworks>net6.0;netcoreapp3.1;netstandard2.0;netstandard2.1</TargetFrameworks>
<IsTrimmable>true</IsTrimmable>
</PropertyGroup>

Expand All @@ -24,9 +21,9 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Nullable" Version="1.3.1">
<PrivateAssets>all</PrivateAssets>
Expand Down
25 changes: 17 additions & 8 deletions src/AsmResolver.DotNet/Code/Cil/CilInstructionCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ private bool TryOptimizeVariable(CilInstruction instruction)
{
var variable = instruction.GetLocalVariable(Owner.LocalVariables);

CilOpCode code = instruction.OpCode;
var code = instruction.OpCode;
object? operand = instruction.Operand;

if (instruction.IsLdloc())
Expand All @@ -470,7 +470,7 @@ private bool TryOptimizeVariable(CilInstruction instruction)
1 => (CilOpCodes.Ldloc_1, null),
2 => (CilOpCodes.Ldloc_2, null),
3 => (CilOpCodes.Ldloc_3, null),
{} x when x >= byte.MinValue && x <= byte.MaxValue => (CilOpCodes.Ldloc_S, variable),
<= byte.MaxValue and >= byte.MinValue => (CilOpCodes.Ldloc_S, variable),
_ => (CilOpCodes.Ldloc, variable),
};
}
Expand All @@ -482,10 +482,15 @@ private bool TryOptimizeVariable(CilInstruction instruction)
1 => (CilOpCodes.Stloc_1, null),
2 => (CilOpCodes.Stloc_2, null),
3 => (CilOpCodes.Stloc_3, null),
{} x when x >= byte.MinValue && x <= byte.MaxValue => (CilOpCodes.Stloc_S, variable),
<= byte.MaxValue and >= byte.MinValue => (CilOpCodes.Stloc_S, variable),
_ => (CilOpCodes.Stloc, variable),
};
}
else if (instruction.OpCode.Code == CilCode.Ldloca)
{
if (variable.Index is >= byte.MinValue and <= byte.MaxValue)
code = CilOpCodes.Ldloca_S;
}

if (code != instruction.OpCode)
{
Expand All @@ -501,7 +506,7 @@ private bool TryOptimizeArgument(CilInstruction instruction)
{
var parameter = instruction.GetParameter(Owner.Owner.Parameters);

CilOpCode code = instruction.OpCode;
var code = instruction.OpCode;
object? operand = instruction.Operand;

if (instruction.IsLdarg())
Expand All @@ -512,15 +517,19 @@ private bool TryOptimizeArgument(CilInstruction instruction)
1 => (CilOpCodes.Ldarg_1, null),
2 => (CilOpCodes.Ldarg_2, null),
3 => (CilOpCodes.Ldarg_3, null),
{} x when x >= byte.MinValue && x <= byte.MaxValue => (CilOpCodes.Ldarg_S, parameter),
>= byte.MinValue and <= byte.MaxValue => (CilOpCodes.Ldarg_S, parameter),
_ => (CilOpCodes.Ldarg, parameter),
};
}
else if (instruction.IsStarg())
{
code = parameter.MethodSignatureIndex <= byte.MaxValue
? CilOpCodes.Starg_S
: CilOpCodes.Starg;
if (parameter.MethodSignatureIndex <= byte.MaxValue)
code = CilOpCodes.Starg_S;
}
else if (instruction.OpCode.Code == CilCode.Ldarga)
{
if (parameter.Index is >= byte.MinValue and <= byte.MaxValue)
code = CilOpCodes.Ldarga_S;
}

if (code != instruction.OpCode)
Expand Down
31 changes: 31 additions & 0 deletions src/AsmResolver.DotNet/Collections/MemberCollection.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using AsmResolver.Collections;

namespace AsmResolver.DotNet.Collections
{
/// <summary>
/// Represents an indexed member collection where each member is owned by some object, and prevents the member from
/// being added to any other instance of the collection.
/// </summary>
/// <typeparam name="TOwner">The type of the owner object.</typeparam>
/// <typeparam name="TMember">The type of elements to store.</typeparam>
public class MemberCollection<TOwner, TMember> : OwnedCollection<TOwner, TMember>
where TOwner : class
where TMember : class, IOwnedCollectionElement<TOwner>
{
internal MemberCollection(TOwner owner)
: base(owner)
{
}

internal MemberCollection(TOwner owner, int capacity)
: base(owner, capacity)
{
}

internal void AddNoOwnerCheck(TMember member)
{
member.Owner = Owner;
Items.Add(member);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using AsmResolver.Collections;

namespace AsmResolver.DotNet.Collections
{
/// <summary>
/// Provides an implementation of a list of method semantics that are associated to a property or event.
/// </summary>
public class MethodSemanticsCollection : OwnedCollection< IHasSemantics, MethodSemantics>
public class MethodSemanticsCollection : MemberCollection<IHasSemantics, MethodSemantics>
{
/// <summary>
/// Creates a new instance of the <see cref="MethodSemanticsCollection"/> class.
Expand All @@ -36,7 +34,7 @@ internal bool ValidateMembership
set;
} = true;

private void AssertSemanticsValidity([NotNull] MethodSemantics item)
private void AssertSemanticsValidity(MethodSemantics item)
{
if (!ValidateMembership)
return;
Expand Down
12 changes: 2 additions & 10 deletions src/AsmResolver.DotNet/ModuleDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ public class ModuleDefinition :
IHasCustomAttribute,
IOwnedCollectionElement<AssemblyDefinition>
{
private static MethodInfo? GetHINSTANCEMethod;

private readonly LazyVariable<ModuleDefinition, Utf8String?> _name;
private readonly LazyVariable<ModuleDefinition, Guid> _mvid;
private readonly LazyVariable<ModuleDefinition, Guid> _encId;
Expand Down Expand Up @@ -166,14 +164,9 @@ public static ModuleDefinition FromModuleBaseAddress(IntPtr hInstance, PEMapping
/// <returns>The module.</returns>
public static ModuleDefinition FromModule(Module module, ModuleReaderParameters readerParameters)
{
// We get the base address using GetHINSTANCE, but this method is unfortunately not shipped with
// .NET Standard 2.0, so we need to resort to reflection for this.
GetHINSTANCEMethod ??= typeof(Marshal).GetMethod("GetHINSTANCE", new[] { typeof(Module) });

var handle = (IntPtr) GetHINSTANCEMethod?.Invoke(null, new object[] { module })!;
if (handle == IntPtr.Zero)
if (!ReflectionHacks.TryGetHINSTANCE(module, out var handle))
throw new NotSupportedException("The current platform does not support getting the base address of an instance of System.Reflection.Module.");
if (handle == (IntPtr) (-1))
if (handle == -1)
throw new NotSupportedException("Provided module does not have a module base address.");

// Dynamically loaded modules are in their unmapped form, as opposed to modules loaded normally by the
Expand Down Expand Up @@ -302,7 +295,6 @@ public ModuleDefinition(Utf8String? name)
Name = name;

CorLibTypeFactory = CorLibTypeFactory.CreateMscorlib40TypeFactory(this);
AssemblyReferences.Add((AssemblyReference)CorLibTypeFactory.CorLibScope);
MetadataResolver = new DefaultMetadataResolver(new DotNetFrameworkAssemblyResolver());

TopLevelTypes.Add(new TypeDefinition(null, TypeDefinition.ModuleTypeName, 0));
Expand Down
37 changes: 37 additions & 0 deletions src/AsmResolver.DotNet/ReferenceImporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,8 @@ public virtual TypeSignature ImportTypeSignature(Type type)
return new GenericParameterSignature(
type.DeclaringMethod != null ? GenericParameterType.Method : GenericParameterType.Type,
type.GenericParameterPosition);
if (ReflectionHacks.GetIsFunctionPointer(type))
return ImportFunctionPointerType(type);

var corlibType = TargetModule.CorLibTypeFactory.FromName(type.Namespace, type.Name);
if (corlibType != null)
Expand Down Expand Up @@ -355,6 +357,41 @@ private TypeSignature ImportGenericType(Type type)
return result;
}

private TypeSignature ImportFunctionPointerType(Type type)
{
var returnType = ImportTypeSignature(ReflectionHacks.GetFunctionPointerReturnType(type));
var callConvs = ReflectionHacks.GetFunctionPointerCallingConventions(type);
var callConv = CallingConventionAttributes.Default;
if (callConvs.Length == 1)
{
var cc = callConvs[0];
callConv = cc.FullName switch
{
"System.Runtime.CompilerServices.CallConvCdecl" => CallingConventionAttributes.C,
"System.Runtime.CompilerServices.CallConvFastcall" => CallingConventionAttributes.FastCall,
"System.Runtime.CompilerServices.CallConvStdcall" => CallingConventionAttributes.StdCall,
"System.Runtime.CompilerServices.CallConvThiscall" => CallingConventionAttributes.ThisCall,
_ => CallingConventionAttributes.Default
};
if (callConv == CallingConventionAttributes.Default)
returnType = returnType.MakeModifierType(ImportType(cc), false);
}
else
{
foreach (var cc in callConvs)
returnType = returnType.MakeModifierType(ImportType(cc), false);
}

if (callConv == default && ReflectionHacks.GetIsUnmanagedFunctionPointer(type))
callConv = CallingConventionAttributes.Unmanaged;

return new MethodSignature(
callConv,
returnType,
ReflectionHacks.GetFunctionPointerParameterTypes(type).Select(ImportTypeSignature)
).MakeFunctionPointerType();
}

/// <summary>
/// Imports a reference to- or an instantiation of a method into the module.
/// </summary>
Expand Down
Loading

0 comments on commit 78ce89a

Please sign in to comment.