我绝不是汇编专家,而且我对这个主题的了解相当浅薄,但我很好奇Microsoft VC ++编译器在一个简单的函数调用中做了什么,除了返回一个值之外别无其他。
让我们有以下功能:
unsigned long __stdcall someFunction ( void * args) {
return 0;
}
现在,我知道使用__stdcall
调用约定时,CALLEE负责堆栈展开,并且使用__cdecl
函数的CALLER负责处理。但是对于这个例子,我想坚持前者。
使用非优化的调试版本,我看到正在生成以下输出:
unsigned long __stdcall someFunction (void * args) {
00A31730 push ebp
00A31731 mov ebp,esp
00A31733 sub esp,0C0h
00A31739 push ebx
00A3173A push esi
00A3173B push edi
00A3173C lea edi,[ebp-0C0h]
00A31742 mov ecx,30h
00A31747 mov eax,0CCCCCCCCh
00A3174C rep stos dword ptr es:[edi]
return 0;
00A3174E xor eax,eax
}
00A31750 pop edi
00A31751 pop esi
00A31752 pop ebx
00A31753 mov esp,ebp
00A31755 pop ebp
00A31756 ret 4
如果可能的话,我会感谢任何人为我解释这段代码。我知道xor
语句实际上会重置eax
寄存器以产生零返回值。 ret 4
对我来说也是不言自明的。我认为edi
,esi
和ebx
寄存器在之前被推送并弹出以保存原始状态,因此函数可以自由地使用它们。但其余的 - 我不知道。
非常感谢任何答案! :)
谢谢!
答案 0 :(得分:3)
所以你问这些行是做什么的:
00A3173C lea edi,[ebp-0C0h]
00A31742 mov ecx,30h
00A31747 mov eax,0CCCCCCCCh
00A3174C rep stos dword ptr es:[edi]
在Visual C ++调试运行时库中,未初始化的堆栈内存初始化为包含0xCC
个字节。这就是这些说明的作用。
在ASM代码的开头,有一条指令sub esp,0C0h
为堆栈分配0xC0
个字节。但是,此函数中没有使用局部变量,因此它来自何处?这是编辑+继续支持:您可以添加局部变量并继续调试。
0xCC
操作码意味着INT 3
x86汇编指令,因此如果您尝试执行该代码(意外地由于错误),程序将抛出一个INT 3异常,该异常将由调试器或操作系统。所以它不仅仅是一些随机值。