4
votes

I have a simple code:

void func()
{
    func2();
}

I omit the implementation of func2 and main since they are irrelevant. Then I used windbg to trace the assembly, following is the output of assembly code when executing "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)

We can see that before "push ebp" is executed, esp = 0012fe98, and ebp=0012ff68,but after executing "push ebp", esp=0012fdc8, ebp=0012fe94?, so I have two questions: 1. Presumably push code should only affect esp, why ebp is changed, too? 2. Presumably push ebp will push 4 bytes to stack, so the value of esp should decrease 4, but we see here that the value of esp descrease by 208 bytes? Why?

2
It doesn't. 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.harold
Something else is going on here. The difference between the EIP's (0041140e - 004113f0) = 1E bytes. Far too big to be a single instruction. Do you have multiple threads running?adelphus
@adelphus: you're correct. Just disassemble between 004113f0 .. 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 block ADD ESP, ...; POP ...; LEAVE; RET that undoes all this.FrankH.
@wangshuaijie: What changes EBP is not the PUSH EBP but the instruction that follows this - which will be a MOV EBP, ESP. That's why the new value in EBP is four bytes different from the initial value of ESP at entry to func(). As said, check your disassembly.FrankH.
@all, en, you guys make sense, maybe during executing push ebp, compiler has inserted some more assembly code into code sequence that windbg didn't show here, I will try more to see.wangshuaijie

2 Answers

3
votes

If you want to see what each individual instruction is doing, you need to disable source-level debugging. Open the debug menu and uncheck "Source Mode". When you step in source mode, all instructions mapped to the current source line are executed before the debugger breaks.

2
votes

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