在调试模式下用MSVC2008编译这个简单的函数:
int __cdecl sum(int a, int b)
{
return a + b;
}
我得到以下反汇编列表:
int __cdecl sum(int a, int b)
{
004113B0 push ebp
004113B1 mov ebp,esp
004113B3 sub esp,0C0h
004113B9 push ebx
004113BA push esi
004113BB push edi
004113BC lea edi,[ebp-0C0h]
004113C2 mov ecx,30h
004113C7 mov eax,0CCCCCCCCh
004113CC rep stos dword ptr es:[edi]
return a + b;
004113CE mov eax,dword ptr [a]
004113D1 add eax,dword ptr [b]
}
004113D4 pop edi
004113D5 pop esi
004113D6 pop ebx
004113D7 mov esp,ebp
004113D9 pop ebp
004113DA ret
我不明白这些序言的某些部分:
004113BC lea edi,[ebp-0C0h]
004113C2 mov ecx,30h
004113C7 mov eax,0CCCCCCCCh
004113CC rep stos dword ptr es:[edi]
为什么需要这个?
修改
删除/RTC
编译器选项后,正如所建议的那样,大部分代码确实消失了。剩下的是:
int __cdecl sum(int a, int b)
{
00411270 push ebp
00411271 mov ebp,esp
00411273 sub esp,40h
00411276 push ebx
00411277 push esi
00411278 push edi
return a + b;
00411279 mov eax,dword ptr [a]
0041127C add eax,dword ptr [b]
}
现在,为什么需要:sub esp, 40h
?这就像是为局部变量分配了地方,尽管没有。为什么编译器会这样做?还有另一面旗帜吗?
答案 0 :(得分:11)
此代码由于/RTC compile option而发出。它会将函数中的所有局部变量初始化为极有可能产生访问冲突或导致异常输出值的位模式。这有助于您了解何时忘记初始化变量。
您看到分配的堆栈框架中的额外空间用于支持编辑+继续功能。在调试时编辑函数并添加更多局部变量时,将使用此空间。将/ ZI选项更改为/ Zi以禁用它。
答案 1 :(得分:3)
并且在任何缓冲区溢出的情况下(如果你要覆盖局部变量),你将最终进入“int 3”操作码的字段:
int 3 ; 0xCC
int 3 ; 0xCC
int 3 ; 0xCC
int 3 ; 0xCC
int 3 ; 0xCC
int 3 ; 0xCC
...
可以被调试器捕获,因此您可以修复代码