What does Reset_Handler do before main() is called?
Reset_Handler is the first code that runs after the hardware loads SP and PC from the vector table. Its job is to prepare the C runtime so that main() can use globals safely. Three core steps, in order:
-
Copy
.datafrom Flash (LMA) to RAM (VMA). Initialized globals likeint x = 42;have their initial values stored in Flash (as part of the binary image), but the variables themselves live in RAM. The linker provides three symbols —_sidata(Flash source),_sdata(RAM destination start),_edata(RAM destination end) — and Reset_Handler runs a tight*dst++ = *src++loop to bridge them. -
Zero
.bss. Uninitialized globals live in.bss; the C standard says they start as zero. Reset_Handler memsets the region from_sbssto_ebssto zero. -
Call
SystemInit()(typically from CMSIS) to bring up the clock tree (switch from HSI to PLL, raise Flash wait states, configure prescalers) and any other early hardware init.
Then it calls main(). If main returns, Reset_Handler typically loops in while(1) {} — main returning is unusual on bare metal and usually indicates a bug.
A subtle but important point: before step 1 completes, no C global is valid. Anything called before that — including SystemInit on some platforms — must work purely with register-level operations and not rely on globals. This is why startup sequences are sometimes written in assembly: to control exactly what code runs before the C runtime is set up.
Some toolchains also call __libc_init_array() between SystemInit and main to run C++ static constructors. Bare-metal C without C++ skips this.
The hardware side of boot (reset sources, vector table, clock-tree bring-up) lives separately on the Boot, vector table, and clock bring-up page; this page covered the C-runtime side.
Source: Build Systems Q&A
