дизассемблирование C#: почему машинный код DUMPBIN так отличается от дизассемблирования Debug?


Предположим, что это моя программа simpleCsharp.exe:

namespace simpleCsharp
{
    public class Program
    {       
         public static int Main(string[] args)
        {
                uint x = 0xFEFEFE;
                uint y = 0xEEEEEE;
                uint z;
                uint[] list = { 0, 1, 2, 4, 8 };
                uint[] array = { 0xA, 0xB, 0xC, 0xD };
                z = x + y + list[2] + array[1];
                z = z - (y << 1);
                return 0;           
        }
    }
}

Если я просматриваю дизассемблирование простой программы на C# в окне дизассемблирования Debug, то вывод собственного кода, по крайней мере, имеет некоторый смысл. Например, вот отладочная разборка Main, с оптимизацией по:

uint x = 0xFEFEFE;
00000000  push        ebp 
00000001  mov         ebp,esp 
00000003  sub         esp,28h 
00000006  xor         eax,eax 
00000008  mov         dword ptr [ebp-14h],eax 
0000000b  mov         dword ptr [ebp-18h],eax 
0000000e  mov         dword ptr [ebp-4],ecx 
00000011  cmp         dword ptr ds:[037D14ACh],0 
00000018  je          0000001F 
0000001a  call        763B370F 
0000001f  xor         edx,edx 
00000021  mov         dword ptr [ebp-0Ch],edx 
00000024  xor         edx,edx 
00000026  mov         dword ptr [ebp-1Ch],edx 
00000029  xor         edx,edx 
0000002b  mov         dword ptr [ebp-20h],edx 
0000002e  xor         edx,edx 
00000030  mov         dword ptr [ebp-8],edx 
00000033  xor         edx,edx 
00000035  mov         dword ptr [ebp-10h],edx 
00000038  mov         dword ptr [ebp-8],0FEFEFEh 
uint y = 0xEEEEEE;
0000003f  mov         dword ptr [ebp-0Ch],0EEEEEEh 
uint z;
uint[] list = { 0, 1, 2, 4, 8 };
00000046  mov         edx,5 
0000004b  mov         ecx,79882916h 
00000050  call        FD95FD70 
00000055  mov         dword ptr [ebp-24h],eax 
00000058  lea         ecx,[ebp-14h] 
0000005b  mov         edx,37D25E0h 
00000060  call        761A4716 
00000065  lea         eax,[ebp-14h] 
00000068  push        dword ptr [eax] 
0000006a  mov         ecx,dword ptr [ebp-24h] 
0000006d  call        761A47F3 
00000072  mov         eax,dword ptr [ebp-24h] 
00000075  mov         dword ptr [ebp-1Ch],eax 
uint[] array = { 0xA, 0xB, 0xC, 0xD };
00000078  mov         edx,4 
0000007d  mov         ecx,79882916h 
00000082  call        FD95FD70 
00000087  mov         dword ptr [ebp-28h],eax 
0000008a  lea         ecx,[ebp-18h] 
0000008d  mov         edx,37D25ECh 
00000092  call        761A4716 
00000097  lea         eax,[ebp-18h] 
0000009a  push        dword ptr [eax] 
0000009c  mov         ecx,dword ptr [ebp-28h] 
0000009f  call        761A47F3 
000000a4  mov         eax,dword ptr [ebp-28h] 
000000a7  mov         dword ptr [ebp-20h],eax 
z = x + y + list[2] + array[1];
000000aa  mov         eax,dword ptr [ebp-8] 
000000ad  add         eax,dword ptr [ebp-0Ch] 
000000b0  mov         edx,dword ptr [ebp-1Ch] 
000000b3  cmp         dword ptr [edx+4],2 
000000b7  ja          000000BE 
000000b9  call        763B6900 
000000be  add         eax,dword ptr [edx+10h] 
000000c1  mov         edx,dword ptr [ebp-20h] 
000000c4  cmp         dword ptr [edx+4],1 
000000c8  ja          000000CF 
000000ca  call        763B6900 
000000cf  add         eax,dword ptr [edx+0Ch] 
000000d2  mov         dword ptr [ebp-10h],eax 
z = z - (y << 1);
000000d5  mov         eax,dword ptr [ebp-0Ch] 
000000d8  add         eax,eax 
000000da  sub         dword ptr [ebp-10h],eax 
return 0;           
000000dd  xor         eax,eax 
000000df  mov         esp,ebp 
000000e1  pop         ebp 
000000e2  ret 

Однако, если я запускаю DUMPBIN на той же сборке C# (с Debug Info = "None", поэтому он не просто показывает байты), т. е.

dumpbin "simpleCsharp.exe" /disasm /out:"simpleCsharp_dump.txt"

Нативный код, выводимый в сгенерированном файле, даже не очень похоже на то, что я видел в Debug's Disassembly. Я не вижу ни одной инструкции или значения из разборки отладки в файле из dumpbin. Таким образом, 2 строки машинного кода (выше) нигде не найдены. Это происходит независимо от того, запускаю ли я dumpbin на сборке, созданной из Visual Studio (2010), или использую нген.exe чтобы создать собственный образ и запустить dumpbin в файле собственного образа simpleCsharp.ni.exe.

Оптимизация-это на в Debug, и сборка настроена на выпуск, единственное различие между сборкой, на которой я запускаю отладку, и сборкой, которую я даю ngen, - это Debug Info = "None".

dumpbin simpleCsharp.ni.exe /disasm

Вот дизассемблирование программы simpleCsharp при запуске dumpbin в файле native image:

Https://docs.google.com/leaf?id=0B9u9yFU99BOcYjNmNGRmNTItZjQ0NC00YmI0LWEyZTQtNjdkNDdhYTc2MmNm&hl=en

Я бы, по крайней мере, ожидал увидеть число FEFEFE или EEEEEE, отображаемое в выводе dumpbin где-то, и это действительно появляется в отладочной разборке.

Не мог бы кто-нибудь объяснить, почему я не вижу одну строку кода дизассемблирования Debug в выводе dumpbin из файла native image для той же программы? Если это из-за оптимизации, не могли бы вы рассказать немного подробнее?

Спасибо

1 2

1 ответ:

Вы забываете о компиляторе just-in-time. Сборка не содержит машинного кода, она генерируется во время выполнения дрожанием от IL в сборке. Вы можете посмотреть на IL в сборке с помощью таких инструментов, как ildasm.ехе или рефлектор. Программа dumpbin.exe имеет плохую поддержку, он может сбросить заголовок CLR, вот и все.

Обратите внимание, что изображение ngen-ed содержит машинный код, оптимизированный дрожанием. Этот оптимизатор очень сильно изменяет машинный код. Оптимизация-это выключено по умолчанию в отладчике. Чтобы увидеть его, необходимо отладить сборку выпуска и изменить параметр отладчика. Tools + Options, Debugging, General, снимите флажок "подавлять оптимизацию JIT при загрузке модуля". Также имейте в виду, что сгенерированный код может просто отличаться местами, потому что он был предварительно скомпилирован вместо jitted. Дрожание может сделать лучшую работу, потому что у него есть знания, которые не доступны заранее.