我有一个简单的代码:
void func()
{
func2();
}
我省略了func2和main的实现,因为它们是无关的。然后我用windbg跟踪程序集,下面是执行"func2()"时程序集代码的输出:
eax=cccccccc ebx=7ffd6000 ecx=00000000 edx=00000001 esi=01faf760 edi=0012ff68
eip=004113f0 esp=0012fe98 ebp=0012ff68 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
SimpleStack!func:
004113f0 55 push ebp
0:000> t
eax=cccccccc ebx=7ffd6000 ecx=00000000 edx=00000001 esi=01faf760 edi=0012fe94
eip=0041140e esp=0012fdc8 ebp=0012fe94 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
SimpleStack!func+0x1e:
0041140e e83dfcffff call SimpleStack!ILT+75(_func2) (00411050)
我们可以看到,在执行"push ebp"之前,esp=0.012fe98,ebp=0012ff68,但在执行"push ebp"之后,esp=0.0012fdc8,ebp=0.0012fe94?,所以我有两个问题:1.推送代码可能只会影响esp,为什么ebp也会改变?2.假设推送ebp会推送4个字节到堆栈,所以esp的值应该减少4,但我们在这里看到esp的数值减少了208个字节?为什么?
如果您想查看每个单独的指令在做什么,您需要禁用源代码级别的调试。打开调试菜单并取消选中"源模式"。当您进入源代码模式时,映射到当前源代码行的所有指令都会在调试器中断之前执行。
按照Steve Johnson的指示,我取消选中"源模式"来跟踪程序集,事实上,在推送ebp之后,会有很多(真的很多。所以这个案例解决了,但我发现了其他问题,首先请看我更完整的代码:
void func();
int main(int argc, char* argv[])
{
func();
return 0;
}
void func2();
void func()
{
func2();
}
在func中,我没有声明局部变量,下面是我在main中执行func()时的windbg输出:
004113c3 50 push eax
0:000>
eax=0000000a ebx=7ffda000 ecx=00000000 edx=00000001 esi=01f1f760 edi=0012ff68
eip=004113c4 esp=0012fe98 ebp=0012ff68 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
SimpleStack!main+0x24:
004113c4 e8e0fdffff call SimpleStack!ILT+420(_func) (004111a9)
0:000> t
eax=0000000a ebx=7ffda000 ecx=00000000 edx=00000001 esi=01f1f760 edi=0012ff68
eip=004111a9 esp=0012fe94 ebp=0012ff68 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
SimpleStack!ILT+420(_func):
004111a9 e942020000 jmp SimpleStack!func (004113f0)
0:000> t
eax=0000000a ebx=7ffda000 ecx=00000000 edx=00000001 esi=01f1f760 edi=0012ff68
eip=004113f0 esp=0012fe94 ebp=0012ff68 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
SimpleStack!func:
004113f0 55 push ebp
0:000> t
eax=0000000a ebx=7ffda000 ecx=00000000 edx=00000001 esi=01f1f760 edi=0012ff68
eip=004113f1 esp=0012fe90 ebp=0012ff68 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
SimpleStack!func+0x1:
004113f1 8bec mov ebp,esp
0:000> t
eax=0000000a ebx=7ffda000 ecx=00000000 edx=00000001 esi=01f1f760 edi=0012ff68
eip=004113f3 esp=0012fe90 ebp=0012fe90 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
SimpleStack!func+0x3:
004113f3 81ecc0000000 sub esp,0C0h
0:000> t
eax=0000000a ebx=7ffda000 ecx=00000000 edx=00000001 esi=01f1f760 edi=0012ff68
eip=004113f9 esp=0012fdd0 ebp=0012fe90 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
SimpleStack!func+0x9:
004113f9 53 push ebx
0:000> t
eax=0000000a ebx=7ffda000 ecx=00000000 edx=00000001 esi=01f1f760 edi=0012ff68
eip=004113fa esp=0012fdcc ebp=0012fe90 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
SimpleStack!func+0xa:
004113fa 56 push esi
事实上,我们看到推送ebp后,实际上是mov ebp,esp改变了ebp,但在"mov ebp,esp"后面有一个代码"sub esp,0C0h",我知道"sub esp,num"是为堆栈帧上的局部变量分配内存空间,但我没有在func中声明局部变量,所以我有这个问题:"sub esp,0C0h"在这里做什么?从函数prolog开始,uf输出为:
0:000> uf func
SimpleStack!func [d:codesimplestackfunc.c @ 4]:
4 004113f0 55 push ebp
4 004113f1 8bec mov ebp,esp
4 004113f3 81ecc0000000 sub esp,0C0h
4 004113f9 53 push ebx
4 004113fa 56 push esi
4 004113fb 57 push edi
4 004113fc 8dbd40ffffff lea edi,[ebp-0C0h]
4 00411402 b930000000 mov ecx,30h
4 00411407 b8cccccccc mov eax,0CCCCCCCCh
4 0041140c f3ab rep stos dword ptr es:[edi]
5 0041140e e83dfcffff call SimpleStack!ILT+75(_func2) (00411050)
6 00411413 5f pop edi
6 00411414 5e pop esi
6 00411415 5b pop ebx
6 00411416 81c4c0000000 add esp,0C0h
6 0041141c 3bec cmp ebp,esp
6 0041141e e818fdffff call SimpleStack!ILT+310(__RTC_CheckEsp) (0041113b)
6 00411423 8be5 mov esp,ebp
6 00411425 5d pop ebp
6 00411426 c3