Age of Reason

Random musing of books and stuff I am reading.


Advanced Debugging -- Prologue and Epilog

Compile the code with 'cl /ZI main.cpp'
or by pressing F5.
Press F10 to begin debugging.
Press F9 to on fx() to set breakpoint.
Press F5 to run till the breakpoint.
Press A-8 to switch to Assembly mode.

You are now in the prologue of the function:

int fx(int a, int b,int c){
-> push ebp // save the base pointer
mov ebp,esp // point ebp to stack frame.
sub esp,44h // make space for new frame.
push ebx // save original registers on stack.
push esi
push edi

The frames form a linked list on the stack, with ebp pointing to
the previous frame above it. Local variables are created on the
stack, usually with a stack guard and a signature fence to detect
stack overruns (have you ever called sprintf on a locally declared string
or declared a local array inside a function?).
VC++ is very good at finding stack thrashing in debug mode.

Press F10 to single step through the frame setup (prologue)
till the end of the function (epilog), where the registers are

pop edi
pop esi
pop ebx
add esp,44h // destroy the frame.
pop ebp // restore the frame pointer.

In C (cdecl) functions, the caller cleans up the stack. That is, the caller
will pop out the parameters after the call.
This allows varargs (printf( fmt, i,...)), the callee
doesn't have to know how many parameters are
on the stack.

The default return type of a C function is int,
because the return value comes for free in register eax.
In VC, you can watch '@eax' to see the implicit
return values.

Earlier languages like Pascal and lisp from 1970s
with heavy emphasis on tail recursion optimization
let the callee clean the stack, so the stack would not
grow (but was reused) in recursive calls.

To be continued.


Post a Comment

<< Home