检索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'."); } } } }
脚步:
- 打开WinDbg。 从“文件”菜单中,选择“打开可执行文件...”。 浏览到EXE的位置(在我的例子中,
C:\Users\Daniel\Documents\Visual Studio 2013\Projects\TestArrayCompare\TestArrayCompare\bin\Release\TestArrayCompare.exe
)。 -
将包含PDB文件的目录添加到符号路径。 例如:
.sympath“C:\ Users \ Daniel \ Documents \ Visual Studio 2013 \ Projects \ TestArrayCompare \ TestArrayCompare \ bin \ Release”
-
在WinDbg的命令窗口中,通过以下方式加载
clr.dll
时设置断点:sxe ld:clr
-
继续运行'Go'命令:
g
- 在
clr.dll
,加载SOS:.loadby sos clr
-
运行BPMD以中断要查看反汇编的方法。 例如:
0:000>!BPMD TestArrayCompare.exe TestArrayCompare.Program.AreEqual 添加待定断点......
-
通过运行'Go'命令再次继续:
g
-
运行Name2EE以查看方法描述符。 例如:
0:000>!Name2EE TestArrayCompare.exe TestArrayCompare.Program.AreEqual 模块:00a62edc 汇编:TestArrayCompare.exe 令牌:06000001 MethodDesc:00a637a4 名称:TestArrayCompare.Program.AreEqual(Byte [],Byte []) 尚未JITTED。 使用!bpmd -md 00a637a4中断运行。
-
在“Not JITTED yet”行中运行BPMD命令。 例如:
0:000>!bpmd -md 00a637a4 MethodDesc = 00a637a4 添加待定断点......
-
再说一遍:
g
-
您应该在命令窗口中看到“JITTED ...”。 重新运行Name2EE命令以查看JIT代码的地址。 例如:
0:000>!Name2EE TestArrayCompare.exe TestArrayCompare.Program.AreEqual 模块:00a62edc 汇编:TestArrayCompare.exe 令牌:06000001 MethodDesc:00a637a4 名称:TestArrayCompare.Program.AreEqual(Byte [],Byte []) JITTED代码地址:00b500c8
-
从列出的代码地址开始,使用
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代码不同。