Получить вывод JIT
Я заинтересован в просмотре фактического вывода сборки x86 программой C# (не инструкциями байт-кода CLR). Есть ли хороший способ сделать это?
5 ответов
Вы должны использовать WinDbg с SOS/SOSEX, убедиться, что метод, для которого вы хотите увидеть код x86, JITted в таблицах методов, а затем увидеть фактическую разборку с u
команда. Таким образом, вы увидите реальный код.
Как уже упоминалось здесь, с помощью 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
Продолжите, выполнив команду "Перейти":
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 MethodDesc: 00a637a4 Имя: TestArrayCompare.Program.AreEqual(Byte[], Byte[]) Еще не встряхнуло. Используйте! Bpmd -md 00a637a4, чтобы разбить на бегу.
Запустите команду 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 push ebp 00b500c9 8bec mov ebp, esp 00b500cb 57 push edi 00b500cc 56 push esi...
(Для вышеупомянутого я использовал WinDbg 6.3.9600.17200 X86 из Windows 8.1 SDK.)
Одной из полезных ссылок является справочная страница SOS.dll (SOS Debugging Extension) на MSDN.
Вы можете использовать отладчик Visual Studio, установив точку останова, а затем просмотрев окно "Разборка" (Alt + Ctrl + D), или попробуйте инструмент Native Image Generator Tool (ngen.exe).
Вы можете сделать дамп памяти. Однако обратите внимание, что код в памяти не обязательно содержит каждый метод.
ngen выполняет генерацию кода AOT или Ahead-of-time, которая может отличаться от кода JIT.