As instructed by Steve Johnson, I uncheck "Source Mode" to trace the assembly, indeed after push ebp, there follows lots of (really lots of !) assembly code that were previous hidden when "Source Mode" was checked. So this case is solved, but I found other problems, first please see my more complete code:
void func();
int main(int argc, char* argv[])
{
func();
return 0;
}
void func2();
void func()
{
func2();
}
In func, I declare no local variables, following is the windbg output when I execute func() in main:
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
Indeed we see that after push ebp, it is mov ebp, esp, that actually changes ebp, but there is a code "sub esp,0C0h" following "mov ebp, esp", I know that "sub esp, num" is to allocate memory space for local variables on the stack frame, but I didn't declare local variables in func, so I have this questions:
What does "sub esp, 0C0h" do here?
Staring with function prolog, the uf output is:
0:000> uf func
SimpleStack!func [d:\code\simplestack\func.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
push ebp
does exactly what it says on the tin. Note that eip increased by 1E, if only the push had been executed it would have increased by just 1. Clearly more than just the push has been executed. – harold004113f0 .. 0041140e
and you'll find a sequence (using Intel Syntax here):PUSH EBP; MOV EBP, ESP; PUSH <other reg>; ...; SUB ESP, ...
; this is function entry code generated by the compiler (called a function prologue) which makes the code implement the usual C calling conventions / ABI. At the end of / return from the function, you find a corresponding blockADD ESP, ...; POP ...; LEAVE; RET
that undoes all this. – FrankH.EBP
is not thePUSH EBP
but the instruction that follows this - which will be aMOV EBP, ESP
. That's why the new value inEBP
is four bytes different from the initial value ofESP
at entry tofunc()
. As said, check your disassembly. – FrankH.