README
avrmem is an AVR ELF memory and symbol explorer written in C.
The project separates ELF semantics, AVR device discovery, AVR address translation, SFR/register metadata, and command-line presentation into distinct translation units.
Features
- Parses ELF32 little-endian AVR executables without
libelf. - Resolves ELF sections and symbols.
- Resolves symbol VMA, physical address, LMA, and AVR flash word address.
- Automatically discovers the AVR device from ELF device metadata.
- Accepts an explicit
--deviceoverride. - Discovers physical FLASH, SRAM, and EEPROM sizes from the selected AVR-GCC/avr-libc toolchain.
- Discovers AVR-GCC linker address-space regions from the generated linker map rather than hardcoding MCU-specific linker constants.
- Parses
_SFR_IO8()and_SFR_MEM8()definitions emitted by avr-libc. - Associates resolved DATA-space addresses with discovered SFRs.
- Provides section, symbol, memory-model, and memory-map views.
Project layout
.
├── Makefile
├── README.md
├── src/
│ ├── avr_device.c
│ ├── avr_device_probe.c
│ ├── avr_elf.c
│ ├── avr_sfr.c
│ └── avrmem.c
├── include/
│ ├── avr_device.h
│ ├── avr_device_probe.h
│ ├── avr_elf.h
│ └── avr_sfr.h
├── bin/
└── docs/
├── _config.yml
├── index.md
├── guide.md
├── api.md
├── architecture.md
├── testing.md
└── README.md
bin/ contains generated binaries and is not intended to contain source
files.
Requirements
The current host implementation assumes a POSIX environment and requires:
- a C11 compiler
avr-gccavr-libc- AVR binutils selected by
avr-gcc - POSIX process and filesystem APIs
The selected AVR device is supplied at runtime with --device, or inferred
from the ELF when the option is omitted.
Build
Normal build:
make
The executable is generated as:
bin/avrmem
Debug build
Any of the following enables the debug configuration:
make debug
make DEBUG=1
make DEBUG=yes
make DEBUG=true
make DEBUG=on
The debug configuration uses:
-O0
-g3
-DDEBUG
Usage
bin/avrmem firmware.elf
bin/avrmem --memory firmware.elf
bin/avrmem --sections firmware.elf
bin/avrmem --symbols firmware.elf
bin/avrmem --symbol counter firmware.elf
bin/avrmem --map firmware.elf
bin/avrmem --device atmega328p firmware.elf
bin/avrmem --device atmega328p --symbol counter firmware.elf
Options must precede the ELF filename.
Examples:
bin/avrmem --sections firmware.elf
bin/avrmem --device atmega328p --sections firmware.elf
bin/avrmem --device atmega328p --symbol led_app firmware.elf
Automatic device discovery
When --device is omitted, avrmem opens the ELF and attempts to obtain
the AVR device name from the ELF’s AVR device metadata.
The discovered device name is then passed to the device-probe layer.
When --device is supplied, the explicit device name is used for device
initialization.
Address model
The project distinguishes between the ELF/linker address representation and the physical AVR address.
Conceptually:
ELF/linker address
|
v
AvrDevice address classification
|
v
physical AVR address
This distinction is important for AVR DATA-space addresses.
For example, an ELF DATA-space address can represent a physical SRAM address after removing the device’s linker-space origin.
FLASH
Program-memory ELF addresses are represented as byte addresses.
The device model additionally provides the conversion from a physical FLASH byte address to the AVR CPU instruction/word address.
SRAM
.data, .bss, stack, heap, and .noinit are runtime SRAM allocations.
They are not separate physical memory types.
Their differences are determined by ELF sections and initialization semantics.
.data
A .data object normally has:
runtime VMA -> SRAM
load LMA -> FLASH
The symbol LMA is derived from the section’s load mapping.
.bss
.bss is SHT_NOBITS, so it has runtime storage but no file-backed
initialization image.
.noinit
.noinit is runtime SRAM whose contents are preserved across startup rather
than initialized from the FLASH image.
Device discovery architecture
Device information is deliberately not maintained as a hardcoded MCU table.
The probe layer uses the selected AVR-GCC toolchain:
avr-gcc -mmcu=<device>
The preprocessor environment provides:
- physical memory information
- AVR device identity
- SFR definitions
The linker map provides:
- TEXT linker region
- DATA linker region
- EEPROM linker region
This keeps the device abstraction synchronized with the installed AVR toolchain.
SFR discovery
The SFR database is derived from concrete avr-libc macro definitions such as:
#define PORTB _SFR_IO8(0x05)
#define UCSR0A _SFR_MEM8(0xC0)
The SFR layer normalizes these into physical AVR DATA-space addresses.
For _SFR_IO8():
physical DATA address =
encoded I/O address + __SFR_OFFSET
For _SFR_MEM8():
physical DATA address =
encoded memory address
The device abstraction then provides name and address lookup.
Documentation
The docs/ directory is also the source tree for a Jekyll documentation
site.
Documentation includes:
This page mirrors the top-level README.md for the documentation site.
Development principles
The main architectural constraints are:
- Do not add MCU-specific constants to
avrmem.c. - Do not parse ELF structures in the command-line frontend.
- Do not duplicate AVR address calculations outside
avr_device.c. - Do not create per-MCU initialization functions.
- Prefer discovery from the installed AVR-GCC/avr-libc toolchain.
- Keep physical memory and ELF/linker address spaces distinct.
- Treat SFR discovery as an auxiliary device capability.
- Keep ownership of allocated resources explicit.
Testing
The automated suite runs under the plain Makefile (no extra build
system) and uses the single-header framework greatest.h (submodule
with bundled offline fallback, see tests/vendor/):
make clean
make test
This builds bin/avrmem, generates AVR fixtures with avr-gcc under
tests/fixtures/out/ (one firmware.elf per matrix device: atmega328p,
atmega2560, attiny85), and runs unit (SFR, device, ELF validation),
integration (real probe + fixture ELF, incl. SFR association), and CLI
black-box tiers. Tiers needing avr-gcc print SKIP and exit 0 when
the toolchain is absent; unit tiers always run. A sanitizer run is
available via make test-asan.
A manual smoke-test sequence is:
make clean
make
bin/avrmem firmware.elf
bin/avrmem --sections firmware.elf
bin/avrmem --symbols firmware.elf
bin/avrmem --map firmware.elf
bin/avrmem --symbol led_app firmware.elf
bin/avrmem --device atmega328p --symbol led_app firmware.elf
See testing.md for the complete testing procedure (manual sections plus the automated test suite section).
License
MIT