5.5.16Embedded Systems & Real-Time Software

Startup code — vector table, reset handler, stack initialization

2,284 words10 min readdifficulty · medium1 backlinks

WHY does startup code even exist?

WHAT happens physically at reset (ARM Cortex-M example):

  1. CPU reads the first word of memory → loads it into the Main Stack Pointer (MSP).
  2. CPU reads the second word → loads it into the Program Counter (PC) — this is the address of the Reset Handler.
  3. Execution begins at the Reset Handler.

The Vector Table

Offset   Contents
0x00     Initial MSP value        (top of stack)
0x04     Reset_Handler            (entry point)
0x08     NMI_Handler
0x0C     HardFault_Handler
...      ...
0x40+    IRQ0, IRQ1, ... (peripheral interrupts)

In C, the table is just a const array of function pointers placed in a special linker section:

__attribute__((section(".isr_vector")))
void (* const vector_table[])(void) = {
    (void (*)(void)) &_estack,   // 0x00: top of stack (NOT a function!)
    Reset_Handler,               // 0x04
    NMI_Handler,                 // 0x08
    HardFault_Handler,           // 0x0C
    /* ... */
};

The Reset Handler — manufacturing the C environment

The Reset Handler runs before main(). Its job is to make these C facts true:

C source Needs at runtime
int g = 42; (initialized global) The value 42 must be copied from Flash into the variable's RAM address
int z; (uninitialized global) Must be zeroed
main() calls functions Stack must work
extern uint32_t _sidata, _sdata, _edata, _sbss, _ebss, _estack;
 
void Reset_Handler(void) {
    uint32_t *src = &_sidata;
    uint32_t *dst = &_sdata;
    while (dst < &_edata) *dst++ = *src++;   // copy .data
    for (dst = &_sbss; dst < &_ebss; ) *dst++ = 0;  // zero .bss
    __libc_init_array();   // C++/static constructors
    main();
    while (1) { }          // trap: main must never return
}

Stack Initialization

So _estack is set by the linker to the highest RAM address + 1 (the end). Loaded into MSP at reset, the first push lands just below it.

Figure — Startup code — vector table, reset handler, stack initialization

Flashcards

What three things does startup code provide to enable a C program on bare metal?
A valid stack (SP), initialized .data (copied Flash→RAM) and zeroed .bss, and an entry vector to main.
On Cortex-M, what does the hardware load from the first two words of the vector table at reset?
Word 0 → initial Main Stack Pointer (MSP); Word 1 → Program Counter (address of Reset_Handler).
Why is vector table entry 0 NOT a real function pointer?
It's the initial stack-top value; it's cast to function-pointer type only to fit the array. The hardware uses it as the MSP, never jumps to it.
What is the difference between .data and .bss?
.data = initialized globals (values stored in Flash, copied to RAM at reset). .bss = zero-initialized globals (no Flash storage; cleared to 0 at reset).
What linker symbols drive the .data copy and why?
_sidata (Flash source), _sdata/_edata (RAM dest range). Copy maps each RAM offset to the same Flash offset from _sidata.
Why must the reset handler loop forever if main() returns?
There is no OS to return to; returning would pop garbage into PC. The infinite loop traps it safely.
On Cortex-M, which direction does the stack grow and where does _estack point?
Full-descending: grows downward. _estack = top of RAM (highest address + 1), loaded into MSP.
What real-world bug appears if you forget to zero .bss?
Uninitialized globals start with random power-up RAM garbage; works on some boards, fails on others — a heisenbug.
Why is the stack pointer the very first thing initialized?
Even hardware interrupt entry needs a valid stack to push registers; functions need it to store return addresses/locals.

Recall Feynman: explain to a 12-year-old

Imagine you build a robot and switch it on. The robot's brain wakes up totally blank — it doesn't even know where its notebook (memory) is. Startup code is a little checklist the robot runs first: "Where's my notebook to scribble notes? → grab the stack." "Copy my starting facts from the permanent book (Flash) into my scribble notebook (RAM)." "Erase the blank pages so they're truly empty (zero them), not full of old smudges." Only after this tidy-up does the robot start its real job (main). Skip the checklist and the robot reads smudges as facts and goes haywire.

Connections

  • Linker scripts and memory sections (.text .data .bss)
  • ARM Cortex-M exception and interrupt model
  • Stack vs Heap memory layout
  • The C runtime and crt0
  • Bootloaders and VTOR relocation
  • Volatile, memory-mapped registers and hardware init

Concept Map

reads first word

reads second word

entry 0

entry 1

entries 2+

jumps to

enables

allows

prepares

then calls

placed via

indexed O(1)

CPU Reset

Initial MSP

Program Counter

Vector Table

Reset Handler

Exception / IRQ Handlers

Stack Initialization

Function Calls

RAM: .data / .bss

main

.isr_vector section

Hinglish (regional understanding)

Intuition Hinglish mein samjho

Socho tumne ek microcontroller power-on kiya. CPU bilkul blank hota hai — usse pata hi nahi ki main() kahan hai, variables kahan rakhne hain, ya stack kaha hai. Startup code wahi chhota sa assembly + C ka pul hai jo bare silicon ko ek complete C environment de deta hai. Teen kaam: vector table (kahan se start karna hai bataao), reset handler (RAM ko ready karo), aur stack initialization (function calls kaam karein).

Cortex-M par hardware reset par sabse pehla word memory se padhta hai aur usse MSP (stack pointer) me daal deta hai — kyunki stack to sabse pehle chahiye, interrupt aaye to registers push karne ke liye bhi. Dusra word PC me jaata hai, jo Reset_Handler ka address hai. Yahin se tumhara code chalna shuru hota hai. Vector table bas addresses ka array hai — interrupt aaye to hardware seedha index karta hai, koi search nahi.

Reset handler ka main kaam: .data (jaise int g = 42;) ki initial values Flash se RAM me copy karo, aur .bss (jaise int z;) ko zero kar do. Power-up par RAM me garbage hota hai, isliye agar .bss zero nahi kiya to ek board pe chalega, dusre pe crash — classic heisenbug. Stack RAM ke top se neeche ki taraf badhta hai (full-descending), aur heap neeche se upar — taaki dono beech me takrayein to overflow ek clear failure ban jaaye.

Yaad rakho mnemonic: Stack, Copy, Zero, Main — pehle stack set, phir data copy, phir bss zero, phir main. Yeh chhoti si glue layer hi C ke saare assumptions sach banati hai; ise skip kiya to program shuru hone se pehle hi galat.

Go deeper — visual, from zero

Test yourself — Embedded Systems & Real-Time Software

Connections