检索JIT输出

And*_*rew 10 .net c# clr jit .net-assembly

我有兴趣通过C#程序查看实际的x86程序集输出(而不是CLR字节码指令).有没有办法做到这一点?

Mar*_*uła 8

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

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

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

            int x = 5;
mov         dword ptr [ebp-40h],5 
            int y = 6;
mov         dword ptr [ebp-44h],6 
            int z = x + y;
mov         eax,dword ptr [ebp-40h] 
add         eax,dword ptr [ebp-44h] 
mov         dword ptr [ebp-48h],eax 


Iva*_*lov 5

您应该将WinDbg与SOS/SOSEX一起使用,确保您想要查看x86代码的方法在方法表中是JITted,然后使用u命令查看实际的unassembly .因此,您会看到实际的代码.

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

UPD:一些澄清.WinDbg也是一个调试器,但它是原生的.

在这里,您可以详细了解该技术.


Dan*_*ien 5

正如@IvanDanilov 回答的那样,你可以使用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'.");
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

脚步:

  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.dllModLoad中,加载SOS: .loadby sos clr
  6. 运行BPMD以中断要查看反汇编的方法.例如:

    0:000> !BPMD TestArrayCompare.exe TestArrayCompare.Program.AreEqual
    Adding pending breakpoints...
    
  7. 通过运行"Go"命令再次继续: g

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

    0:000> !Name2EE TestArrayCompare.exe TestArrayCompare.Program.AreEqual
    Module:      00a62edc
    Assembly:    TestArrayCompare.exe
    Token:       06000001
    MethodDesc:  00a637a4
    Name:        TestArrayCompare.Program.AreEqual(Byte[], Byte[])
    Not JITTED yet. Use !bpmd -md 00a637a4 to break on run.
    
  9. 在"Not JITTED yet"行中运行BPMD命令.例如:

    0:000> !bpmd -md 00a637a4
    MethodDesc = 00a637a4
    Adding pending breakpoints...
    
  10. 继续: g

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

    0:000> !Name2EE TestArrayCompare.exe TestArrayCompare.Program.AreEqual
    Module:      00a62edc
    Assembly:    TestArrayCompare.exe
    Token:       06000001
    MethodDesc:  00a637a4
    Name:        TestArrayCompare.Program.AreEqual(Byte[], Byte[])
    JITTED Code Address: 00b500c8
    
  12. 使用该u命令进行反汇编,从列出的代码地址开始.例如:

    0:000> u 00b500c8 L20
    00b500c8 55              push    ebp
    00b500c9 8bec            mov     ebp,esp
    00b500cb 57              push    edi
    00b500cc 56              push    esi
    ...
    

(对于上面的内容,我使用的是Windows 8.1 SDK中的WinDbg 6.3.9600.17200 X86.)

一个方便的参考是MSDN上SOS.dll(SOS调试扩展)参考页面.