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?
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:
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
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.