Reference

Output formats

The dialect tour covers every assembler syntax rg-asm can read. This page covers what it can write: GEMDOS executables, linkable objects for classic and modern toolchains, Motorola DSP56001 binaries and loaders, raw flat images, and the symbol tables embedded in a .PRG.

Output Kinds

Everything rg-asm emits is one of four kinds, selected by CLI flags. The difference is who resolves addresses:

KindFlagDefault nameRelocations resolved by
Executable --prg (default) <input>.PRG GEMDOS loader (PEXEC relocation table)
Object --obj[=KIND] <input>.o The linker (rg-asm built-in or rg-link / vlink)
Raw --raw <input>.BIN None (bytes must already be final)
DSP Co-processor --format=FMT <input>.lod / .p56 / .dsp Falcon XBIOS, DSP memory loader, or host 68030 feeder

Atari-bound artifacts use UPPERCASE extensions (.PRG, .BIN); objects stay lowercase .o because they are host toolchain intermediates. An explicit -o path is honoured verbatim: GAME.TOS, DESK.ACC, and TOOL.TTP are the same GEMDOS container; only the desktop launch hint differs.

GEMDOS Executables

The Atari ST executable format, also used for .APP, .GTP, .ACC, and .TTP. All multi-byte fields are big-endian. The file begins with magic $601A, literally a bra.s over the header, which a debugger can step over.

28-byte header

OffsetSizeFieldNotes
0x00wordmagic$601A
0x02longtext sizebytes of code segment in file
0x06longdata sizebytes of initialised data in file
0x0AlongBSS sizeuninitialised RAM (not stored in file)
0x0Elongsymbol table size0 when stripped (--strip)
0x12longreserved0 (Pure C expects this)
0x16longflagsGEMDOS PRGFLAGS (see below)
0x1Awordabsflag0 = relocation table follows; non-zero = no relocs

Header flags (--prg-flags)

The flags longword at offset 0x16 controls load behaviour. Memory protection tokens share bits 4-7; pick one mode for --prg-flags.

CLI tokenBitEffect
fastload0Clear BSS only on load, not the whole heap
fastram1May load into TT-RAM
fastalloc2Malloc may use TT-RAM
private
global
super
readable
4-7 Private memory protection (mode 0)
Global memory protection (mode 1)
Supervisor memory protection (mode 2)
Readable memory protection (mode 3)

File layout

RegionPresenceNotes
Header Always 28 bytes; segment sizes and flags (see tables above).
Text segment Always Code; length from header text size.
Data segment Always Initialised data; length from header data size. BSS follows at load time only.
Symbol table Optional Embedded debug symbols; omitted with --strip or when header symbol size is 0.
Relocation table Conditional Present when absflag is 0; GEMDOS fixup stream (see below).

Relocation table

When absflag is 0, GEMDOS loads the program at an arbitrary base and patches absolute longwords in the combined text+data image using a compact byte stream appended after the optional symbol table. The table starts with a longword offset to the first fixup site; 0 means no relocations. Fixup offsets must be even (68000 alignment).

Table byteAction
$00End of relocation table.
$01Advance the fixup offset by 254 bytes without patching (long gap).
$02…$FE (even)Advance the fixup offset by this many bytes, then add the load base to the longword at that offset in the image.

Loader pseudocode

// image: text || data loaded at `base`; rt points at the relocation table in the file
offset = be32_read(rt)
if offset == 0: return

p = rt + 4
loop:
    b = u8_read(p++)
    if b == 0: break
    if b == 1:
        offset += 254
        continue
    offset += b
    u32_at(base + offset) += base

The long-gap byte is $01, not $FE; $FE (254) is a valid even step that also performs a patch. rg-link and rg-asm emit absflag 0 with a full table (TurboAss / GEMDOS style). GenST 1.01 uses absflag $FFFF and a single trailer $00 instead.

Symbol tables (DRI, GST, extern)

Executables can carry an embedded symbol table for debuggers and profilers, controlled by --sym=KIND (default gst). Use --strip to omit it entirely.

