Hunk Object and Link-Library Format

An object file is the intermediate output of a compiler or assembler: one per translation unit, with unresolved external references left intact. A link library is a collection of object files used by a linker to resolve those references; functions from a link library are copied into the final executable at link time (unlike AmigaOS run-time libraries, which stay on disk and are shared via OpenLibrary()).

Both use a subset of the executable Hunk format with extensions:

  • HUNK_UNIT to delimit translation units.
  • HUNK_RELOC16 / HUNK_RELOC8 for short PC-relative relocations (object files only).
  • HUNK_DRELOC32/16/8 for base-register-relative relocations into __MERGED segments.
  • HUNK_EXT for external symbol definitions and references.
  • HUNK_LIB / HUNK_INDEX for indexed link libraries.

Object files have no HUNK_HEADER. Memory attributes are encoded in the top two bits of each hunk type instead. The bit combinations 00/01/10 correspond to MEMF_ANY/MEMF_CHIP/MEMF_FAST. The combination 11 is undocumented; the manual recommends using it as an extension hook for an explicit memory type in the next long-word, mirroring HUNK_HEADER's layout.

Object file layout

[ HUNK_UNIT ]                                — translation-unit header (name in long-words)

[ HUNK_NAME ]   optional
  2 bits  mt                                  — memory type
  30 bits h                                 — hunk type
  [HUNK_CODE | HUNK_DATA | HUNK_BSS]        — segment body, depending on `h`
  do {
     [HUNK_RELOC32 | RELOC16 | RELOC8
      | RELOC32SHORT | RELRELOC32
      | DRELOC32 | DRELOC16 | DRELOC8
      | EXT | SYMBOL | DEBUG]
     …until HUNK_END
  }
  repeat until EOF

HUNK_UNIT — translation-unit identifier

struct {
    LONG hn_longs;       /* length of name, in long-words */
    LONG hn_name[hn];    /* the name, zero-padded to long-word boundary */
};

The name is typically the source file name; most linkers ignore it. Required as the first hunk of every object file. Not present in libraries or executables.

HUNK_NAME — segment naming

In object and library files, segment names drive the merging logic of the linker. Two segments with identical names (across object files and library members) are merged into one segment in the final executable. Special names:

Name Effect
__MERGED Segment addressed via a base register (small-data model). Compiler uses one address register (usually a4) loaded to the segment base, with 32K offset to allow ±32K addressing.
_NOMERGE Never merged with anything, regardless of small/large model.
NTRYHUNK Becomes the first segment of the final executable — required for the overlay manager, which must run first.
text Conventional name for code+constant data.
data Conventional name for non-constant data in the large data model.
udata Conventional name for BSS in the large data model.
chip Conventional name for MEMF_CHIP data.

The memory type is not implied by the name — mt in the hunk type header remains the source of truth.

HUNK_RELOC16 / HUNK_RELOC8

Both follow the same format as HUNK_RELRELOC32 (32-bit offsets, but pointing at 16- or 8-bit elements). They are used for short PC-relative branches in object files; the loader itself does not handle them, only the linker does. For the linker to resolve them, the referencing and target segments must be merged (identical HUNK_NAME).

If the merged segment still exceeds the displacement range, linkers may emit an automatic link vector (ALV) — a small intermediate stub that performs an absolute jump. ALVs work for code jumps but not for PC-relative data accesses. Avoid 16- or 8-bit references to data across translation units.

HUNK_DRELOC32 / HUNK_DRELOC16 / HUNK_DRELOC8

Same wire format as HUNK_RELOC32. Operands are 32-, 16-, or 8-bit displacements relative to a base register (typically a4) at the segment base of __MERGED. Used when the small-data model moves static data through a base register.

The 68K's 16-bit base-relative addressing mode limits __MERGED to 64K total. Linkers handle the 32K boundary by adjusting the base register 32K into the segment and applying a -32K offset to all r0 entries.

HUNK_EXT — external symbol definitions and references

This hunk is what makes an object file unresolved. It carries both definitions (symbols this unit provides) and references (symbols this unit needs from elsewhere).

struct {
    BYTE   st;       /* symbol type, see table below */
    UBYTE  sl;       /* length of name in long-words (24 bits!) */
    LONG   sn[sl];   /* name, zero-padded to long-word boundary */
    /* For definitions (st < 0x80): one LONG sv (symbol value) */
    /* For common references (st == 0x82 or 0x89): one LONG sc (size of common block in bytes) */
    /* For other references: one LONG sn (number of references), then so[] (offsets into segment) */
} [];

The array terminates when an entry has sl == 0.

Symbol types

Bit 7 of st selects definitions (clear) or references (set):

