【发布时间】:2011-10-19 04:44:22
【问题描述】:
我有兴趣查看 C# 程序的实际 x86 程序集输出(不是 CLR 字节码指令)。有什么好办法吗?
【问题讨论】:
标签: c# .net clr jit .net-assembly
我有兴趣查看 C# 程序的实际 x86 程序集输出(不是 CLR 字节码指令)。有什么好办法吗?
【问题讨论】:
标签: c# .net clr jit .net-assembly
在 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【讨论】:
作为@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'.");
}
}
}
}
步骤:
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通过以下方式加载时设置断点:
继续运行“Go”命令:g
clr.dll ModLoad,加载 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 方法描述:00a637a4 名称:TestArrayCompare.Program.AreEqual(Byte[], Byte[]) 还没有 JITTED。使用 !bpmd -md 00a637a4 在运行时中断。在“尚未 JITTED”行中运行 BPMD 命令。例如:
0:000> !bpmd -md 00a637a4 方法描述 = 00a637a4 添加挂起的断点...再次继续:g
您应该在命令窗口中看到“JITTED ...”。重新运行 Name2EE 命令查看 JIT 代码的地址。例如:
0:000> !Name2EE TestArrayCompare.exe TestArrayCompare.Program.AreEqual 模块:00a62edc 程序集:TestArrayCompare.exe 代币:06000001 方法描述:00a637a4 名称:TestArrayCompare.Program.AreEqual(Byte[], Byte[]) JITTED代码地址:00b500c8使用u 命令反汇编,从列出的代码地址开始。例如:
(对于上述情况,我使用的是 Windows 8.1 SDK 中的 WinDbg 6.3.9600.17200 X86。)
一个方便的参考是SOS.dll (SOS Debugging Extension) reference page on MSDN。
【讨论】:
您应该将 WinDbg 与 SOS/SOSEX 一起使用,确保您想要查看 x86 代码的方法在方法表中进行了 JIT 处理,然后使用 u 命令查看实际的反汇编。这样你就可以看到实际的代码了。
正如其他人在这里提到的,使用 ngen 您可以看到与实际 JIT 编译结果不完全匹配的代码。使用 Visual Studio 也是可能的,因为 JIT 的编译很大程度上取决于调试器是否存在这一事实。
UPD:一些澄清。 WinDbg 也是一个调试器,但它是 native 一个。
Here你可以详细阅读该技术。
【讨论】:
您可以通过放置断点然后查看反汇编窗口 (Alt+Ctrl+D) 或尝试 Native Image Generator Tool (ngen.exe) 来使用 Visual Studio 调试器。
【讨论】:
您可以进行内存转储。但是请注意,内存中的代码不一定包含所有方法。
ngen 执行 AOT 或 Ahead-of-time 代码生成,这可能与 JIT 代码不同。
【讨论】: