Interface Header Files for Amiga C Development

Amiga OS functions are register-based — each function documents which CPU registers its parameters go in (e.g. AllocMem(byteSize, requirements) takes D0 and D1). C compilers, though, pass parameters on the stack. Bridging that gap is the job of the interface header files: the clib/, proto/, pragmas/, pragma/, and inline/ drawers in the NDK, plus the amiga.lib static library. This article — distilled from Olaf Barthel's NDK 3.2 R4 developer documentation — explains how they came about and what to use.

The original bridge: stub code in amiga.lib

The early Amiga C compilers (Kickstart 1.0-1.3, the Green Hills compiler) called OS functions through stub code in amiga.lib. For each function, a small assembly stub fetches the parameters off the C stack, loads them into the required registers, loads the library base into A6, and jumps through the library's jump table:

_AllocMem:
    move.l  a6,-(sp)
    move.l  _SysBase,a6
    movem.l 8(sp),d0/d1
    jsr     -198(a6)
    move.l  (sp)+,a6
    rts

The stub code makes up the great bulk of amiga.lib. The leading underscore on _SysBase (and on every global symbol) is the convention the C compiler uses to mark a linker-visible global; assembly code must prepend it manually.

Library vector offsets (LVOs)

OS functions are reached through a 6-byte jump-table entry that precedes the library base. The byte offset into that table is the library vector offset (LVO). For AllocMem, the offset is 198, and 198 / 6 = 33 — it is the 33rd exec.library function. The FD/ drawer of the NDK holds the .fd ("function description") files that record each function's parameter count, registers, and LVO, usable by other languages (BASIC, Pascal, Modula-2, ARexx) too.

The pragma revolution: Lattice C 5 and Aztec C

Lattice C 5 (which became SAS/C) made the amiga.lib stubs redundant with two extensions:

  • ANSI function prototypes with parameter types.
  • #pragma libcall and #pragma syscall — the compiler generates the register-loading inline, no stub call.
#pragma syscall AllocMem c6 1002

The fields are: function name, LVO in hex (c6 = 198), and a register encoding (1002 = result in D0, two params in D0/D1). #pragma syscall only works for exec.library (it assumes SysBase); #pragma libcall takes an explicit base:

#pragma libcall IntuitionBase OpenWindow cc 801

Aztec C followed with #pragma amicall, invoked via a single <pragmas.h>:

#pragma amicall(SysBase, 0xc6, AllocMem(d0,d1))

The modern header organization

As compilers multiplied, the headers split into one drawer for prototypes and one set per compiler for the call mechanism:

Drawer Contents For
clib/ Function prototypes (*_protos.h) — compiler-independent All C/C++
proto/ Umbrella include: pulls in clib/ + the compiler's pragmas/inline + base-pointer declarations Recommended for everyone
pragmas/ #pragma libcall / #pragma syscall Lattice C, SAS/C
pragma/ #pragma amicall Aztec C, Maxon C, StormC
inline/ Inline-assembler macros vbcc
Include_I/lvo/ (R4) LVO definitions for every OS lib/device Assembly

The de-facto standard is a single include:

#include <proto/exec.h>

That pulls in <clib/exec_protos.h> (prototypes) plus the compiler-appropriate <inline/exec_protos.h> or <pragmas/exec_pragmas.h>. For vbcc the inline macro expands to:

#define AllocMem(byteSize, requirements) \
    __AllocMem(SysBase, (byteSize), (requirements))

Library base declarations

The pragma/inline headers need a library base pointer. The proto/ headers declare it, e.g. for dos.library (proto/dos.h):

extern struct DosLibrary * DOSBase;

These are only declared, not defined. Most compilers define and initialise SysBase and DOSBase as part of their runtime library, so those two are always available without an explicit OpenLibrary. For other libraries you must OpenLibrary() yourself and assign the base. To opt out of the auto-declarations (if you manage your own base variables), define __NOLIBBASE__ before including the proto header.

What R4 changed

NDK 3.2 R4 (the first release to include the DeveloperDocumentation/ drawer) brought full vbcc inline-header support (previously a vbcc install had to shadow the proto headers with its own), a new Include_I/lvo/ assembly directory with LVOs for every public OS library/device, Include_H/pragma/ headers for Aztec/Maxon/StormC, rebuilt amiga.lib/small.lib/debug.lib/ddebug.lib, and tidied the clib/inline/pragmas subdirectories. See NDK 3.2 R2/R3/R4 Release Notes.

See Also


Sources: Olaf Barthel, NDK 3.2 R4 DeveloperDocumentation/InterfaceHeaderFiles, 2022-01-28. Raw: raw/architecture/interface-header-files.md Updated: 2026-08-04