--symFormatWhere it livesTypical consumer
dri DRI (8-char names) Embedded in .PRG Classic Atari debuggers, Hatari (limited)
gst GST (DRI + long-name continuations) Embedded in .PRG Devpac/HiSoft profilers, extended debuggers
extern Plain text (ADDR t name, nm-style) Sidecar .sym file Hatari, godbox source-level debug

Provenance: DRI and GST symbol tables come from the Digital Research GEMDOS / CP/M-68K toolchain; GST extended them for names longer than 8 characters (Devpac/HiSoft). Hatari and godbox are consumers, not authors, of these formats.

DRI symbols use 14-byte records (8-char name + type word + value). GST adds continuation records for long names. The embedded table is separate from linkable object formats: it lives inside the finished executable, not in a .o file.

Linkable objects (--obj=KIND)

--obj emits one relocatable object per source file. The KIND selects which linker ecosystem the object targets. rg-asm's built-in linker and rg-link ingest ELF natively and transcode GST, a.out, Pure C, and DRI objects to ELF at read time, so mixed links work through one pipeline.

KINDMagic / markerTypical consumerNotes
elf (default) ELF vlink, vbcc, gcc-binutils ELF32 big-endian m68k; modern toolchain path
gst $FB directive stream Devpac, HiSoft, GenST linkers Classic Atari .O; vasm -Fgst oracle
dri $601A + 28-byte header Alcyon / DR AS68, RMAC family Word-parallel reloc bitmap; 8-char DRI symbols
purec (pc) $4EFA Pure C, Lattice C, AHCC (PLINK / AHCL) Atari "group 1" object; AHCL-validated emit
aout $0107 (OMAGIC) MiNT, BSD a.out toolchains Round-trip oracle via vlink -baoutmint
lout (mwc) $0107 LE Mark Williams C as Coherent-family l.out; minimal emit
seka $A001 framing Andelos / K-Seka Framed linkable (A0 01 …)
hunk (amiga) HUNK_* Lattice Amiga Amiga hunk format, not GST

ELF32 m68k

Default object format. Sections (.text, .data, .bss) carry standard ELF relocations (R_68K_32, PC-relative variants, etc.). This is the format vbcc and gcc emit when targeting vlink, and what rg-asm's linker consumes directly.

GST object

A flat byte stream of directives. Any byte that is not part of a directive is literal section data. Directives begin with escape byte $FB; a literal $FB in data is written as $FB $FB.

DirectiveLayoutMeaning
FB 01len.b name[len]Source file name (debug)
FB 04id.wSelect current section
FB 06len.b name[len] value.l secid.wDefined symbol (export)
FB 07addend.l size.b flag.b target.wRelocated field
FB 10id.w len.b name[len]Section (negative id) or external xref (positive id)
FB 13(none)End of object

Library archives use magic $FB01 (GMAGIC) with GST members inside. vlink does not read GST objects. Correctness is verified by byte-matching vasm -Fgst output.

DRI / Alcyon object

Shares the executable magic $601A but is disambiguated by layout: a 28-byte header (same field order as PRG) followed by text, data, a symbol table, and a word-parallel relocation bitmap with one 16-bit slot per image word.

Reloc slotMeaning
$0000No relocation at this word
$0001 / $0002Low word, internal reference (GenST vs vasm differ)
$0005High word of a 32-bit absolute relocation
n×8+4Low word, external reference to symbol n

DRI library archives use magic $FF65 (DLMAGIC). Emitted with --obj=dri; pair with --dialect=alcyon or RMAC-family dialects.

Pure C object (group 1)

The object format shared by Pure C, Lattice C, and AHCC. It is mutually incompatible with gcc/vbcc ELF at the object level, but interoperable among group-1 tools. Magic $4EFA (PMAGIC); the second word is fixed at $001C (PPMAGIC). All fields are big-endian.

32-byte header

