The process stack is typically used for return addresses, procedure arguments, temporarily saved registers and locally allocated variables. The processor typically contains a register that points to the top of the stack. This register is called the stack pointer and is implicitly used by machine code instructions that call a procedure, return from a procedure, store a data item on the stack and fetch a data item from the stack.
The use of stack for procedure arguments and locally allocated variables relies on the fact that the arguments and the variables reside in a constant position relative to the top of the stack. The processor typically allows addressing data relative to the top of the stack, making it possible to use the same machine code instructions to access the procedure arguments and the locally allocated variables regardless on their absolute addresses in the virtual address space, as long as their addresses relative to the top of the stack do not change.
Allocating the block that contains stack requires estimating the stack size. Typically, the block is allocated with a reasonable default size and an extra page protected against reading and writing is added below the end of the allocated block. Should the stack overflow, an attempt to access the protected page will be made, causing an exception. The operating system can handle the exception by growing the block that contains stack and retrying the machine code instruction that caused the exception.
A multithreaded program requires as many stacks as there are threads. This makes placing the block that contains stack more difficult with respect to growing the block later, unless segmentation or split stack is used.
The Intel 80x86 processors have a stack pointer register called ESP
.
The CALL
machine code instruction decrements the ESP
register by the size of a return address and stores the address of the immediately following machine code instruction to the address pointed to by the ESP
register.
Symetrically, the RET
machine code instruction fetches the stored return address from the address pointed to by the ESP
register and increments the ESP
register by the size of a return address.
The PUSH
and POP
machine code instructions can be used to store and fetch an arbitrary register to and from the stack in a similar manner.
Note that the stack grows towards numerically smaller addresses. This simplifies the process memory management when only one stack block is present, as it can be placed at the very end of the virtual address space rather than in the middle of the virtual address space, where it can collide with other blocks that change during process execution.
To address the stack content, the Intel 80x86 processors have a base pointer register called EBP
.
The EBP
register is typically set to the value of the ESP
register at the beginning of a procedure, and used to address the procedure arguments and locally allocated variables throughout the procedure.
Thus, the arguments are located at positive offsets from the EBP
register, while the variables are located at negative offsets from the EBP
register.
void SomeProcedure (int anArgument) { int aVariable; aVariable = anArgument; } SomeProcedure: push ebp ;save original value of EBP on stack mov ebp,esp ;store top of stack address in EBP sub esp,4 ;allocate space for aVariable on stack mov eax,[ebp+8] ;fetch anArgument into EAX, which is ;8 bytes below the stored top of stack mov [ebp-4],eax ;store EAX into aVariable, which is ;4 bytes above the stored top of stack mov esp,ebp ;free space allocated for aVariable pop ebp ;restore original value of EBP ret ;return to the caller
In the example, the stack at the entry to SomeProcedure
contains the return address on top, that is 0 bytes above the value of ESP
, and the value of anArgument
one item below the top, that is 4 bytes above the value of ESP
.
Saving the original value of EBP
stores another 4 bytes to the top of the stack and therefore decrements the value of ESP
by another 4 bytes, this value is then stored in EBP
.
During the execution of SomeProcedure
, the value of anArgument
is therefore 8 bytes above the value of EBP
.
Note that the machine code instructions used to access the procedure arguments and the locally allocated variables do not use absolute addresses in the virtual address space of the process.