st Class Meaning
EXT_SYMB 0x00 Definition sv + ma[i] is the address of the symbol. (HUNK_SYMBOL-style debug info only.)
EXT_DEF 0x01 Definition sv + ma[i] is the address; references become HUNK_RELOC32 to segment i.
EXT_ABS 0x02 Definition sv is the absolute value, substituted into references verbatim.
EXT_RES 0x03 Definition Obsolete (dynamic-library runtime binding).
EXT_REF32 0x81 Reference 32-bit, resolved by EXT_DEF or EXT_ABS.
EXT_COMMON 0x82 Reference Like EXT_REF32, but if no definition is found the linker allocates BSS space for the largest referenced size. (FORTRAN common blocks; SAS/C header-include guard pattern.)
EXT_REF16 0x83 Reference 16-bit PC-relative; target segment must be merged.
EXT_REF8 0x84 Reference 8-bit PC-relative; same segment.
EXT_DREF32/16/8 0x85–0x87 Reference Base-register-relative references to __MERGED.
EXT_RELREF32 0x88 Reference 32-bit PC-relative; generates a HUNK_RELRELOC32.
EXT_RELCOMMON 0x89 Reference Like EXT_COMMON, but emits a HUNK_RELRELOC32.
EXT_ABSREF16/8 0x8a/0x8b Reference 16/8-bit absolute value.

Link libraries come in two forms:

Non-indexed (old style)

A simple concatenation of object files. Join is sufficient to produce one. Slow: the linker must scan the whole file to find a single symbol.

Indexed

[ HUNK_LIB ]  payload of compiled object units
[ HUNK_INDEX ]  compressed symbol/hunk index
… (repeat)

The pair is bounded by <2^16 long-words of payload. Larger libraries use multiple HUNK_LIB / HUNK_INDEX pairs.

HUNK_LIB

Carries the actual code/data hunks. Differences from a plain object file:

  • No HUNK_UNIT (the unit name lives in HUNK_INDEX).
  • No HUNK_NAME (the segment name lives in HUNK_INDEX).
  • No EXT_DEF, EXT_ABS, or other definitions (the symbol table lives in HUNK_INDEX). References — st ≥ 0x80 — are retained.

Memory type mt is encoded the same way as in object files (top two bits of the hunk type).

HUNK_INDEX

struct {
    /* String table */
    UWORD  sl;          /* byte length of string table (must be even) */
    UBYTE  strings[sl]; /* NUL-terminated C strings, the first being "" */
    /* Per-unit entries, until end-of-hunk sentinel */
    UWORD  uo;          /* byte offset of unit name into string table */
    UWORD  ho;          /* long-word offset of first hunk of unit within HUNK_LIB */
    UWORD  hc;          /* number of segments in unit */
    for (each segment) {
        UWORD  hn;      /* byte offset of hunk name */
        UWORD  hl;      /* abbreviated hunk size, in long-words */
        UBYTE  mt:2;    /* memory type */
        UWORD  h:14;    /* abbreviated hunk type */
        UWORD  xc;      /* number of references */
        for (each reference) {
            UWORD xn;   /* byte offset of reference name */
        }
        UWORD  dc;      /* number of definitions */
        for (each definition) {
            UWORD  dn;  /* byte offset of defined name */
            WORD   sv;  /* low 16 bits of symbol value */
            UBYTE  au;  /* bits 23..16 of EXT_ABS value */
            bit    0;   /* always 0 (definition marker) */
            bit    as;  /* sign bit + bits 30..24 of EXT_ABS value */
            UBYTE  st:6;/* low 6 bits of EXT type (always definition: bit 7 = 0) */
        }
    }
};

Limitations of the indexed format:

  • Address symbols are restricted to 16 bits within a hunk (64K max) — fine for service functions, restrictive for low-level code.
  • EXT_ABS symbol values fit in 32 bits (-2^24 + 1 to 2^24 - 1) — enough for Amiga custom-chip register addresses.
  • EXT_COMMON and EXT_RELCOMMON cannot be represented.
  • Reference types (the st byte) are not in the index; they remain in the corresponding HUNK_EXT of HUNK_LIB.

The string table is the deduplicated union of all unit names, segment names, reference names, and definition names. The first entry must be the empty string (offset 0), enabling unnamed hunks.

See Also


Sources: Thomas Richter, "ROM Kernel Reference Manual: AmigaDOS" (First Edition, 2024), Chapter 11.6–11.7 — Object File Format and Link Library File Format; Ralph Babel, "The Amiga Guru Book" (1993), Chapter 22. Raw: raw/rkm/rkm-dos-book.md; raw/rkm/guru-book.md Updated: 2026-10-02