OffsetSizeFieldNotes
0x00wordmagic$4EFA (PMAGIC)
0x02wordhe$001C (PPMAGIC), always this value
0x04longlimageImage length (text + data concatenated)
0x08longlfixupFixup stream length in bytes
0x0ClonglnamesNames section length
0x10longlsymSymbol section length (0 in plain objects)
0x14longres1Reserved (0)
0x18longres2Reserved (0)
0x1ClonghekpReserved (0)

File layout

RegionSizeNotes
Header 32 bytes PC_H fields above.
Image limage Text then data, back-to-back; no per-segment headers. BSS has no file bytes.
Fixup stream lfixup Sequence of 4-byte FIX records (see below); positional walk over the image.
Names lnames Length-prefixed Pascal strings; index 0…n referenced by fixups.
Symbols lsym Optional debug symbols; usually 0 in assembler objects.

Fixup record (FIX, 4 bytes)

OffsetSizeFieldNotes
+0bytetyFixup type (FIX_text, FIX_labs, …)
+1byteskSkip: byte delta from previous record's position to this one
+2wordnnrName index into the names section, or -1 if none
tyNameMeaning
1FIX_endEnd of fixup stream
2FIX_stepLarge position advance (24-bit × 256)
3FIX_textStart of TEXT segment
4FIX_dataStart of DATA segment
5FIX_bssStart of BSS segment
7FIX_glmodGlobal module (exported) start
9FIX_lcmodLocal module start
11FIX_labs32-bit absolute relocation at current position
12FIX_wabs16-bit absolute relocation
13FIX_lpcrel32-bit PC-relative relocation
14FIX_wpcrel16-bit PC-relative relocation
17FIX_wbraWord branch (PC-relative)
18FIX_sbraShort branch (PC-relative)

rg-asm emits Pure C objects (--obj=purec) validated by AHCC's real AHCL.TTP linker under emulation. It reads both Pure C ($4EFA) and DRI ($601A) inputs when linking.

BSD / MiNT a.out

Classic Unix a.out relocatable (OMAGIC $0107, big-endian on Atari). Same broad shape as many host toolchains: fixed exec header, segment blobs, relocation records, then symbol and string tables. Oracle-validated through vlink -baoutmint round-trips with vasm -Faout.

Exec header (32 bytes)

OffsetSizeFieldNotes
0x00longa_info$00010107 (OMAGIC in low word)
0x04longa_textText segment size
0x08longa_dataData segment size
0x0Clonga_bssBSS size (not stored in file)
0x10longa_symsSymbol table size (12 × n symbols)
0x14longa_entryEntry point (0 for objects)
0x18longa_trsizeText relocation size (8 × n)
0x1Clonga_drsizeData relocation size (8 × n)

File layout

RegionSizeNotes
Exec header32 bytesEight big-endian longwords (above).
Texta_textCode segment.
Dataa_dataInitialised data.
Text relocationsa_trsize8 × n byte records for text fixups.
Data relocationsa_drsize8 × n byte records for data fixups.
Symbol tablea_symsnlist entries, 12 bytes each.
String tablevariableLeading u32 length + NUL-terminated names.

Relocation record (8 bytes)

OffsetFieldNotes
+0r_addressOffset of the field within its segment
+4r_infoSymbol/segment index in bits 31-8; flags in low byte (pcrel, length, extern)

Section-relative fields hold seg_base + addend; external fields hold the addend alone.

MiNT a.out executables (GEMDOS-wrapped) are a separate follow-up; the modern MiNT/GNU path already consumes ELF from rg-asm.

Heritage and niche objects

l.out, Seka, and Amiga hunk sit outside the main GST / DRI / Pure C / a.out line. They do not share one on-disk layout: a.out and l.out are header+segment cousins; Seka is a framed byte stream; hunk is a tagged longword sequence. The matrix below is an at-a-glance map; each format has its own detail section.

Aspect a.out l.out Seka hunk
Magic / marker $0107 OMAGIC (BE) $0107 (LE) $A001 frame words HUNK_* tags
Header 32-byte exec header 48-byte Coherent header None (inline framing) HUNK_UNIT … HUNK_END
Segments text, data, bss (implied) text, data (minimal emit) TEXT frame, optional DATA frame CODE / DATA / BSS hunks
Relocations 8-byte records per segment Not emitted yet A1 02 inline tags Not emitted yet
Symbols nlist + string table Not emitted yet A3 GLOBL records In hunk stream (Lattice)
rg-asm emit Full Text/data only TEXT/DATA + relocs TEXT (+DATA/BSS basic)

l.out (Mark Williams C)

Coherent-family relocatable used by MWC as (--obj=lout). Shares the $0107 magic with a.out but is little-endian and uses a 48-byte header. rg-asm currently emits text (+ optional data) only; symbol and relocation tables are still growing.

RegionNotes
Header Magic $0107 (LE) at 0x00; text size at +0x0A (or +0x0E after .prvi layout directives).
Text Code bytes immediately after the header.
Data Optional initialised data following text.

Seka (Andelos / K-Seka)

Framed linkable for K-Seka (--obj=seka). No fixed header: the file is a byte stream of 16-bit frame words and payload. Words in the $A000…$AFFF range are escaped so they cannot be mistaken for control tags.

PhaseNotes
ExportsOptional A3 GLOBL symbol records before the TEXT frame.
TEXTOpened with A0 01, payload (with inline relocs), closed with A0 01.
DATAIf non-empty, wrapped in A0 02 … A0 02.
TagLayoutMeaning
A0 00wordEscape: literal payload word in $A000…$AFFF
A0 01(none)TEXT section open / close frame
A0 02(none)DATA section open / close frame
A1 02zero.lAbsolute relocation site (placeholder patched at link time)
A3name…Exported GLOBL symbol

Amiga hunk (Lattice)

Lattice Amiga object format (--obj=hunk), not GST despite the shared vendor. A sequence of big-endian longword tags and payloads; minimal emit is HUNK_UNIT → named CODE (or DATA/BSS) → HUNK_END.

TagNameMeaning
$03E7HUNK_UNITStart translation unit (+ name)
$03E8HUNK_NAMEName the following hunk
$03E9HUNK_CODEInitialised executable bytes (longword-padded)
$03EAHUNK_DATAInitialised data
$03EBHUNK_BSSBSS size (longwords, no bytes)
$03F2HUNK_ENDEnd of hunk block

Raw .BIN

--raw writes a flat memory image: no header, no symbol table, no relocation records. Addresses must be final at assembly time. Use PC-relative code or ORG for absolute placement. ORG is honoured for raw output and ignored for --prg and --obj.

Raw output enforces two constraints: one effective section (sections are concatenated into a single buffer) and no undefined symbols (nothing left for a linker to resolve). The boot-sector idiom text / org $600 / … is the classic use case.

Motorola DSP56001 Formats (--format=FMT)

When assembling Motorola DSP56001 code (invoked via --cpu=56001, DSP source extensions like .s56 or .asm56, or in-file .56001 blocks), rg-asm can target seven distinct output representations. These range from classic text loaders for Atari Falcon XBIOS to high-speed binary containers, industry-standard Motorola COFF, and embeddable host C/ASM tables.

Format CLI Flag Default Ext Word Layout Primary Consumer & Use Case
Motorola .LOD --format=lod .lod ASCII hex (24-bit) Atari Falcon XBIOS Dsp_ExecProg, Hatari, Motorola debuggers (default).
Brainstorm .P56 --format=p56 .p56 Packed binary (3 bytes/word) Atari demoscene multi-segment loader; zero gap overhead between P/X/Y runs.
GODLIB .DSP --format=dsp .dsp Unpacked binary (4 bytes/word) sDspBinary container; 32-bit longwords for unrolled 68030 host port blasting.
Raw Flat .BIN --format=bin / --raw .bin Packed (3B) or unpacked (4B) Direct memory images, EEPROMs, or custom Falcon DMA buffers.
a56 .OUT --format=out .out ASCII per-word + symbols Quinn Jensen a56 compatibility and legacy DSPMAKE pipelines.
Motorola COFF --format=cld / --format=cln .cld / .cln COFF binary (3 bytes/word) Motorola DSP suite (dsplnk, sim56, cldlod); absolute or relocatable.
Embeddable C --format=c / --format=c.3 .c C source arrays Static arrays (uint32_t or uint8_t) compiled directly into host programs.
Embeddable ASM --format=inc / --format=asm.3 .inc 680x0 dc.l / dc.b Host 68k assembly tables ready for direct include.

