Linker Map Auditor

Paste the .map your linker already wrote. Get the exact bytes: which region overflowed, and which object file spent them. Runs entirely in this tab - the file never leaves your machine.

Free here, for one build

Everything above is free, for every map file you have, forever. The full version answers the question one build cannot: what changed since last time.

Get the full version - $29

$29 once - one licence key per person or team seat - 7-day full refund. A freelance embedded engineer averages $103/hr (contractrates.fyi, 2026); this is about 17 minutes of one.

Your map file

Works with any GNU ld map: arm-none-eabi, riscv, avr, msp430, and the map files written by STM32CubeIDE, MCUXpresso and PlatformIO.

Get the complete version $29

This page is the working piece. The full pack has everything below.

Read the .map your linker already wrote and see, in exact bytes, which object file is spending your FLASH and RAM - and by how much you overflowed.

A freelance embedded software engineer averages $103.27/hour (contractrates.fyi crowdsourced rates, 2026); one afternoon spent hand-reading a map file costs more than this tool.

Buy the full version โ€” $29
Want the full version?
Enter your email and we send the download link.
ENDEJAESPT

Find a tool

ยท ReadyStack

Worked example

Real numbers from this tool, line by line.

RAM 8,872 / 8,192 bytes: reading the one line your linker refuses to print

RAM 8,872 of 8,192 bytes, over by 680 - that is the complete answer a firmware engineer needs when arm-none-eabi-ld refuses to link, and it is the one line the linker never prints. What it prints instead is region 'RAM' overflowed by 680 bytes, and then it stops. It tells you that you lost. It does not tell you who took it.

The information is not missing. It is sitting in build/app.map, the file your build already wrote, twenty thousand lines long, in hexadecimal, with section sizes on one line and the object file that owns them on another. Everything you need is public, in your own repository, and nobody looks.

What is actually in a map file

Three things, and they have to be combined:

  1. The Memory Configuration block: the real origin and length of every region.
  2. Output sections, each with an address and a size, some with a separate load address.
  3. Input sections, each naming the object file or archive member that contributed it.

Combining them is the whole job, and it has two traps.

.data is charged twice. Its variables live in RAM at run time, and its initialiser sits in FLASH so it can be copied there at boot. A script that counts it once is wrong by exactly the size of your initialised globals. In the build above that is 612 bytes on both sides.

Debug sections are charged to nothing. .debug_info, .comment and .ARM.attributes are laid down at address 0, inside no region, and never reach the device. Count them and a build that added debug symbols appears to have grown by forty kilobytes it did not grow by.

The answer, for a real build

REGION              USED        SIZE        FREE     USED%  STATUS
FLASH             15,088      65,536      50,448     23.0%  ok
RAM                8,872       8,192        -680    108.3%  OVER by 680 B

RAM - top spenders
       4,096  uart.o                     .bss.uart_rx_buf
       2,048  log.o                      .bss.log_pool
         640  app.o                      .data.cfg, COMMON
         448  libhal.a(stm32f4xx_hal.o)  .bss.hal_state
         100  main.o                     .data.tick
       1,540  (not attributed)           padding, heap and stack reservations

Now the fix is obvious rather than archaeological: one UART ring buffer is holding half of an 8 KB device. Halve it and the build fits with room to spare - 5,800 of 8,192 bytes, 70.8%.

Notice the last row. Alignment padding and the _Min_Heap_Size / _Min_Stack_Size reservations belong to no object file, so most hand-written scripts quietly drop them and their columns stop adding up. Here they get their own line, and the parts sum to the region total exactly: 7,332 attributed plus 1,540 unattributed is 8,872.

Why not ask a model

Because the task is adding twenty thousand hexadecimal numbers and grouping them by owner. A language model will give you a confident total, and you will have no way to tell that it drifted. This is arithmetic; it wants a parser, not a guess. Bloaty and puncover do it well but want the ELF and a matching toolchain; the .map file is the artefact you already have, including on a Windows machine with nothing installed.

Try it on your own build

Build with -Wl,-Map=build/app.map, then paste the file into the free web version, or open it in VS Code and run Linker Map: Analyze this linker map. Reading one map file is free, with no key and no limit. What one build cannot tell you is what changed since the build that fit - and that comparison, per-region budgets, and a CI-ready report are what the licence adds.

15 seconds โ€” what it actually does

Questions people ask

What does Linker Map Auditor actually do?

It reads the .map file GNU ld writes with -Wl,-Map and turns it into a byte-exact budget: every MEMORY region's capacity, used bytes, free bytes and overflow, plus every object file, archive member and input section ranked by what it spends in that region. The .data section is charged to both FLASH and RAM, because both costs are real.

Who is Linker Map Auditor for?

Embedded firmware engineers on microcontrollers with a fixed FLASH and RAM budget: STM32, nRF, ESP32, AVR, RISC-V, built with arm-none-eabi-gcc, STM32CubeIDE, MCUXpresso, Zephyr or PlatformIO. It is for the moment the linker prints region RAM overflowed by 680 bytes and you must find which of two hundred object files is responsible.

Why not just ask an AI chatbot or use a free tool?

A chat model cannot reliably add twenty thousand hexadecimal sizes; it returns a confident total you cannot check. Bloaty and puncover need the ELF plus a matching toolchain, and MemBrowse is a CI service to wire up. The .map file is already on your disk, and this reads it in the editor already open, on Windows, with nothing installed.

What is free, and what needs a licence?

Analysing one map file is free forever: no key, no watermark, no file limit, the full region table and the full contributor ranking. The licence adds what a single build cannot show: saving a baseline, diffing a later build to see which object grew, per-region budgets that pass or fail, and JSON plus Markdown export for CI.

What would it cost to do this by hand?

Hand-reading a linker map means summing hexadecimal sizes and attributing them across a file routinely twenty thousand lines long. A freelance embedded software engineer averages $103.27 an hour on crowdsourced 2026 rate data, so one afternoon of that hunt costs several hundred dollars, and it repeats every time the firmware grows.

Ask about this tool

One question, answered by the person who built it. Your email only if you want the answer sent.