make-elf
Build ARM ELF executables with DWARF debug data for Astrobe Oberon programs
Name
make-elf – build ARM ELF executables with DWARF debug data for Astrobe Oberon programs
Synopsis
make-elf [-v] [--debug] [--symbols] [--sym-prefix prefix] [--image-def] [--rdb-dir dir] [--bss start:end] [--map file] [--entry addr] [--no-main] [-o output] [-e ext] [--nxp] [-l] [bin_file[:load_addr] …]
Description
make-elf builds a 32-bit little-endian ARM ELF executable from Oberon program binaries built with Astrobe. The resulting ELF is suitable for loading via GDB/OpenOCD, STM32CubeProgrammer, or picotool. Optionally, the ELF can include symbol tables, DWARF debug information (line-number mappings, type information, call-frame descriptions), or both.
Prerequisites
Before running make-elf, the Astrobe compilation and linking must be complete, with the output files (.bin, .map) present and unmodified.
In its simplest form, make-elf only requires the .bin and .map
files – no listing files are needed:
make-elf SignalSync.bin
To include symbols or debug data, first run gen-rdb to produce the
rdb directory containing the absolute assembly listing files (.alst):
- compile and link with Astrobe (IDE or command line)
gen-rdb SignalSync.mapmake-elf SignalSync.bin --debug
Modes of Operation
Minimal mode (no --symbols, no --debug) –
One or more binary files are specified on the command line. The ELF
contains the binary as a loadable .text section, a main and startup
symbol at the entry address, and a .bss section if auto-detected from
the .map file. No listing files are needed. This is the simplest path
for loading a program onto the target without debugging.
Symbols mode (--symbols) –
As above, but procedure and variable symbols are extracted from listing
files in the rdb directory (produced by gen-rdb). ARM mapping
symbols ($t) are also included. No DWARF debug sections are generated.
Debug mode (--debug) – Full DWARF debug information is included (implies --symbols). The ELF contains line-number mappings, type information, call-frame descriptions, and all symbols.
Debug-only mode (no binary files) – No binary files are given. The tool produces an ELF containing only symbol and debug sections, with no loadable code segments. This mode is useful when the debugger is to use the ELF solely for symbol look-up and source-level navigation, whilst the target is programmed by other means. The --debug flag is enabled automatically in this mode.
In all modes, the load address can be given explicitly (file:address) or auto-detected from the .map file when a single binary is given without an address. The first binary supplies the entry point (read from offset 4 of the vector table).
Options
- -v
- Verbose output. Print details of extracted symbols, section layout, entry address, and other diagnostic information during ELF generation.
- --debug
- Include DWARF debug sections in the output:
.debug_line,.debug_info,.debug_abbrev,.debug_aranges,.debug_pubnames,.debug_str,.debug_frame, and.ARM.attributes(ifarm-attr.cfgis present). Implies --symbols. Requires listing files in therdbdirectory (see --rdb-dir). - --symbols
- Include procedure and variable symbols extracted from listing files
in the
rdbdirectory (produced by gen-rdb). Also includes ARM mapping symbols ($t). Without --symbols or --debug, the ELF contains onlymain/startupsymbols and no listing files are needed. - --sym-prefix prefix / --sym-prefix=prefix
- Prefix all symbol names with prefix_. In the symbol table,
SignalSync_RunbecomesS_SignalSync_Run; in DWARFDW_AT_name,SignalSync.RunbecomesS_SignalSync.Run. Themainandstartupsymbols are also prefixed (eg.S_main,S_startup). Used for TrustZone dual-image debugging to distinguish Secure and Non-secure symbols when both ELF files are loaded into the same debug session. - --image-def
- Prepend a 256-byte RP2350 IMAGE_DEF picobin metadata block at
code_base - 100H, where code_base is the load address of the first binary. The block enables standalone boot after GDB or OpenOCD flash programming: the RP2350 boot ROM scans the first 256 bytes of flash for IMAGE_DEF and uses it to locate the vector table. At least one binary file must be specified when this option is used. - --rdb-dir dir / --rdb-dir=dir
- Directory containing assembly listing files (the
rdbdirectory produced by gen-rdb). Default:rdb. Only consulted when --symbols or --debug is set. The directory is also searched forarm-attr.cfg, used to generate the.ARM.attributessection. The DWARF compilation directory (DW_AT_comp_dir) is derived from this path: the parent of the rdb directory becomes the compilation directory, and the rdb directory name becomes the source subdirectory. For example,--rdb-dir s/rdbsetscomp_dirtosso that GDB resolves source files ass/rdb/Module.alst. For the default--rdb-dir rdb,comp_diris.(the current directory). - --bss start:end / --bss=start:end
- Declare a
.bss(uninitialised data) region spanning from start to end. Both addresses are hexadecimal and may use any of the accepted hex formats (see Hex Formats below). The section is emitted asSHT_NOBITSwith a matchingPT_LOADprogram header; no bytes are added to the file. This allows the debugger to read variables from RAM. The addresses typically correspond toDataStartandDataEndin the Astrobe linker configuration. If omitted and a .map file is available, the BSS range is auto-detected from theData Rangeline in the .map file. Currently, only one.bssrange can be specified. - --map file / --map=file
- Path to the linker .map file. The map file supplies global variable
addresses, and is also used to auto-detect the code base address and
BSS range when those are not given explicitly. If omitted, the tool
looks for
<first_binary>.mapin the same directory as the first binary. - --entry addr / --entry=addr
- Set the ELF entry address and
main/startupsymbol location to addr (hex). In standard mode the entry address is normally read from the first binary's vector table; this option overrides it. In debug-only mode this option is required unless --no-main is given. The address must be within 32-bit range. - --no-main
- Suppress creation of the
mainandstartupsymbols at the entry address. Useful for boot-loader images where the reset vector is not a conventional entry point. - -o output
- Write the ELF to output instead of the default file. The default is
derived from the first binary file name (replacing
.binwith.elf), or from the parent directory of the listing directory when no binary files are given. - -e ext
- Source file extension, including the leading dot. Default:
.alst. Only files matching this extension in the listing directory are processed. - --nxp
- Apply NXP-specific modifications. Writes the binary size to offset 20H in the first binary image (little-endian, 4 bytes). This satisfies the NXP boot ROM's image-size requirement.
- -l, --source-lines
- Map addresses to Oberon source lines rather than assembly listing
lines. Requires --debug. When enabled, the
.debug_linesection references Oberon source files (.Mod) rather than assembly listings. Experimental.
Hex Formats
Hexadecimal addresses throughout the command line accept three notations:
- Bare hex digits:
20000000 - C-style prefix:
0x20000000 - Oberon-style postfix:
20000000H
All three are equivalent. Case is not significant.
Binary File Specification
Each positional argument takes the form file:address, where file is the path to a raw binary and address is the hexadecimal load address. The colon separates the two fields. Paths may be absolute or relative and may use either forward or backward slashes.
When a single binary is given without a load address (no colon), the code
base address is read from the Code Range line in the .map file. This
requires a .map file to be available (explicitly via --map or
auto-detected).
The first binary's vector table is read to obtain the initial stack pointer (offset 0) and the entry point (offset 4). Subsequent binaries are placed at their respective load addresses but do not contribute an entry point.
Multiple binaries produce multiple .text-like sections and PT_LOAD
segments, enabling a single ELF to describe a multi-region flash layout.
ELF Structure
The generated ELF conforms to the ARM EABI version 5 (soft-float). The file contains the following elements, in order:
-
ELF header – 32-bit, little-endian,
ET_EXEC,EM_ARM. -
Program headers – One
PT_LOADper binary file (readable, executable), one for.bss(readable, writable,NOBITS), and one for.image_def(readable) if applicable. -
Section headers and sections –
Section Type Description .shstrtabSHT_STRTABSection name strings .image_defSHT_PROGBITSRP2350 picobin metadata (optional) .textSHT_PROGBITSFirst binary image .bssSHT_NOBITSUninitialised data region (optional) .debug_lineSHT_PROGBITSDWARF line-number program .debug_infoSHT_PROGBITSDWARF compilation unit and types .debug_abbrevSHT_PROGBITSDWARF abbreviation table .debug_arangesSHT_PROGBITSDWARF address ranges .debug_pubnamesSHT_PROGBITSDWARF public names .debug_strSHT_PROGBITSDWARF string pool .debug_frameSHT_PROGBITSDWARF call-frame information .ARM.attributesSHT_ARM_ATTRIBUTESARM build attributes .strtabSHT_STRTABSymbol name strings .symtabSHT_SYMTABSymbol table Debug sections (
.debug_*and.ARM.attributes) are present only when --debug is active. Procedure and variable symbols in.symtabrequire --symbols or --debug; without either, the symbol table contains onlymainandstartup.
Symbols
A main symbol and a startup symbol (STT_FUNC, STB_GLOBAL) are
always placed at the entry address with the Thumb bit set, unless
--no-main is given. These are present in all modes, including
minimal mode without --symbols.
With --symbols or --debug, procedure (function) symbols are
extracted from the assembly listing files. In the symbol table, dots in
Oberon qualified names are replaced by underscores
(eg. SignalSync.Run becomes SignalSync_Run), as some expression
evaluators interpret dots as structure-member operators. DWARF
compilation unit entries retain the original dotted names.
ARM mapping symbols ($t) are emitted at each procedure entry to indicate
Thumb code regions.
Global variable symbols (STT_OBJECT) are included when a map file is
available, carrying the variable's absolute address and byte size.
When --sym-prefix is used, all symbol names (procedures, globals,
main, startup) are prefixed with the given string and an underscore.
Examples
Minimal ELF for loading only (no gen-rdb needed):
make-elf SignalSync.bin
Minimal ELF with RP2350 IMAGE_DEF for standalone boot:
make-elf SignalSync.bin --image-def
Build with symbols (requires gen-rdb):
make-elf SignalSync.bin --symbols
Build with full debug data:
make-elf SignalSync.bin --debug
Build with explicit addresses:
make-elf SignalSync.bin:0C000000 --debug --bss 20000000:20030000
Build with RP2350 IMAGE_DEF and debug data:
make-elf SignalSync.bin:10000100 --debug --image-def
Build a debug-only ELF (no loadable sections):
make-elf --entry 10000100 --rdb-dir rdb
Build a Secure ELF with symbol prefix for dual-image TrustZone debugging:
make-elf S.bin:0C000000 NSC.bin:C0FE000 --debug --rdb-dir sec/rdb --sym-prefix S
Build a Non-secure ELF for the same debug session:
make-elf NS.bin:08100000 --debug --rdb-dir nonsec/rdb --sym-prefix NS
Minimal S/NS ELFs for loading without debugging:
make-elf S.bin:0C000000 NSC.bin:C0FE000
make-elf NS.bin
Environment
make-elf has no environment variable dependencies. All paths and options are supplied via the command line.
Diagnostics
The tool exits with status 0 on success and status 1 on any error. Common error conditions include:
- binary file not found
- invalid hexadecimal address
- load address exceeds 32-bit range
- malformed file:address specification
- missing listing directory when --symbols or --debug is requested
- --image-def used without any binary file
- --bss end address not greater than start address
With -v, the tool prints section names, symbol counts, entry addresses, and other details to standard output.
Compatibility
The generated ELF files have been verified with:
- GDB (arm-none-eabi-gdb) – loading, breakpoints, source-level debugging
- OpenOCD – flash programming via GDB
loadcommand - JLink GDB Server – flash programming and debugging
Developed and tested with Astrobe for RP2350 version 10. Other Astrobe versions may produce listing and map files with different formats.
Listing Files
The absolute assembly listing files (.alst by default) are produced by
gen-rdb from the Astrobe compiler and linker output, and placed in the
rdb directory. Each file corresponds to one Oberon module and contains
interleaved source lines and ARM assembly with hex addresses. The
companion library elfdata parses these files to extract procedure
boundaries, local variables, types, and line-number mappings.
An optional arm-attr.cfg file in the listing directory supplies ARM
build attribute values for the .ARM.attributes section.
Notes
The --image-def option is specific to the Raspberry Pi RP2350 (Cortex-M33, dual-core). The metadata block follows the format documented in the RP2350 datasheet. The block declares a Secure, ARM, executable image and points the boot ROM to the program's vector table.
The .bss section contains no file data. Its purpose is to inform the
debugger of the RAM address range so that it may read variable values from
the target. Without this section, some debuggers cannot resolve global
variable addresses.
Symbol names use an underscore-separated form (Module_Procedure) in the
ELF symbol table. This convention avoids ambiguity with C structure member
access in debugger expression evaluators, whilst remaining readable.
Nested procedures (a procedure declared inside another procedure) are not supported. The Oberon language permits this, but the debug data extraction does not currently handle the scoping correctly, and the outer procedure's debug data may be incomplete or incorrect.
See Also
gen-rdb, elfdata, arm-none-eabi-objdump, arm-none-eabi-readelf, openocd
Last updated: 18 April 2026