Skip to content

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

Do

  • Checkpoint 7.1: Build from the terminal. Build your register blink from Module 3 with cmake and make (or ninja) from a terminal, no IDE. Run arm-none-eabi-size on the ELF and explain each number. Run arm-none-eabi-objdump -d and find your main().
  • 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 a static const uint8_t table[1024] and a static 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, call main()), 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 .data and .bss sections, 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 weak change?
  • Your binary is 4 KB too big for flash. Name three things you would check in the map file.

Go deeper

Optional extras