Motorola .LOD (--format=lod)

The canonical ASCII format developed by Motorola and the default output for standalone DSP assembly. .LOD files are human-readable, streamable text files directly accepted by the Atari Falcon operating system through the XBIOS call Dsp_ExecProg (Opcode 96) as well as emulators and system monitors.

An rg-asm .LOD file consists of four record varieties:

RecordSyntaxDescription
_START _START <symbol> <hex_addr> Defines the entry point address in P-memory (e.g. _START Start 0040). If no entry symbol is found, defaults to _START MAIN.
_DATA _DATA <space> <start_addr> Declares the start of a contiguous run in space P, X, or Y at a 4-hex-digit word address, followed by lines of up to 8 space-separated 6-hex-digit (24-bit) words.
_BLOCKDATA _BLOCKDATA <space> <addr> <count> Emitted for block-fill directives (e.g. bsc). Specifies target space, start address, repetition count, followed by the single 6-digit hex fill word on the next line.
_END _END Marks the end of the loader stream.

Entry points can be set explicitly via --entry-symbol=<NAME>, or inferred automatically from standard symbols (Start, Entry, or Init). Starting addresses can be overridden from the command line using --org-p=<HEX>, --org-x=<HEX>, and --org-y=<HEX>.

Brainstorm .P56 (--format=p56)

Pioneered by the Brainstorm demogroup, .P56 is a compact multi-segment binary format widely used across the Atari Falcon 030 demoscene. Unlike flat binaries, .P56 can represent disjoint allocations in program memory and X/Y data memory without filling the intervening address gaps with zeros.

A .P56 file has no monolithic file header. Instead, it is a sequential stream of binary segments:

FieldSizeNotes
space 3 bytes (BE) Address space identifier: 0 = P memory, 1 = X memory, 2 = Y memory.
start_addr 3 bytes (BE) Destination start word address in the target memory space.
count 3 bytes (BE) Number of 24-bit words ($N$) in this segment.
data $N \times 3$ bytes Packed big-endian 24-bit words ([High, Mid, Low]) streamed without padding.

Host upload routines can parse each 9-byte header, configure the DSP base address register, and stream the $N$ words into the DSP host interface register.

GODLIB .DSP (sDspBinary)

The structured binary format used by the Reservoir Gods GODLIB library runtime. While .P56 prioritises minimum disk size, .DSP is architected around host transfer throughput on the 16 MHz MC68030 bus.

Each 24-bit DSP word is stored in a 4-byte big-endian slot: 0x00, High, Mid, Low. Because the most significant byte is zero, the Falcon 68030 host CPU can blast longwords directly from ST-RAM into the DSP Host Interface data register ($FFFFA204) using an unrolled move.l (a0)+,(a1) loop with zero shifting, masking, or byte-packing overhead.

sDspBinary 28-byte Header

OffsetTypeFieldDescription
0x00u32mpCodeFile offset to P-memory image (typically 28 if P is present, else 0)
0x04u32mpXInitFile offset to X-memory image (or 0 if empty)
0x08u32mpYInitFile offset to Y-memory image (or 0 if empty)
0x0Cu32mCodeBytesP-memory byte count ($N_P \times 4$ bytes)
0x10u32mXInitBytesX-memory byte count ($N_X \times 4$ bytes)
0x14u32mYInitBytesY-memory byte count ($N_Y \times 4$ bytes)
0x18u16mEntryWordWord offset of the entry point relative to P start
0x1Au8mAbilityGODLIB cooperative job slot / ability ID tag
0x1Bu8mFlagsRuntime flags (reserved, defaults to 0)

