Search topics...
Build SystemsSections & Memory Layoutfoundational

How do you read a linker map file to find what's bloating your binary?

0 upvotes
Practice with AISoon
Study the fundamentals first — Build Systems topic page

The linker map (generated via -Wl,-Map=firmware.map) is verbose but structured. Three sections matter:

  1. Memory configuration — the top of the file shows your MEMORY regions and how much of each is used. A quick Used: 458752 / 524288 (87%) for FLASH tells you how close to the limit you are.

  2. Section/symbol map — the body of the file lists every output section, every input section it contains, and every linker-defined symbol with its address and size. This is where bloat investigation happens. Search for the section name (typically .text or .rodata) and look for the largest entries:

text
.text 0x08000000 0x6e80
.text.main 0x080012a0 0x180 build/main.o
.text.printf 0x08001420 0x4a00 /opt/.../newlib/libc.a(printf.o) ← here it is

The rightmost column tells you which .o file or library member brought the symbol in. So printf.o(libc.a) means newlib's printf — likely pulled in by a printf("%f", ...) somewhere that's dragging in float-formatting code.

  1. Cross-references — at the end, the linker lists which .o files reference which symbols. Useful for "where is this symbol used?" investigations.

The faster alternative for most bloat hunts is arm-none-eabi-nm -S --size-sort -r firmware.elf | head -20. The nm output shows the largest symbols sorted descending, with their location codes (T=text, D=data, etc.). 80% of bloat investigations are solved in 30 seconds with this command. The map file is the deeper-dive tool when you need to know which library or .o introduced a symbol.

For tracking size over time, modern teams put arm-none-eabi-size firmware.elf into CI and alert on regression — typically failing the build if text grows more than 1% or bss grows more than 5%.

Source: Build Systems Q&A