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, raw flat images, and the symbol tables embedded in a .PRG.

Output Kinds

Everything rg-asm emits is one of three kinds, selected by a mutually exclusive flag. 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)

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_UNITHUNK_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 02A0 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.


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