Introduction
Firmware for a Cortex-M microcontroller is often kept as a plain .bin file: the bytes that go into the chip’s flash, from the
first one, with nothing added. A compiler’s objcopy -O binary writes it, and so does a flash dump. The file does not say what
it is: the extension .bin is used by hundreds of formats, so the explorer does not take a .bin file for this one
on its name. This page describes what such a file does contain and what has to be said about it.
The vector table
The one structure in the file is the vector table at its start. A Cortex-M processor reads the stack pointer from word 0 and the address of the reset handler from word 1 when it starts, and the other 14 system words and the interrupt words after them are handler addresses, each with the low bit (the Thumb bit) set. The names of the words depend on the architecture level; they are on the flash image page of UF2, which reads the same table. How many interrupt words follow is not in the file (a Cortex-M0+ has up to 32, larger cores up to 240), so the explorer shows 48 words unless told otherwise, and cuts the table short where the first handler’s code begins.
When the explorer offers it
The explorer finds this format only when you press Identify on a file that no other format took, and then offers it under Read as. It is offered when the first 64 bytes pass a check of a vector table:
- the stack pointer is a multiple of 4 between
0x10000000and0x3FFFFFFF; - the reset address has the Thumb bit set and is not
0xFFFFFFFF; - the HardFault address has the Thumb bit set;
- the NMI, SVCall, PendSV and SysTick addresses are zero or have the Thumb bit set;
- the addresses that are set lie within 16 MiB of the reset address.
This is a check of the words and not a proof that a file is a Cortex-M image. Run over 30,000 files on one computer (emulator firmware,
hardware projects and source trees), it passed 35 files, all of them real firmware images of Cortex-M boards, and no other file. That sample
is small and says nothing about other files, which is why the format is not tied to the name .bin. An image whose table is not at
the start, or whose stack pointer is outside the range, is not offered, and the explorer cannot read it as this format.
Base address
The file does not say at which address its first byte lives. The reset address in the table does, if the image is not a position-independent
one: the explorer takes the reset address rounded down to a multiple of 16 MiB as the base when that puts the reset address inside the image,
and 0 otherwise. The Base address choice overrides it. Common bases are 0x08000000 for STM32 flash,
0x10000000 for the flash of the RP2040 and RP2350 and 0x00000000 for the Nordic, Microchip and NXP parts. For the
emulator firmware found on the computer, this rule gave the same base as the emulator’s own page states for every image of the boards whose
page states one (a second-core image of the Flipper Zero, which lies at another address, was left out of the comparison).
Architecture level
The image does not say which core it is for either. The ARM architecture choice sets which encodings are valid: ARMv6-M for the Cortex-M0 and M0+, ARMv7-M for the M3, ARMv7E-M for the M4 and M7, ARMv8-M for the M23 and M33. The default is ARMv7E-M, which decodes the instructions of the smaller cores too, so a first look at any image reads. The Floating-point unit choice turns the coprocessor 10 and 11 encodings into floating-point instructions; the Vector table offset choice moves the table for an image that has a second-stage bootloader in front of it (an RP2040 flash image has 256 bytes of it), and the Start address opens the disassembly elsewhere than at the reset handler.
Not described
- Viewer: the table is read and named, the whole image is disassembled as Thumb code (every byte is decoded as an instruction; code and data are not told apart), and the ARMv6-M system region is named. No peripheral names are given, as the file does not say which chip it is for. The viewer has not been run in a browser by its author.
- Reference: the second-stage bootloaders of the RP2040, the image headers of boot loaders such as MCUboot, and the names of the interrupts of any one chip.
Links
Software
- llvm-objcopy – converts an ELF file into a raw binary, as
objcopy -O binarydoes (Windows, macOS, Linux) - picotool – inspects and loads images for the Raspberry Pi RP2040 and RP2350 (Windows, macOS, Linux)
Reference
- UF2 flash image – the same vector table, read from a UF2 file
- ARM instruction set – the Thumb and Thumb-2 instructions the explorer decodes