Skip to content

โ† Home ยท Linking & Libraries

AmigaLib Static Linking

Overview

AmigaOS programs are linked against a set of static libraries that provide startup code, C runtime stubs, and glue for OS entry points. The linker resolves all external symbols at link time and produces a self-contained HUNK-format executable.


Key Static Libraries (NDK39 / SAS/C)

Library Purpose
amiga.lib OS stub functions โ€” OpenLibrary, AllocMem, etc. for non-inline linking
sc.lib / c.lib SAS/C runtime: printf, malloc, strlen, standard I/O
auto.lib Auto-open libraries (DOSBase, SysBase acquisition)
debug.lib kprintf, dprintf serial debugging stubs
m.lib Math library (software floating point)
scm68020.lib SAS/C math for 68020 (co-processor stubs)

For GCC: | Library | Purpose | |---|---| | libnix | C runtime for m68k-amigaos-gcc โ€” replaces sc.lib | | libamiga | OS glue for GCC (NDK-based) | | libm | Soft-float math | | libgcc | GCC internal helpers (division, etc.) |


Startup Object: c.o / _start

Every AmigaOS C program begins execution at the first word of segment 0 โ€” not at main(). The startup object c.o (SAS/C) or crt0.o (GCC/libnix) is always linked first and provides:

;; SAS/C c.o skeleton (simplified)
_start:
    MOVE.L  4.W, A6              ; SysBase from absolute location $4
    MOVE.L  A0, _CommandStr      ; raw CLI argument string (from dos.library)
    MOVE.L  A1, _WBenchMsg       ; WBStartup message (if WB launch, else NULL)
    JSR     __main               ; C runtime init โ†’ eventually calls main()
    ; D0 = exit code from main()
    MOVE.L  D0, _rc              ; save return code
    JSR     __exit               ; C runtime cleanup
    RTS                          ; return to dos.library

What __main Does

  1. Opens DOSBase via OpenLibrary("dos.library", 0) using SysBase in A6
  2. Sets up stdin/stdout/stderr file handles (wraps dos.library I/O)
  3. Allocates C heap (if any static malloc/new usage)
  4. Initializes errno, _timezone, __ProgramName
  5. Calls any registered __constructor functions (C++ static init)
  6. Calls main(argc, argv) โ€” argument string is parsed from _CommandStr
  7. Calls exit(return_code) โ†’ runs atexit() handlers โ†’ CloseLibrary(DOSBase)

WBStartup Glue

When launched from Workbench (double-click), A0 = NULL, A1 = WBStartup msg ptr. The startup code must:

/* standard WB detection in __main / startup */
if (_WBenchMsg) {
    /* We are a WB launch. argc=0, argv=NULL passed to main() */
    /* Must not return until cleanup */
}

On exit from a WB-launched program:

Forbid();                          /* prevent task switching during cleanup */
ReplyMsg((struct Message *)_WBenchMsg);  /* unblock Workbench */
/* now safe to RTS / remove task */

This pattern is critical: failing to ReplyMsg a WB launch will hang Workbench.


SAS/C startup checks for a stack size cookie in the executable:

/* In your source โ€” sets minimum stack to 8 KB */
LONG __stack = 8192;

The linker includes this symbol at a known offset; the OS shell reads it and allocates at least that much stack before launching. IDA Pro will often highlight _stack as a data symbol.


CTRL-C Checking

SAS/C runtime polls for CTRL-C via CheckSignal(SIGBREAKF_CTRL_C) inside printf, fgets, and other stdio functions. Programs that do long computation loops should call:

if (SetSignal(0, 0) & SIGBREAKF_CTRL_C)
    cleanup_and_exit();

Or use SAS/C's __chkabort() hook.


slink FROM lib/c.o myobj.o LIB lib/sc.lib lib/amiga.lib TO myprogram

Order matters: 1. lib/c.o โ€” must be first (entry point at start of segment 0) 2. Object files (myobj.o, ...) 3. sc.lib โ€” C runtime (resolves printf, etc.) 4. amiga.lib โ€” OS stubs (resolves any non-inlined OS calls)

m68k-amigaos-gcc -o myprogram myobj.o -lamiga -lnix -lgcc \
    -Wl,-Map,myprogram.map

Linker script places crt0.o automatically via -lnix startup group.


Library Archive Format

Static libraries (.lib) are HUNK_LIB archives โ€” sequences of embedded HUNK_UNIT object files with a HUNK_INDEX for fast symbol lookup:

HUNK_LIB
  [HUNK_UNIT: AllocMem.o]
    HUNK_CODE
    HUNK_EXT   (export: _AllocMem)
    HUNK_END
  [HUNK_UNIT: FreeMem.o]
    ...
HUNK_INDEX
  [symbol table: _AllocMem โ†’ unit 0, _FreeMem โ†’ unit 1, ...]

The linker only pulls in units whose exported symbols are referenced โ€” unused code from libraries is not linked into the executable (link-time dead-stripping).


Segment Layout in Final Executable

With a typical 3-object, 2-lib link:

Segment 0 (code):  c.o startup + all CODE sections merged
Segment 1 (data):  all DATA sections merged
Segment 2 (BSS):   all BSS sections (zero-filled)

Most linkers merge same-type sections by default. slink supports explicit placement control via CHIP / FAST keywords.


References

  • NDK39: lib/ โ€” amiga.lib, auto.lib, debug.lib, c.o
  • SAS/C 6.x Programmer's Reference Manual โ€” linking chapter
  • libnix source: https://github.com/bebbo/libnix
  • Amiga ROM Kernel Reference Manual: Libraries โ€” process startup appendix