Loading header...

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

flowchart TD R[Reset] --> SP[Load initial stack pointer] SP --> RV[Read reset vector] RV --> SYS[SystemInit clocks and FPU] SYS --> DATA[Copy .data from flash to RAM] DATA --> BSS[Zero .bss] BSS --> CTOR[Run constructors if used] CTOR --> MAIN[Call main]

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 .map after 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 .data or zero .bss in 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.

Mind Map

mindmap root((Startup and Memory)) Core concept Reset before main Linker places sections RAM must be budgeted Applications Bootloader offset Crash debug DMA buffers RTOS stacks Calculations RAM equals data plus bss plus stack plus heap Flash usage Stack high water Vector base address Design rules Copy data Zero bss Reserve stack Read map file Practical checks Vector table Map symbols Fault handler DMA memory Common mistakes Wrong flash origin Huge local arrays Hidden malloc No stack measurement