How to Check Stack Usage in Embedded C: Simple Methods
To check stack usage in embedded C, use a technique called
stack painting by filling the stack with a known pattern before running your program, then inspect how much of that pattern remains after execution. Alternatively, use linker symbols to find stack boundaries and calculate usage during runtime.Syntax
Stack usage checking involves two main parts: initializing the stack memory with a known pattern and then checking how much of that pattern remains unused.
Example steps:
void stack_paint(void *start, size_t size, uint8_t pattern);- fills stack memory with a pattern.size_t stack_check(void *start, size_t size, uint8_t pattern);- returns used stack size by scanning for overwritten pattern.
Also, linker symbols like _estack or _sstack define stack start/end addresses.
c
/* Fill stack with pattern */ void stack_paint(uint8_t *start, size_t size, uint8_t pattern) { for (size_t i = 0; i < size; i++) { start[i] = pattern; } } /* Check how much stack is used */ size_t stack_check(uint8_t *start, size_t size, uint8_t pattern) { size_t used = 0; for (size_t i = 0; i < size; i++) { if (start[i] != pattern) { used = size - i; break; } } return used; }
Example
This example shows how to paint the stack with 0xAA pattern before main runs and then check stack usage after some function calls.
c
#include <stdio.h> #include <stdint.h> #define STACK_SIZE 256 uint8_t stack_memory[STACK_SIZE]; void stack_paint(uint8_t *start, size_t size, uint8_t pattern) { for (size_t i = 0; i < size; i++) { start[i] = pattern; } } size_t stack_check(uint8_t *start, size_t size, uint8_t pattern) { size_t used = 0; for (size_t i = 0; i < size; i++) { if (start[i] != pattern) { used = size - i; break; } } return used; } void recursive_function(int depth) { uint8_t buffer[20]; // Use some stack for (int i = 0; i < 20; i++) { buffer[i] = depth; } if (depth > 0) { recursive_function(depth - 1); } } int main() { stack_paint(stack_memory, STACK_SIZE, 0xAA); recursive_function(5); size_t used = stack_check(stack_memory, STACK_SIZE, 0xAA); printf("Estimated stack used: %zu bytes\n", used); return 0; }
Output
Estimated stack used: 20 bytes
Common Pitfalls
- Not initializing the stack pattern: Forgetting to fill the stack with a known pattern leads to incorrect usage results.
- Stack grows in unexpected direction: Some systems have stack growing up or down; scanning must match direction.
- Interrupts and other stacks: Interrupt stacks or other contexts may use stack memory, confusing results.
- Optimizations: Compiler optimizations may remove unused variables, affecting stack usage measurement.
c
/* Wrong: Not painting stack before use */ // stack_check will always report zero usage or garbage /* Right: Always paint stack before running code */ stack_paint(stack_start, stack_size, 0xAA);
Quick Reference
Tips for checking stack usage in embedded C:
- Fill stack memory with a unique pattern before running your program.
- After execution, scan stack memory for overwritten bytes to estimate usage.
- Use linker symbols to find stack boundaries for accurate measurement.
- Consider stack growth direction when scanning memory.
- Test with worst-case call depth and interrupts to find maximum stack usage.
Key Takeaways
Always fill stack memory with a known pattern before running your embedded program.
Scan the stack memory after execution to find how much has been overwritten to estimate usage.
Use linker symbols to get accurate stack start and end addresses.
Remember stack growth direction varies by system and affects scanning logic.
Test with worst-case scenarios to ensure stack size is sufficient.