Startup Code & the Reset Handler

What happens between power-on and main(): the vector table, copying .data, zeroing .bss and calling SystemInit.

On a PC the operating system loads your program and sets up its memory. On a microcontroller, the first code to run after reset is a small startup routine — usually supplied by the vendor in assembly or C, and worth reading at least once.

Power-on on a Cortex-M

The linker script defines _sidata, _sdata, _edata, _sbss, _ebss and _estack (see the previous module).

Copy loop: initial values of .data are moved from flash to RAM.

Zero loop: .bss is cleared, which is why C guarantees uninitialised globals are 0.

SystemInit configures clocks; then main runs and must never return.

Weak aliases let any ISR you define elsewhere replace the default handler.

Weak symbols and the vector table

void USART2_IRQhandler(void) {... } // lower-case 'h' void USART2_IRQHandler(void) {... }

The name must match the startup file exactly; a typo leaves the weak default (an infinite loop) in the vector table.

Reading a global in a function called before the.data copy Only call code that uses globals after the startup copy/zero loops

Before the copy, initialised globals still contain whatever was in RAM at power-up.

What are the first two entries of a Cortex-M vector table?

The initial value of the main stack pointer, then the address of the reset handler.

Why does an uninitialised global start at 0 on a microcontroller?

Because the startup code explicitly zeroes the .bss section before calling main.