首页 > 解决方案 > 在 Calli 指令中使用 Reflection.Emit 生成 modopt

问题描述

我正在尝试使用 Reflection.Emit 为Call以下代码的方法生成代码:

public unsafe class Program
{
    public struct ATest
    {
        public int Test;
    }
    
    public struct Test
    {
        public Vtable* vtbl;
        
        public struct Vtable
        {
            public delegate * unmanaged[Stdcall]<Test*, ATest> ptr;
        }
    }
    
    public static ATest Call(Test* instance)
    {
        return ((delegate * unmanaged[Stdcall, MemberFunction]<Test*, ATest>)instance->vtbl->ptr)(instance);
    }
    
}

我已经使用sharplab.io反编译了该方法并得到了以下msil:

// Methods
.method public hidebysig static 
    valuetype Program/ATest Call (
        valuetype Program/Test* 'instance'
    ) cil managed 
{
    // Method begins at RVA 0x2050
    // Code size 25 (0x19)
    .maxstack 2
    .locals init (
        [0] method unmanaged valuetype Program/ATest modopt([System.Private.CoreLib]System.Runtime.CompilerServices.CallConvMemberFunction) modopt([System.Private.CoreLib]System.Runtime.CompilerServices.CallConvStdcall) *(valuetype Program/Test*),
        [1] valuetype Program/ATest
    )

    IL_0000: nop
    IL_0001: ldarg.0
    IL_0002: ldfld valuetype Program/Test/Vtable* Program/Test::vtbl
    IL_0007: ldfld method unmanaged stdcall valuetype Program/ATest *(valuetype Program/Test*) Program/Test/Vtable::ptr
    IL_000c: stloc.0
    IL_000d: ldarg.0
    IL_000e: ldloc.0
    IL_000f: calli unmanaged valuetype Program/ATest modopt([System.Private.CoreLib]System.Runtime.CompilerServices.CallConvMemberFunction) modopt([System.Private.CoreLib]System.Runtime.CompilerServices.CallConvStdcall)(valuetype Program/Test*)
    IL_0014: stloc.1
    IL_0015: br.s IL_0017

    IL_0017: ldloc.1
    IL_0018: ret
} // end of method Program::Call

我尝试使用反射.emit 生成 MSIL 指令,但我不知道如何发出该行IL_000f

var il = dynamicMethod.GetILGenerator();

il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, vtableField);
il.Emit(OpCodes.Ldfld, methodField);
il.Emit(OpCodes.Stloc_0);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldloc_0);

il.EmitCalli(???);

问题是,MSIL 中的这条线同时具有modopt(MemberFunction)and mopopt(Stdcall),我没有看到这在il.EmitCalli方法中的任何地方都暴露出来。

有人可以帮忙吗?

标签: c#.netcilreflection.emit

解决方案


如问题https://github.com/dotnet/runtime/issues/11354中所述,目前无法在反射堆栈中使用函数指针(当前typeof(delegate* ...)始终返回IntPtr),因此无法使 Reflection.Emit 可靠地工作在这种情况下。


推荐阅读