【问题标题】:Retrieve JIT output检索 JIT 输出
【发布时间】:2011-10-19 04:44:22
【问题描述】:

我有兴趣查看 C# 程序的实际 x86 程序集输出(不是 CLR 字节码指令)。有什么好办法吗?

【问题讨论】:

    标签: c# .net clr jit .net-assembly


    【解决方案1】:

    在 Visual Studio 中调试应用程序时,您可以右键单击已停止的代码(使用断点),然后单击“转到反汇编”。您可以通过原生指令进行调试。

    至于使用磁盘上的 *.exe 文件,也许你可以使用 NGen 生成本机输出然后反汇编它(虽然我从未尝试过,所以我不能保证它会工作)。

    以下是用 c# 编写的简单算术运算的一些示例操作码:

    诠释 x = 5; mov dword ptr [ebp-40h],5 整数 y = 6; mov dword ptr [ebp-44h],6 int z = x + y; mov eax,dword ptr [ebp-40h] 添加 eax,dword ptr [ebp-44h] mov dword ptr [ebp-48h],eax

    【讨论】:

    • 注意,如果要查看实际优化后的代码,需要按照here的步骤进行操作
    【解决方案2】:

    作为@IvanDanilov answered,您可以使用WinDbg 和SOS。我将单独回答以提供演练。

    在这个例子中,我想从以下位置查看 AreEqual() 方法的反汇编:

    using System;
    
    namespace TestArrayCompare
    {
        class Program
        {
            static bool AreEqual(byte[] a1, byte[] a2)
            {
                bool result = true;
                for (int i = 0; i < a1.Length; ++i)
                {
                    if (a1[i] != a2[i])
                        result = false;
                }
                return result;
            }
    
            static void Main(string[] args)
            {
                byte[] a1 = new byte[100];
                byte[] a2 = new byte[100];
                if (AreEqual(a1, a2))
                {
                    Console.WriteLine("`a1' equals `a2'.");
                }
                else
                {
                    Console.WriteLine("`a1' does not equal `a2'.");
                }
            }
        }
    }
    

    步骤:

    1. 打开 WinDbg。从“文件”菜单中,选择“打开可执行文件...”。浏览到 EXE 的位置(在我的例子中,C:\Users\Daniel\Documents\Visual Studio 2013\Projects\TestArrayCompare\TestArrayCompare\bin\Release\TestArrayCompare.exe)。
    2. 将包含 PDB 文件的目录添加到符号路径。例如:

      .sympath "C:\Users\Daniel\Documents\Visual Studio 2013\Projects\TestArrayCompare\TestArrayCompare\bin\Release"
    3. 在WinDbg的命令窗口中,当clr.dll通过以下方式加载时设置断点:

      sxe ld:clr
    4. 继续运行“Go”命令:g

    5. clr.dll ModLoad,加载 SOS:.loadby sos clr
    6. 运行 BPMD 以中断您希望查看其反汇编的方法。例如:

      0:000> !BPMD TestArrayCompare.exe TestArrayCompare.Program.AreEqual 添加挂起的断点...
    7. 通过运行“Go”命令再次继续:g

    8. 运行 Name2EE 以查看方法描述符。例如:

      0:000> !Name2EE TestArrayCompare.exe TestArrayCompare.Program.AreEqual 模块:00a62edc 程序集:TestArrayCompare.exe 代币:06000001 方法描述:00a637a4 名称:TestArrayCompare.Program.AreEqual(Byte[], Byte[]) 还没有 JITTED。使用 !bpmd -md 00a637a4 在运行时中断。
    9. 在“尚未 JITTED”行中运行 BPMD 命令。例如:

      0:000> !bpmd -md 00a637a4 方法描述 = 00a637a4 添加挂起的断点...
    10. 再次继续:g

    11. 您应该在命令窗口中看到“JITTED ...”。重新运行 Name2EE 命令查看 JIT 代码的地址。例如:

      0:000> !Name2EE TestArrayCompare.exe TestArrayCompare.Program.AreEqual 模块:00a62edc 程序集:TestArrayCompare.exe 代币:06000001 方法描述:00a637a4 名称:TestArrayCompare.Program.AreEqual(Byte[], Byte[]) JITTED代码地址:00b500c8
    12. 使用u 命令反汇编,从列出的代码地址开始。例如:

      0:000> 00b500c8 L20 00b500c8 55 推送 ebp 00b500c9 8bec 移动 ebp,esp 00b500cb 57 推 edi 00b500cc 56推esi ...

    (对于上述情况,我使用的是 Windows 8.1 SDK 中的 WinDbg 6.3.9600.17200 X86。)

    一个方便的参考是SOS.dll (SOS Debugging Extension) reference page on MSDN

    【讨论】:

      【解决方案3】:

      您应该将 WinDbg 与 SOS/SOSEX 一起使用,确保您想要查看 x86 代码的方法在方法表中进行了 JIT 处理,然后使用 u 命令查看实际的反汇编。这样你就可以看到实际的代码了。

      正如其他人在这里提到的,使用 ngen 您可以看到与实际 JIT 编译结果不完全匹配的代码。使用 Visual Studio 也是可能的,因为 JIT 的编译很大程度上取决于调试器是否存在这一事实。

      UPD:一些澄清。 WinDbg 也是一个调试器,但它是 native 一个。

      Here你可以详细阅读该技术。

      【讨论】:

        【解决方案4】:

        您可以通过放置断点然后查看反汇编窗口 (Alt+Ctrl+D) 或尝试 Native Image Generator Tool (ngen.exe) 来使用 Visual Studio 调试器。

        【讨论】:

          【解决方案5】:

          您可以进行内存转储。但是请注意,内存中的代码不一定包含所有方法。

          ngen 执行 AOT 或 Ahead-of-time 代码生成,这可能与 JIT 代码不同。

          【讨论】:

            猜你喜欢
            • 2019-09-16
            • 1970-01-01
            • 1970-01-01
            • 2012-06-12
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-09-09
            • 2015-01-15
            相关资源
            最近更新 更多