The link register and stack are two important concepts in ARM assembly programming that play different but complementary roles. Understanding the differences between the two is key to effectively utilizing registers and memory in ARM programs.
Link Register
The link register, also known as LR or R14, is one of the general purpose registers in the ARM processor. It has a special purpose – storing the return address when a subroutine call is made.
Here is how the link register works:
- When a BL (branch with link) instruction is executed to call a subroutine, the address of the next instruction after BL is stored in the link register (LR).
- During the subroutine execution, LR holds the return address back to the calling routine.
- When the subroutine finishes execution, it uses the LDR instruction to load the PC (program counter) with the return address stored in LR.
- This returns control back to the calling routine.
In essence, the link register acts as a holder for return addresses within subroutine calls. It connects different parts of a program through holding the address to return to after a function call completes.
Some key points about the link register:
- The LR is updated automatically by branch instructions, no explicit store is needed.
- The LR contents are volatile and change with each subroutine call.
- Saving LR to the stack allows nested subroutine calls.
- LR is banked for exception handling to differentiate normal/exception returns.
- Some ARM processor modes have more than one LR (for threads, exceptions etc).
Stack
The stack is a region of memory used for temporary data storage. It relies on a LIFO (last in first out) structure to store and retrieve data in a sequential order.
In ARM programs, the stack is used to:
- Store return addresses for subroutine calls
- Save register values across function calls
- Allocate space for local variables
- Pass arguments to functions
- Handle interrupts and exceptions
The stack grows downwards from high to low memory. The SP (stack pointer) register points to the current top of the stack. Pushing to the stack decrements SP, popping increments SP.
Some key properties of the software stack on ARM:
- Data is accessed in a last-in, first-out (LIFO) order.
- Stack access is typically very fast compared to other data structures.
- Variable sized data can be stored and accessed.
- Stack overflow can occur if SP exceeds stack bounds.
- Stack is allocated from the read-write memory.
Differences between Link Register and Stack
While both the link register and stack are involved in handling subroutine calls, there are some key differences:
- Size: The link register is a single 32-bit hardware register. The stack is a contiguous block of memory that can contain multiple 32-bit values.
- Purpose: The link register solely holds the return address. The stack holds return addresses, arguments, local variables etc.
- Lifetime: LR values last for a single subroutine call. Stack data persists until explicitly popped.
- Manipulation: LR is updated by branch instructions. Stack must be manually managed with PUSH, POP etc.
- Visibility: LR is directly accessible to code. Stack data requires SP to track & access.
- Nesting: LR alone can’t handle nested calls. Stack allows multiple nested call levels.
In summary:
- The link register is a dedicated return address register updated by BL implicitly.
- The stack is a more general purpose LIFO memory structure managed explicitly.
- LR handles single level subroutine returns.
- The stack enables nested subroutine calls through storing multiple return addresses.
Interplay Between Link Register and Stack
The link register and stack work together closely to handle function calls:
- Main program calls SubA and LR gets return address to Main.
- SubA prologue code pushes LR to stack before using LR register.
- SubA calls SubB. LR now gets return address to SubA.
- SubB prologue pushes its LR to stack.
- SubB returns to SubA using popped LR value.
- SubA returns to Main using its restored LR from stack.
This demonstrates how the stack supplements the link register by storing multiple return addresses. This enables nested subroutine calls.
Another area where stack assists link register is context switching:
- On interrupt, the LR and other registers are automatically pushed to stack.
- The interrupt handler uses the stack to preserve the interrupted code’s context.
- On return from interrupt, registers are popped back from stack.
This way stack works alongside LR to store return state across interrupts.
When to Use Each
Based on their distinct roles, we can deduce when to use link register vs stack:
- Use LR any time you need to make a subroutine call.
- Use stack any time you need to preserve values across calls.
- Use LR for simple non-nested subroutine calls.
- Use stack when making nested subroutine calls.
- Use stack to store any temporary data besides just return address.
- Use stack during interrupts to preserve context.
Cases where both are used:
- Subroutine call – LR for return address, stack for arguments.
- Context switching – LR and registers saved to stack.
- Nested calls – Old LR saved to stack, new LR gets return address.
Examples
Here are some examples to illustrate link register and stack usage:
Simple Subroutine Call
Main: … BL SubA ; Call SubA, return address in LR … SubA: … ; Code for SubA LDR PC, [LR] ; Return to caller
- BL sets LR to return address to Main
- LDR PC, [LR] returns to Main using LR
Nested Subroutine Call
Main: … BL SubA … SubA: PUSH {LR} ; Save return address … BL SubB ; Nested call … POP {LR} ; Restore return address BX LR ; Return to Main SubB: … BX LR ; Simple return
- SubA stack saves LR return address to Main
- This allows BL to SubB without losing SubA’s return
- Stack enables multiple call levels through stacked LRs
Context Switching
Main: … BL FuncA ; Call FuncA … FuncA: … ; Interrupt occurs ; LR and regs automatically pushed to stack ; Int handler runs … ; Return from interrupt ; Registers popped from stack LDR PC, [LR] ; Resume Main
- Stack used to save LR and registers on interrupt
- This preserves FuncA’s state during handler
- After interrupt, stack restores context to resume Main
Summary
In summary:
- The link register is a dedicated subroutine return address register.
- The stack is a general purpose LIFO memory structure.
- LR handles simple single-level calls.
- Stack enables nested multi-level calls through stacked return addresses.
- LR and stack work together closely for subroutine calls and context switching.
- Understanding their differences and interplay is key to efficient ARM programming.