Startup, Linker Scripts, and Memory
Before main() runs, the microcontroller follows a strict startup path. Startup code, vector tables, linker scripts, stacks, and memory initialization determine whether C code can run safely.
Learning Objectives
By the end of this lesson, you should be able to trace reset execution, explain .text, .data, .bss, heap, and stack placement, read a linker map at a basic level, and identify common startup failures.
Reset Flow
On many Arm Cortex-M MCUs, the vector table starts with the initial stack pointer followed by interrupt handler addresses.
Memory Sections
.text: code, normally stored in flash..rodata: read-only constants in flash..data: initialized variables copied into RAM..bss: zero-initialized variables in RAM.- stack: call frames and interrupt context in RAM.
- heap: dynamic allocation area in RAM, if used.
The startup file copies .data initial values from flash to RAM and clears .bss to zero.
Linker Script Responsibilities
A linker script defines memory regions and places sections.
FLASH : ORIGIN = 0x08000000
FLASH : LENGTH = 256K
RAM : ORIGIN = 0x20000000
RAM : LENGTH = 64K
It also exports symbols used by startup code, such as start and end addresses for .data and .bss.
Worked Example: RAM Budget
An MCU has 64 KiB RAM. The map file reports .data = 3 KiB, .bss = 18 KiB, heap reserve 4 KiB, and stack reserve 8 KiB.
$$
3+18+4+8=33KiB
$$
Remaining RAM:
$$
64-33=31KiB
$$
This looks healthy, but interrupt nesting, DMA buffers, RTOS task stacks, and library calls must still be checked.
Vector Tables and Handlers
Every enabled interrupt needs a valid handler. A common pattern aliases unused handlers to a default fault loop. Production code should log or expose enough fault context to debug resets.
Practical Checks
- Confirm vector table address matches boot mode and bootloader offset.
- Inspect
.mapafter every major feature addition. - Fill stack with a pattern and measure high-water mark.
- Keep DMA buffers in memory regions accessible by the DMA engine.
- Align sections as required by cache, MPU, or flash programming rules.
Common Mistakes
- Changing flash origin for a bootloader but not vector table relocation.
- Forgetting to copy
.dataor zero.bssin custom startup code. - Allocating large arrays on the stack.
- Assuming all RAM banks are equivalent for DMA.
- Ignoring C library heap use.
Summary
Startup code prepares the C runtime, and the linker script defines where every byte lives. Reading the map file, budgeting RAM, and checking vector table placement prevent many hard-to-debug boot failures.
Further Reading
- Arm, "Cortex-M Exception Model and Vector Table" documentation.
- GNU ld linker script manual.
- MCU vendor startup file and memory map reference manuals.