7. Toolchain and build¶
Time: 1 week · Board: Pico 2 · Prerequisites: Module 3
Why this matters¶
Between main.c and a blinking LED there is a compiler, an assembler, a linker with a script that decides where every byte goes, startup code that copies your initialized variables into RAM, a vector table the hardware reads before your code runs, and a flashing tool. Most self-taught engineers let an IDE hide all of it. Then one day the binary does not fit, a global variable is mysteriously zero, or main() is never reached, and there is nobody to ask. This module makes the whole pipeline visible once so it never scares you again.
You will be able to¶
- Describe each stage from source to running firmware and name the tool that does it.
- Read a linker script and a map file, and explain
.text,.data,.bss, and the stack and heap. - Explain what startup code does before
main()and where the vector table lives. - Build a project with Make or CMake from the command line, without an IDE.
- Use Git well enough to work on a team.
Learn¶
- Article Compiling, Linking, and Locating by Michael Barr, from Programming Embedded Systems ~45 min
The classic chapter. What each stage does and why embedded adds a "locating" step. - Article From Zero to main(): Bare metal C by François Baldassari, Memfault Interrupt ~1 h, plus the follow-up posts linked at the end, ~2 h
Writes the startup code and linker script for a Cortex-M by hand, one line at a time. The single best resource in this module. - Article How to Write Linker Scripts for Firmware by Memfault Interrupt ~1 h
Memory regions, sections, symbols, and the tricks real projects use. - Article GNU Binutils: the ELF Swiss Army Knife by Memfault Interrupt ~45 min
objdump,nm,readelf,size,objcopy. You will use these weekly. - Article Tools for Firmware Code Size Optimization by Memfault Interrupt ~30 min
Reading the map file and finding out what is eating your flash. - Docs Arm GNU Toolchain downloads Reference
arm-none-eabi-gccand friends, the compiler behind the Pico SDK and most STM32 projects. - Article Makefile Tutorial ~1 h
Enough Make to read any firmware Makefile you will encounter. - Docs CMake Tutorial steps 1 to 3, then An Introduction to Modern CMake ~2 h
The Pico SDK, Zephyr, and most modern firmware projects use CMake. Learn to readCMakeLists.txtand add a source file. - Course Pro Git chapters 1 to 3, and Learn Git Branching ~3 h
Commit, branch, merge, rebase, and how to undo. Every team uses Git. Practice the branching game until it is boring.
Do¶
- Checkpoint 7.1: Build from the terminal. Build your register blink from Module 3 with
cmakeandmake(orninja) from a terminal, no IDE. Runarm-none-eabi-sizeon the ELF and explain each number. Runarm-none-eabi-objdump -dand find yourmain(). - Checkpoint 7.2: Read the map. Enable the linker map file. Find: the vector table's address,
main(), one of your global variables, and the end of.bss. Add astatic const uint8_t table[1024]and astatic uint8_t buffer[1024]and show, from the map, which sections grew and by how much. - Checkpoint 7.3: Startup by hand. Following the "From Zero to main()" series, write your own minimal vector table, reset handler (copy
.data, zero.bss, callmain()), and linker script for the Pico 2, building on what Low Byte Productions showed in Module 3 for the boot stage. Blink the LED with no SDK at all. This is the hardest checkpoint in Phase 2 and the most worthwhile. - Checkpoint 7.4: Version it. Put your Phase 1 and 2 projects in a Git repository with a sensible
.gitignore, one commit per checkpoint, and a README with build instructions. Push it to GitHub. This is the start of your portfolio (Module 20).
Check yourself¶
- What is the difference between the
.dataand.bsssections, and what does startup code do with each? - Why does the vector table have to be at a specific address, and what is in its first entry?
- A global
int counter = 5;reads as 0 at runtime. Name two causes in the toolchain. - What does the linker do when two object files define the same symbol? What does
weakchange? - Your binary is 4 KB too big for flash. Name three things you would check in the map file.
Go deeper¶
Optional extras
- Book Bare-metal programming for ARM by Daniels Umanovskis Free, ~6 h
A free ebook that builds startup code, a linker script, a UART driver, and interrupts on an emulated Arm board. Complements the Interrupt series. - Article Exploring Startup Implementations: Newlib (ARM) by Phillip Johnston ~1 h
What the standard C library's startup does for you, and what it costs. - Article Code Size Optimization: GCC Compiler Flags and Reproducible Firmware Builds by Memfault Interrupt ~1 h
-Os,-ffunction-sections,--gc-sections, LTO, and why the same source should produce the same bytes. - Docs GNU ld manual Reference
The full linker script language, for when a blog post is not enough. - Docs GCC attributes Reference
section,aligned,used,naked,interrupt: the attributes startup code depends on.