2010-07-29 35 views
14

我刚刚注意到一些奇怪的空主函数的汇编语言代码。用Visual C++编译器解释空C`main`函数的奇怪程序集

//filename: main.c 
void main() 
{ 

} 

拆解:

push  ebp 
mov   ebp,esp 
sub   esp,0C0h; why on the earth is it reserving 192 bytes? 
push  ebx 
push  esi 
push  edi ; good compiler. Its saving ebx, esi & edi values. 
lea   edi,[ebp-0C0h] ; line 1 
mov   ecx,30h ; line 2 
mov   eax,0CCCCCCCCh ; line 3 
rep stos dword ptr es:[edi] ; line 4 


xor   eax,eax ; returning value 0. Code following this line is explanatory. 
pop   edi ; restoring the original states of edi,esi & ebx 
pop   esi 
pop   ebx 
mov   esp,ebp 
pop   ebp 
ret 
  1. 为什么地球上它保留了功能192个字节,其中没有任何变量
  2. 怎么了四大行:1号线, 2,第3行,第4行?它试图做什么&为什么?
+0

为什么不突出显示代码语法? – claws 2010-07-29 13:25:05

+0

装配非空主语句时产生了什么程序集,以及将main的返回类型更改为int时会发生什么? – 2010-07-29 13:29:17

+5

值得指出的是主要回报int。使用void作为main不是很好。 – nmichaels 2010-07-29 13:30:21

回答

15

您指出的四条代码行是调试版本,用“清除”特殊值(0xCCCCCCCC)清除局部变量空间。

我不知道为什么有192个字节的看起来死的空间,但可能是VC++建立一些警卫空间到您的本地变量区域,以尝试检测堆栈粉碎。

如果从Debug切换到Release版本,您可能会得到非常不同的输出。

+1

为什么'0xCCCCCCCC' ='1100 1100 1100 1100 1100 1100 1100 1100'?不会用0x00000000清除会更有意义? – claws 2010-07-29 13:39:09

+0

@claws:微软选择了这个值,因为它很明显,很容易识别你的程序是否最终使用了一个未初始化的变量。使用零会掩盖很多潜在的错误,因为经常将变量初始化为零,并且让编译器在调试版本中这样做会导致发布版本失败。 – 2010-07-29 13:42:18

+0

@Greg Hewgill:如何在Visual Studio中查看Release配置中的反汇编?我在关闭支架上放置了一个断点并查看反汇编。这似乎不能在发布模式下工作。 – claws 2010-07-29 14:06:12

18

Greg已经解释了编译器如何生成代码来诊断由/ RTCu编译选项启用的未初始化的局部变量。 0xcccccccc值被选择为独特的,并且在调试器中容易识别。并确保在未初始化的指针被解除引用时程序炸弹。并确保程序在作为代码执行时终止程序。 0xcc非常适合完成所有这些工作,它是INT3的指令操作码。

在堆栈框架中分配的神秘的192个字节是支持编辑+继续功能,/ ZI编译选项。它允许您在断点处于活动状态时编辑代码。并且将一些局部变量添加到一个函数中,这192个字节可用于为那些添加的本地人提供空间。超过这个空间将会让IDE强迫你重建你的程序。

btw:如果您在代码中使用递归,会导致问题。调试版本将以更快的速度与这个网站的名字相撞。通常不是很多问题,您可以使用实际的数据集大小进行调试。

+2

向上,提供的信息是晦涩但令人着迷。 – mickeyf 2010-07-29 14:50:06

+0

你说的是正确的http://stackoverflow.com/questions/370195/when-and-why-will-an-os-initialise-memory-to-0xcd-0xdd-etc-on-malloc-free-new – 2014-06-19 08:36:43