检索JIT输出

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

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

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

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

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

在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] 
添加eax,dword ptr [ebp-44h] 
 mov dword ptr [ebp-48h],eax 

正如@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'."); } } } } 

脚步:

  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 ,加载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
     MethodDesc:00a637a4
    名称:TestArrayCompare.Program.AreEqual(Byte [],Byte [])
    尚未JITTED。 使用!bpmd -md 00a637a4中断运行。
    
  9. 在“Not JITTED yet”行中运行BPMD命令。 例如:

     0:000>!bpmd -md 00a637a4
     MethodDesc = 00a637a4
    添加待定断点......
    
  10. 再说一遍: g

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

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

     0:000> u 00b500c8 L20
     00b500c8 55推ebp
     00b500c9 8bec mov ebp,尤其是
     00b500cb 57推edi
     00b500cc 56推esi
     ...
    

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

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

您可以通过放置断点然后查看Dissassembly窗口( Alt + Ctrl + D )或尝试使用本机图像生成器工具 (ngen.exe)来使用Visual Studio Debugger。

你可以做一个内存转储。 但请注意,内存中的代码不一定包含所有方法。

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