In general we can describe the stack as a temporary storage for data.  The access to data in the stack is organized as Last In First Out (LIFO), which means that the last data stored in the stack is the first than can be retrieved and the first data stored in the stack is the last to be retrieved. The operation of adding data to the stack is called PUSH and the operation of retrieving data is called POP(PULL).

Fig. 1 Push Operation


Fig. 2 Pop Operation

The stack can be viewed as a pile of plates. The bottom plate is the first data pushed onto the stack and the top plate is the last data pushed. When the top plate is removed (pulled), the one below pops up to become the new top. The top plate is pulled first and the bottom plate is pulled last. It is important to note that only the top element in the stack can be accessed (in the classic stack implementation).

Stack Usage in Programming Languages

The vast majority of programming languages that implement functions use a stack.  Each function is given its own section of memory to operate in. This section is a part of the stack and is referred to as a stack frame. It most commonly includes the following components:

  • The return address (when the function is complete it returns back to the function call)
  • Arguments passed to the function
  • Local variables of the function
  • Saved copies of any registers modified by the function that have to be restored

When a program enters a function, space is allocated on top of the stack. When the program leaves the function, the space is freed. The life span of variables on the stack is limited to the duration of the function. Data that must survive across function calls is stored on the heap.

Hardware Implementation of Stack

The common hardware implementation of stack consists of reserved contiguous region of memory with a stack pointer into that memory. The stack has a fixed location in memory at which it begins. The stack pointer is a hardware register that points to the current extents of the stack. There are stacks that grow downwards and ones that grow upwards. The stack can technically be located anywhere in memory, depending on the system.

Fig. 3 Stack Grow Direction

Usage in Microprocessors

The stack is fundamental to an embedded system. Setting it properly is crucial to system stability and reliability. Underestimating stack usage can lead to serious issues such as overwritten variables, uninitialized pointers, and corrupted return addresses.

The stack shares the available RAM memory with the heap and the static memory area. It is therefore limited by the RAM size.  The C runtime library takes care of things that need to be defined before the main() function can be executed. One of those things is setting up the stack by loading the stack pointer register with the start address of the stack. The CPU has special instructions for pushing values onto the stack and popping them back.

Was this post helpful?