Course contentsShow
← Embedded Systems & Computer Architecture
Lesson 233 of 9363. Microcontroller Fundamentals and Bare-Metal CFree lesson

Managing Stack and Heap Memory Boundaries

Learners will define the size and placement of the stack and heap within the linker script to prevent memory overflow errors.

In this lesson, you will learn how to define the size and placement of the stack and heap in your linker script to ensure your application has enough memory without crashing.

In a bare-metal environment, the linker script is your blueprint for memory. While global variables are explicitly placed in sections like .data or .bss, the stack (for local variables and function calls) and the heap (for malloc) are often dynamic regions that exist within your RAM. If these regions aren't carefully managed, they can grow into each other—or into your global data—causing silent memory corruption.

Defining Boundaries in the Linker Script

We define these boundaries using symbols in the linker script. Usually, the stack grows downwards from the top of the RAM, while the heap grows upwards from the end of the uninitialized data section.

/* Define RAM boundaries */
_ram_start = 0x20000000;
_ram_end   = 0x2001FFFF;

/* Define sizes */
_stack_size = 0x2000; /* 8KB */
_heap_size  = 0x1000; /* 4KB */

SECTIONS {
    .heap : {
        _sheap = .;
        . = . + _heap_size;
        _eheap = .;
    } > RAM

    .stack : {
        . = ALIGN(8);
        _stack_bottom = .;
        . = . + _stack_size;
        _stack_top = .;
    } > RAM
}

Preventing Overflow

The code above reserves specific chunks of RAM. The danger occurs when the application uses more memory than allocated. If the stack pointer exceeds _stack_bottom, it overwrites the heap or data sections.

To catch these issues during development, you can use a "stack guard." By placing the stack at the very end of RAM, any overflow will cause a hardware fault (Memory Management Fault) rather than silently corrupting your data, because the CPU will attempt to access an address outside the defined physical memory region. When setting these boundaries, always leave a safety margin; if your application performs deep recursion or heavy dynamic allocation, you must increase these values or risk a system hang.

Key Takeaway: By explicitly defining stack and heap sizes in the linker script, you create predictable memory boundaries that allow the CPU to trigger hardware faults if memory limits are exceeded, preventing silent data corruption.