I'm interested in viewing the actual x86 assembly output by a C# program (not the CLR bytecode instructions). Is there a good way to do this?
问题:
回答1:
You should use WinDbg with SOS/SOSEX, ensure that method you want to see x86 code for is JITted in method tables and then see actual unassembly with u
command. Thus you would see actual code.
As others mentioned here, with ngen you could see code that is not exactly matches actual JIT compilation result. With Visual Studio it is also possible because JIT's compilation depends heavily on the fact if debugger is present or not.
UPD: Some clarification. WinDbg is a debugger also, but it is native one.
Here you can read about the technique in detail.
回答2:
While debugging your application in Visual Studio, you can right-click on a code where you have stopped (using breakpoint) and click "Go to Disassembly". You can debug through native instructions.
As for doing that with *.exe files on disk, maybe you could use NGen to generate native output and then disassemble it (although I never tried that, so I can't guarantee that it will work).
Here are some sample opcodes from simple arithmetic operation that was written in 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
回答3:
As @IvanDanilov answered, you can use WinDbg and SOS. I am answering separately to provide a walk-through.
In this example, I want to view the disassembly of the AreEqual() method from:
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'.");
}
}
}
}
Steps:
- Open WinDbg. From the File menu, select "Open Executable...". Browse to the location of the EXE (in my case,
C:\Users\Daniel\Documents\Visual Studio 2013\Projects\TestArrayCompare\TestArrayCompare\bin\Release\TestArrayCompare.exe
). Add the directory containing the PDB file to the symbol path. For example:
.sympath "C:\Users\Daniel\Documents\Visual Studio 2013\Projects\TestArrayCompare\TestArrayCompare\bin\Release"
In WinDbg's Command window, set a breakpoint when
clr.dll
is loaded via:sxe ld:clr
Continue by running the 'Go' command:
g
- At the
clr.dll
ModLoad, load SOS:.loadby sos clr
Run BPMD to break on the method for which you wish to see the disassembly. For example:
0:000> !BPMD TestArrayCompare.exe TestArrayCompare.Program.AreEqual Adding pending breakpoints...
Continue again by running the 'Go' command:
g
Run Name2EE to see the method descriptor. For example:
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.
Run the BPMD command in the "Not JITTED yet" line. For example:
0:000> !bpmd -md 00a637a4 MethodDesc = 00a637a4 Adding pending breakpoints...
Continue again:
g
You should see "JITTED ..." in the Command window. Re-run the Name2EE command to see the address of the JIT code. For example:
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
Use the
u
command to disassemble, starting at the listed code address. For example:0:000> u 00b500c8 L20 00b500c8 55 push ebp 00b500c9 8bec mov ebp,esp 00b500cb 57 push edi 00b500cc 56 push esi ...
(For the above, I was using WinDbg 6.3.9600.17200 X86 from the Windows 8.1 SDK.)
One handy reference is the SOS.dll (SOS Debugging Extension) reference page on MSDN.
回答4:
You could use Visual Studio Debugger by placing a breakpoint and then viewing the Dissassembly window (Alt+Ctrl+D) or try the Native Image Generator Tool (ngen.exe).
回答5:
You can do a memory dump. However, note that the in-memory code does not necessarily contain every method.
ngen does AOT, or Ahead-of-time code generation, which can be different from JIT code.