2

我绝对不是汇编专家,我对这个主题的了解也很浅,但我很好奇 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,esiebx寄存器是在之前推送和之后弹出以保存原始状态,以便函数可以自由使用它们。但对于其余的 - 我不知道。

非常感谢任何答案!:)

谢谢!

4

1 回答 1

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操作码表示x86 汇编指令,因此如果您尝试执行该INT 3代码(由于错误而意外),程序将抛出一个 INT 3 异常,该异常将由调试器或操作系统处理。所以它不仅仅是一些随机值。

于 2012-06-09T17:37:53.407 回答