Flat .BIN & a56 .OUT

Raw Flat Binary (--format=bin)

--format=bin (or --raw with a DSP target) produces a pure memory dump containing only instruction words with no headers, metadata, or segment framing. Contiguous runs are output in ascending address order. By default, words are written in packed 24-bit big-endian format (3 bytes per word). When combined with --unpacked, each word is padded to 4 bytes with a leading zero byte.

Quinn Jensen a56 (--format=out)

Emits the ASCII word-by-word representation produced by Quinn Jensen's legacy a56 assembler. Each word is printed on its own line as <space> <addr:04X> <word:06X>. The file concludes with a deterministic symbol trailer sorted alphabetically by symbol name:

P 0040 0A7004
P 0041 00FFE8
I 000040 Start
F 400000 VolumeHalf

Integer equates and labels are prefixed with I, while fractional constants are marked with F.

Motorola DSP COFF (.CLD & .CLN)

rg-asm implements full emit support for the Motorola Common Object File Format (COFF) standard (magic 0x01E0) used by Motorola's official DSP56000 toolsuite (including dsplnk, the sim56 simulator, and cldlod).

Embeddable C & ASM Tables

For projects where DSP kernels are linked directly into the host executable rather than loaded from disk as external files, rg-asm can transpile assembled DSP code into embeddable C headers and 680x0 assembly tables.

C Header Arrays

Selected via --format=c (or --format=c.4 for 32-bit unpacked, --format=c.3 for 24-bit packed bytes). Generates a complete C compilation unit with size constants:

/* Generated by rg-asm */
#include <stdint.h>
#include <stddef.h>

const uint32_t dsp_code[] = {
    0x000A7004, 0x0000FFE8, 0x00200000
};

const size_t dsp_code_len = sizeof(dsp_code) / sizeof(dsp_code[0]);

680x0 Assembly Include Tables

Selected via --format=inc (or --format=asm.4 for 32-bit dc.l, --format=asm.3 for 24-bit dc.b). Outputs structured assembly data with alignment and extent markers:

; Generated by rg-asm
    even
dsp_code:
    dc.l    $000A7004,$0000FFE8,$00200000
dsp_code_End:
    even

The symbol name (default dsp_code) is customized with --entry-symbol=<NAME>.

In-File Mixed-Mode Wire Formats

Instead of maintaining separate .s and .s56 source files, rg-asm allows writing 680x0 host routines and DSP56001 microkernels within the same source file. Target switching is achieved via RMAC-style directives:

; --- 68030 host code ---
    move.w  #$2700,sr
    bsr     UploadDspKernel

; --- Inline DSP56001 kernel ---
    .56001  unpacked
    org     p:$40
Start:
    movep   #0,x:<<$FFFE    ; disable BCR bus wait states
    rts
    .68030

; --- 68030 resumes ---
UploadDspKernel:
    lea     Start,a0
    ; ... upload loop ...

Wire Modifiers

The opening directive (.56001, pushcpu 56001, or cpu 56001) accepts modifiers controlling how the sub-assembled DSP binary is placed into the host 68k section:

ModifierLayoutDescription
unpacked 4 bytes / word (dc.l) Default. Words are emitted as $00xxxxxx longwords for fast 32-bit host-port transfer.
packed 3 bytes / word (dc.b) Words are packed tightly as 3 raw bytes ($xx,$xx,$xx) to minimize host binary footprint.
bootstrap Header + 4B words Automatically prepends Falcon host bootstrap preamble (word count + P-memory load address) before the unpacked words.
noeven (none) Suppresses the trailing even alignment directive that is otherwise automatically emitted after the DSP payload.
org=p:$addr Address Explicitly sets the DSP memory origin if not defined by an internal org directive.

To return to host code, use .68000, .68030, popcpu, or cpu 68000. Host 68k equates are seamlessly available inside the DSP block, and DSP labels and equates are automatically exported back to the host 68k symbol table.


For every CLI flag, worked examples, and JSON machine output, see the full documentation. For input syntax history, see the dialect tour.