PS: Do a draft first, then have time to organize and map,:)
This is achieved mainly by using the bottom register (EBP), the top register (ESP), and the EAX register (which stores the return value).
Suppose P calls Q:
P ()
{
Q (up to);
}
1. Pre-call preparation, put the parameters of Q into the stack (non-push)
MOV $ $, (%ESP)
MOV $4 (%ESP)
2. Call 0x12345678 (address of Q)
First, the return address of the function (the address of the instruction after the call statement) is put into the stack,
Then jump to 0x12345678 to execute the code for Q.
3. Revert the old ebp into the stack (for exit Q)
Push%EBP
4. Set a new stack base
mov%esp,%EBP
5. Allocate stack space for Q (stack is down)
Sub $24,%esp (+ * k + 8, for alignment)
6. Execute the relevant code for Q. Local variables/parameters are accessed based on ESP, EBP, and offset.
7. Assign the return value to%eax before the function leaves.
8. Call leave, equivalent to:
mov%ebp,%esp (Restore stack top)
Pop%ebp (Restore stack bottom)
9. Process the return value and then the code followed by P continues execution.
Function call procedure in C language (how to manage stack space)