Дизассемблирование 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 с Debug с оптимизацией на:

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. Я не вижу ни единой инструкции или значения из разборки отладки в файле из мусорной корзины. Таким образом, 2 строки нативного кода (выше) нигде не найдены. Это тот случай, когда я запускаю dumpbin в сборке, сгенерированной из Visual Studio (2010), или использую ngen.exe для создания собственного образа, и запускаю dumpbin в собственном файле образа simpleCsharp.ni.exe.

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

dumpbin simpleCsharp.ni.exe /disasm

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

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

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

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

Спасибо

1 ответ

Решение

Вы забываете о своевременном компиляторе. Сборка не содержит машинный код, она генерируется во время выполнения джиттером из IL в сборке. Вы можете посмотреть на IL в сборке с помощью таких инструментов, как ildasm.exe или Reflector. Dumpbin.exe имеет плохую поддержку, он может сбросить заголовок CLR, вот и все.

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

Другие вопросы по тегам