liveBook · Manning

Stack pointer

As explained in Rust in Action: Systems programming concepts and techniques

A stack pointer is a CPU-maintained pointer to the current location or top of a call stack.

A stack pointer tracks where a program is in its call stack. Each function call creates a stack frame holding state for that call. If the function calls another function, its frame remains available while the new call runs. When the newer call returns, the earlier one can resume. This last-in, first-out pattern is why the structure is called a stack. section 6.3.1

In a running program, the stack pointer is a CPU cursor for the current stack frame. Frames can differ in size and provide room for arguments, a return location, and local variables not allocated on the heap. As calls add frames, this stack pointer decreases in value; as functions return, it increases. section 6.3.1

A stack pointer in a small CPU emulator

A simpler emulator represents the stack as 16 address slots and keeps its stack_pointer as an array index. Its CALL operation saves the address at which execution should resume, increments the index, then jumps to the function. RETURN decrements the index, retrieves that saved address, and resumes execution there. Unlike the stack-frame cursor above, this index increases on a call: the two representations use different directions. Returning when the index is zero is a stack underflow. section 5.7.4

Listing 5.28 Adding the call() and ret() methods
41 fn call(&mut self, addr: u16) {
42     let sp = self.stack_pointer;
43     let stack = &mut self.stack;
44  
45     if sp > stack.len() {
46         panic!("Stack overflow!")
47     }
48  
49     stack[sp] = self.position_in_memory as u16;       #1
50     self.stack_pointer += 1;                          #2
51     self.position_in_memory = addr as usize;          #3
52 }
53  
54 fn ret(&mut self) {
55     if self.stack_pointer == 0 {
56         panic!("Stack underflow");
57     }
58  
59     self.stack_pointer -= 1;
60     let call_addr = self.stack[self.stack_pointer];   #4
61     self.position_in_memory = call_addr as usize;     #4
62 }

Follow the assignments in call() and ret(): saving a return address and moving stack_pointer make it possible to return to the caller. section 5.7.4

How Rust in Action: Systems programming concepts and techniques covers it

How deep it goes
Explains stack-frame behavior and works through an indexed stack pointer in CALL and RETURN methods.
Examples
Uses Rust CPU fields and call() and ret() methods with a 16-slot address stack.
What it assumes
Uses Rust arrays and methods while introducing stack frames and the stack pointer.
What you can do after
Build it from scratch in a small CPU emulator to save return addresses and resume callers.
How it connects
Connects the stack pointer to stack frames, last-in-first-out order, function calls, return addresses, and stack underflow.

Also explained in

Compare how 4 books explain stack pointer →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Rust in Action: Systems programming concepts and techniques. The section links point to the parts of the book it draws on.