【问题标题】:disassembly of C#: why is DUMPBIN native code so different from Debug's Disassembly?C# 的反汇编:为什么 DUMPBIN 本机代码与 Debug 的反汇编如此不同?
【发布时间】:2011-04-04 13:29:40
【问题描述】:

假设这是我的程序 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;           
        }
    }
}

如果我在 Debug 的 Disassembly 窗口中查看一个简单 C# 程序的反汇编,native code 的输出至少是有意义的。例如,这里是 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 

但是,如果我在同一个 C# 程序集上运行 DUMPBIN(使用 Debug Info = "None" 所以它不只显示字节),即

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

生成文件中的本机代码输出甚至与我在 Debug 的反汇编中看到的不太相似。在 dumpbin 的文件中,我什至看不到调试反汇编中的一条指令或值。所以找不到 2 行本机代码(上图)。无论是在 Visual Studio (2010) 生成的程序集上运行 dumpbin 还是使用 ngen.exe 生成本机映像,然后在本机映像文件 simpleCsharp.ni.exe 上运行 dumpbin 都是这种情况.

优化在 Debug 中开启,并且 build 设置为 Release,我运行 Debug 的程序集和我提供给 ngen 的程序集之间的唯一区别是 Debug Info = "None"。

dumpbin simpleCsharp.ni.exe /disasm

这是我在原生镜像文件上运行dumpbin时simpleCsharp程序的反汇编:

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

我至少希望看到数字 FEFEFE 或 EEEEEE 出现在某处的 dumpbin 的输出中,它确实出现在 Debug Disassembly 中。

有人能解释一下为什么我在同一程序的本机图像文件的转储bin 输出中看不到一个 行的Debug 反汇编代码吗?如果是因为优化,介意给点细节吗?

谢谢

【问题讨论】:

    标签: .net disassembly native-code


    【解决方案1】:

    您忘记了即时编译器。程序集不包含机器代码,它是在运行时由程序集中 IL 的抖动生成的。您可以使用 ildasm.exe 或 Reflector 等工具查看程序集中的 IL。 Dumpbin.exe支持差,可以转储CLR头,就这样吧。

    请注意,经过 ngen 处理的图像包含已通过抖动优化的机器代码。该优化器会大量更改机器代码。优化在调试器中默认关闭。要查看它,您必须调试发布版本并更改调试器选项。工具 + 选项,调试,常规,取消勾选“在模块加载时抑制 JIT 优化”选项。另请注意,生成的代码可能在某些地方完全不同,因为它是预编译的而不是 jitted。抖动可以做得更好,因为它具有预先无法获得的知识。

    【讨论】:

    • 但是我提到使用 ngen.exe,MSDN 说:“本机图像,这是包含编译的处理器特定机器代码的文件,并将它们安装到本地计算机上的本机图像缓存中。运行时可以使用缓存中的本机图像,而不是使用即时 (JIT) 编译器来编译原始程序集。”
    • Hans/NoBugz,我刚刚更新了问题。我在调试中打开了优化,但这段代码不仅仅是“在某些地方完全不同”,它一点也不相似。如果您不介意再看一次,请...
    • 这就是你反汇编数据而不是代码时得到的结果。注意大量的 00。以及以 6x 或 7x 开头的字节,它们是字符串。不确定您在看什么,显然它不是机器代码。在我看来,就像 IL 和元数据。
    猜你喜欢
    • 2015-02-27
    • 1970-01-01
    • 1970-01-01
    • 2015-12-21
    • 2014-06-21
    • 2021-12-16
    • 1970-01-01
    • 2013-07-21
    • 1970-01-01
    相关资源
    最近更新 更多