Flash, RAM & the Memory Map
Where your code, constants and variables physically live on a microcontroller, and why const matters for RAM usage.
A microcontroller has two kinds of memory: non-volatile flash (hundreds of KB) that holds the program, and much smaller SRAM (tens of KB) for variables. The linker decides what goes where, section by section.
A minimal linker script
Simplified GNU ld script for an STM32F4 with 512 KB flash and 128 KB RAM. '> RAM AT > FLASH' is the key line: .data runs from RAM but is loaded from flash. The _sdata/_edata/_sbss/_ebss symbols are what the startup code (next module) uses.
uint8_t font[2048] = {... }; // never modified static const uint8_t font[2048] = {... };
Without const the font is copied into RAM at boot — 2 KB of RAM wasted on data that never changes.
An initialised global int x = 5; — where is it stored?
Its initial value (5) is in flash; at start-up the startup code copies it into its RAM location in the .data section, where the program reads and writes it.
Why does .bss not take any flash space?
It only needs to be zeroed at start-up, so the image stores just its size and address, not its contents.
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128K
}
_estack = ORIGIN(RAM) + LENGTH(RAM);
SECTIONS
{
.isr_vector : { KEEP(*(.isr_vector)) } > FLASH
.text : { *(.text*) *(.rodata*) } > FLASH
_sidata = LOADADDR(.data);
.data : { _sdata = .; *(.data*) _edata = .; } > RAM AT > FLASH
.bss : { _sbss = .; *(.bss*) *(COMMON) _ebss = .; } > RAM
}