Oberon RTK

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):

  1. compile and link with Astrobe (IDE or command line)
  2. gen-rdb SignalSync.map
  3. make-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 (if arm-attr.cfg is present). Implies --symbols. Requires listing files in the rdb directory (see --rdb-dir).
--symbols
Include procedure and variable symbols extracted from listing files in the rdb directory (produced by gen-rdb). Also includes ARM mapping symbols ($t). Without --symbols or --debug, the ELF contains only main/startup symbols and no listing files are needed.
--sym-prefix prefix  /  --sym-prefix=prefix
Prefix all symbol names with prefix_. In the symbol table, SignalSync_Run becomes S_SignalSync_Run; in DWARF DW_AT_name, SignalSync.Run becomes S_SignalSync.Run. The main and startup symbols 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 rdb directory produced by gen-rdb). Default: rdb. Only consulted when --symbols or --debug is set. The directory is also searched for arm-attr.cfg, used to generate the .ARM.attributes section. 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/rdb sets comp_dir to s so that GDB resolves source files as s/rdb/Module.alst. For the default --rdb-dir rdb, comp_dir is . (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 as SHT_NOBITS with a matching PT_LOAD program header; no bytes are added to the file. This allows the debugger to read variables from RAM. The addresses typically correspond to DataStart and DataEnd in the Astrobe linker configuration. If omitted and a .map file is available, the BSS range is auto-detected from the Data Range line in the .map file. Currently, only one .bss range 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>.map in the same directory as the first binary.
--entry addr  /  --entry=addr
Set the ELF entry address and main/startup symbol 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 main and startup symbols 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 .bin with .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_line section 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:

  1. ELF header – 32-bit, little-endian, ET_EXEC, EM_ARM.

  2. Program headers – One PT_LOAD per binary file (readable, executable), one for .bss (readable, writable, NOBITS), and one for .image_def (readable) if applicable.

  3. Section headers and sections

    Section Type Description
    .shstrtab SHT_STRTAB Section name strings
    .image_def SHT_PROGBITS RP2350 picobin metadata (optional)
    .text SHT_PROGBITS First binary image
    .bss SHT_NOBITS Uninitialised data region (optional)
    .debug_line SHT_PROGBITS DWARF line-number program
    .debug_info SHT_PROGBITS DWARF compilation unit and types
    .debug_abbrev SHT_PROGBITS DWARF abbreviation table
    .debug_aranges SHT_PROGBITS DWARF address ranges
    .debug_pubnames SHT_PROGBITS DWARF public names
    .debug_str SHT_PROGBITS DWARF string pool
    .debug_frame SHT_PROGBITS DWARF call-frame information
    .ARM.attributes SHT_ARM_ATTRIBUTES ARM build attributes
    .strtab SHT_STRTAB Symbol name strings
    .symtab SHT_SYMTAB Symbol table

    Debug sections (.debug_* and .ARM.attributes) are present only when --debug is active. Procedure and variable symbols in .symtab require --symbols or --debug; without either, the symbol table contains only main and startup.

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 load command
  • 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