FAQ
TL;DR: Enabling -O3 without -ffreestanding on bare-metal STM32 almost doubles code size (+100 %) and breaks builds, while “The -g option produces debugging information GDB can use” [Elektroda, lazor, #17571595; #17571519].
Why it matters: Correct startup, flags, and linker settings decide whether your Cortex-M even reaches main().
Quick Facts
• Reset vector lives at 0x00000004; initial SP at 0x00000000 [Elektroda, _lazor_, post #17568319]
• Example flash region: 0x0800 0000, length 0x1000 (4 KB) [Elektroda, _lazor_, post #17568319]
• Example SRAM region: 0x2000 0000, length 12 KB [Elektroda, _lazor_, post #17568319]
• -ffreestanding stops GCC auto-calling memset/memcpy under -O3 [Elektroda, _lazor_, post #17571595]
• NUCLEO-L432KC with on-board ST-Link ≈ PLN 49 [Elektroda, _lazor_, post #17612659]
What exactly runs before main() on a Cortex-M?
Execution starts at address 0x00000000, reading the initial stack pointer, then jumps to the Reset_Handler entry at 0x00000004. Reset_Handler calls _cstartup, which zeroes .bss, copies .data from flash to SRAM, sets up clocks if needed, and finally calls main() [Elektroda, lazor, #17568319].
Why do I need my own startup.S file?
Startup.S defines the vector table, initial SP value, and Reset_Handler. Without it, the linker has no entry point, and the MCU boots into an undefined state. Writing it yourself lets you keep binaries small and free of vendor libraries [Elektroda, lazor, #17568319].
What does .thumb_func really do?
.thumb_func marks following symbols as Thumb functions. The assembler stores an odd address so branches load PC with bit0=1, forcing Thumb mode. Using an even address on Cortex-M freezes execution at the first ISR fetch [Elektroda, jta, #17597051].
How does the linker script map sections?
The sample script places .text and .rodata in flash, .bss and .data in SRAM. .data uses “AT (__rodata_end__)” so its initial values reside in flash but get copied to RAM during _cstartup [Elektroda, lazor, #17568319].
How do I copy .data and clear .bss in C?
Use pointers provided by the linker:
- while(bss<bss_end) *bss++ = 0;
- while(data<data_end) data++ = rodata_end++;
- main();
This three-step loop runs in _cstartup before main [Elektroda, lazor, #17568319].
Which compiler flags are mandatory for debugging?
Compile with -g to embed DWARF symbols; without it, GDB cannot match addresses to source lines [Elektroda, lazor, #17571519]. Keep optimisation at -O0 or -Og for single-stepping clarity [Elektroda, simw, post #17571220]
Why add -ffreestanding when I raise optimisation to -O3?
-O3 makes GCC replace loops with memset/memcpy. In bare-metal projects these library calls are missing, so linking fails or the MCU jumps to HardFault. -ffreestanding tells GCC not to assume the standard library exists [Elektroda, lazor, #17571595].
How can I issue a software reset on STM32 and where does execution resume?
Write 0x05FA0004 to SCB->AIRCR. After reset, the core always restarts from 0x00000000 regardless of previous VTOR settings; RCC registers retain their values [Elektroda, lazor, #17572569; RM0364, 2021].
What’s an edge case that bricks the boot?
If any vector entry holds an even address, the core attempts ARM mode (unsupported on Cortex-M) and locks up before main—no error message, just a stalled PC [Elektroda, jta, #17597051].
How do I flash and debug without a full IDE?
3-step how-to:
- openocd -f board/st_nucleo_f3.cfg
- arm-none-eabi-gdb build.elf
- In GDB: target extended-remote :3333 ➜ monitor reset halt ➜ load ➜ continue
Works with any ST-Link board [OpenOCD manual; Elektroda, lazor, #17568319].
Are 32-bit MCUs really harder than 8-bit AVRs?
No. Modern STM32 tools generate Makefiles, startup code and linker scripts automatically. Quote: “The plugin will generate makefiles, startups, and linker scripts” [Elektroda, chudybyk, post #17570228] Larger datasheets exist, but higher-level libraries and debuggers speed learning.
What low-cost boards include a ready programmer/debugger?
ST STM32L100C-Discovery (≈ PLN 39), Infineon XMC 2Go (≈ PLN 40), and NUCLEO-L432KC (≈ PLN 49) ship with on-board ST-Link or Segger probes [Elektroda, lazor, #17612659].