C# 有没有办法查看DynamicMethod生成的x86汇编代码?

C# 有没有办法查看DynamicMethod生成的x86汇编代码?,c#,.net,.net-assembly,cil,C#,.net,.net Assembly,Cil,我正在构建一种动态方法,使用ILGenerator动态插入操作码。我正在使用VisualStudio插件以DynamicMethod查看IL代码,所以这不是问题 不过,我希望看到JITer发出的最终x86代码。Visual Studio 2017不允许我使用x86汇编代码,无论我如何尝试。它在堆栈中显示为轻量级函数,VS将跳过它 是否有办法查看通过编译DynamicMethod生成的x86汇编代码?至少在Visual Studio VS2017中,似乎没有办法这样做。因此,使用WinDbg作为W

我正在构建一种动态方法,使用ILGenerator动态插入操作码。我正在使用VisualStudio插件以DynamicMethod查看IL代码,所以这不是问题

不过,我希望看到JITer发出的最终x86代码。Visual Studio 2017不允许我使用x86汇编代码,无论我如何尝试。它在堆栈中显示为轻量级函数,VS将跳过它


是否有办法查看通过编译DynamicMethod生成的x86汇编代码?

至少在Visual Studio VS2017中,似乎没有办法这样做。因此,使用WinDbg作为Windows SDK的一部分可能会更幸运

为了让事情变得更简单,我建议让您的应用程序输出一些有用的数据,这将有助于使用WinDbg在内存中查找代码。具体地说,如果您可以在从动态方法创建的委托上输出调用Marshal.GetFunctionPointerForDelegate的结果,这将使您非常接近该方法的代码。您需要为此使用非泛型委托,因此,如果您正在使用动态方法创建Func委托,则需要临时将其替换为非泛型委托

例如:

private delegate int AddDelegate(int a, int b);

public static void DynamicMethodTest()
{
    // Create a DynamicMethod that adds its two int parameters
    // Passing "true" as the final (restrictedSkipVisibility) parameter causes the method to be JITted immediately when you call .CreateDelegate()
    var dynamicAdd = new DynamicMethod("Add", typeof(int), new[] { typeof(int), typeof(int) }, true);
    var il = dynamicAdd.GetILGenerator();
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Ldarg_1);
    il.Emit(OpCodes.Add);
    il.Emit(OpCodes.Ret);

    // Use the non-generic AddDelegate defined above, rather than a generic one like Func<int, int, int> so that Marshal.GetFunctionPointerForDelegate() works
    var addDelegate = (AddDelegate)dynamicAdd.CreateDelegate(typeof(AddDelegate));
    Console.WriteLine("Function Pointer: 0x{0:x16}", Marshal.GetFunctionPointerForDelegate(addDelegate).ToInt64());

    Debugger.Break();
}
从这里可以看到动态方法的代码

首先对上面的函数指针输出使用u unassemble命令:

0:000> u 0x0000000012345678 L1

00000000`12345678 49ba2143658700000000 mov r10,87654321h
这里,第一条指令将指向实际动态方法代码的指针地址加载到r10中,因此我们使用dp Display memory-pointer命令来获取指针的目标:

0:000> dp 0x87654321 L1
00000000`87654321  000007fe`9abcdef0
在此地址上运行u unassemble,或在“反汇编”窗口视图->反汇编中输入地址以获取动态方法的代码:

0:000> u 000007fe`9abcdef0

000007fe`9abcdef0 8d0411          lea     eax,[rcx+rdx]
000007fe`9abcdef3 c3              ret
...
默认情况下,unassemble命令输出8条指令,您可以向该命令添加长度说明符来更改此设置,例如,添加L20将输出32条0x20指令-由您确定函数的完整范围

或者,您可能会发现使用WinDbg的.NET调试扩展来执行转储动态方法代码的最后一步更容易,在这种情况下,您首先需要使用.loadby sos clr在每个调试会话中只加载一次所需的扩展,然后使用!改为在代码地址上使用u:

0:000> !u 000007fe`9abcdef0

Normal JIT generated code
DynamicClass.Add(Int32, Int32)
Begin 000007fe9abcdef0, size 4
>>> 000007fe`9abcdef0 8d0411          lea     eax,[rcx+rdx]
000007fe`9abcdef3 c3              ret
上述所有示例均为64位模式,但在32位模式下,方法基本相同。

0:000> !u 000007fe`9abcdef0

Normal JIT generated code
DynamicClass.Add(Int32, Int32)
Begin 000007fe9abcdef0, size 4
>>> 000007fe`9abcdef0 8d0411          lea     eax,[rcx+rdx]
000007fe`9abcdef3 c3              ret