问题
I am learning GNU assembly from Jonathan Bartlett's "Programming from ground up" book.
While going through the topic of a function call and stack, I'm unable to understand its working.
Below is what's written in the book:
Before executing a function, a program pushes all of the parameters for the function onto the stack in the reverse order that they are documented. Then the program issues a call instruction indicating which function it wishes to start. The call instruction does two things. First it pushes the address of the next instruction, which is the return address, onto the stack. Then it modifies the instruction pointer (%eip) to point to the start of the function. So, at the time the function starts, the stack looks like this (the "top" of the stack is at the bottom on this example):
Parameter #N ... Parameter 2 Parameter 1 Return Address <--- (%esp)
Each of the parameters of the function have been pushed onto the stack, and finally the return address is there. Now the function itself has some work to do.
The first thing it does is save the current base pointer register, %ebp, by doing pushl %ebp. The base pointer is a special register used for accessing function parameters and local variables. Next,it copies the stack pointer to %ebp by doing movl %esp, %ebp. This allows you to be able to access the function parameters as fixed indexes from the base pointer. You may think that you can use the stack pointer for this. However, during your program you may do other things with the stack such as pushing arguments to other functions. Copying the stack pointer into the base pointer at the beginning of a function allows you to always know where your parameters are (and as we will see, local variables too), even while you may be pushing things on and off the stack. %ebp will always be where the stack pointer was at the beginning of the function, so it is more or less a constant reference to the stack frame (the stack frame consists of all of the stack variables used within a function, including parameters, local variables, and the return address).
At this point, the stack looks like this:
Parameter #N <--- N*4+4(%ebp) ... Parameter 2 <--- 12(%ebp) Parameter 1 <--- 8(%ebp) Return Address <--- 4(%ebp) Old %ebp <--- (%esp) and (%ebp)
As you can see, each parameter can be accessed using base pointer addressing mode using the %ebp register.
Can I get a concise intro on what the author wants to tell after the second paragraph. I am clearly confusing among the %esp, %ebp registers and %ebp's working here. Any help is highly appreciated.
回答1:
In the second diagram, there is this "Old %ebp <--- (%esp) and (%ebp)". What does it mean ?
It means the saved %ebp
value (the caller's value that your function saves/restores) is pointed to by both %esp
and your new %ebp
at that point.
You just ran push %ebp
, which did esp -= 4
and stored %ebp
to (%esp)
. This saves your caller's %ebp
so you can restore it later.
Then you ran mov %esp, %ebp
to set up %ebp
as a frame pointer. So %ebp = %esp
, and they're both pointing at the last thing you pushed.
来源:https://stackoverflow.com/questions/47448283/how-do-function-calls-work-in-x86-32-bit-assembly-on-linux