After the movl %esp,%ebp instruction of tne entry (prologue) code of a subroutine, the frame point is all set. With proper symbolic definitions of the distance from where %ebp points to each parameter, we can easily access parameters.
But what about local variables? These objects cannot be allocated by the caller because the caller does not know how much storage to allocate for local variables of a subroutine. As a result, it is the responsibility of a subroutine to allocate space for its own local variables.
But where to allocate space from?
Why, the stack, of course!
This is actually also very easy. Let’s say we have dealing with a function as follows:
The unspoken convention is that x has the lowest address, and z has the highest address. However, this ordering is not mandatory.
We should allocate space for local variables after setting the frame pointer. This way, we can change the number of local variables without affecting the offsets to parameters. In this case, we need 12 bytes for the three local variables, so the prolog of the function can look like the following:
The code did not use push because no initialized values are specified.
Using this method, we can also define symbolic names corresponding to the offsets of local variables from where the frame pointer points:
With these symbolic definitions, we can change our allocation instruction to the following instead:
Note that we change the subl instruction to addl because lastLocalVar is already a negative value. This method (of using lastLocalVar) is preferred so that it is easier to keep the allocation of stack space consistent with the definition of local variables.
Interestingly, even though local variables use up additional stack space, we don’t have to change the exit code (epilog) of a subroutine. This is because we copy %ebp to %esp, which “warps” the stack pointer all the way back to point to the old frame pointer.