SAS/C Compiler Reference

SAS/C (Version 6.50) is the C compiler used to build all the NDK example code. This article documents its key features, extensions, and the knowledge needed to compile AmigaOS programs with it. Source: SAS/C User's Guide Volumes 1+2 (SAS Institute, 1993).

The compilation chain

source.c → sc (compiler) → object.o → slink (linker) → executable
source.c → sc link (one-step compile+link) → executable
Tool Purpose
sc C compiler (also does assembly via .s input)
slink Linker
smake Make utility (reads smakefile)
cdbg Source-level debugger (CodeProbe)
bum Library maintenance
oml Object module librarian

Key sc compiler options

Option Effect
link Compile + link in one step
optimize=N Optimization level 0–4 (0=none, 4=max)
define=SYM Define preprocessor symbol
ignore=NN Suppress warning number NN
nostackcheck Disable stack overflow checking
structureequivalence Allow struct assignment by structure type
verbose Verbose compilation output
includedir=dir Additional include path
code=small Small code model
data=far Far data model
math=standard Standard math library

smakefile patterns

An smakefile (SAS/C makefile) uses tab-indented rules like standard make:

CFLAGS = optimize=2 structureequivalence

all: myapp helper

myapp: myapp.c
    sc link $(CFLAGS) $*

helper: helper.c
    sc $(CFLAGS) $*.c
    slink lib:c.o helper.o myapp.o lib:sc.lib lib:amiga.lib to myapp

$* = target name without extension. $< = first dependency. $@ = full target name.

All NDK smakefiles follow the pattern: sc link structureequivalence $*.

SAS/C-specific keywords

These are critical for correct AmigaOS code:

__saveds — load data segment

void __saveds my_callback(void)
{
    /* Data segment (A4) is loaded — safe to access globals */
}

Mandatory for: interrupt handlers, hook callbacks, timer callbacks, any function called from a different task context or supervisor mode. Without __saveds, the function may access the wrong data segment, causing silent corruption or crashes.

The NDK examples consistently use __saveds on: - Hook entry functions - Interrupt handlers (AddIntServer callbacks) - Timer callbacks - BOOPSI dispatcher functions

__interrupt — interrupt handler

Marks a function as an interrupt handler (no stack switch, must preserve all registers). Combined with __saveds.

__regargs / __stdargs

  • __regargs — pass all arguments in CPU registers (D0–D2, A0–A1) instead of on the stack. Faster but non-standard ABI.
  • __stdargs — standard C calling convention (stack-based). Default.

Amiga library functions use the register-based ABI via the library's jump table and #pragma libcall.

Startup modules

SAS/C provides startup code that runs before main():

  1. OS calls the program entry point with:
  2. A6 = ExecBase
  3. A0 = BCPL return vector
  4. A2 = argument BSTR
  5. Startup module (e.g., c.o) opens DOSBase, parses arguments into argc/argv
  6. Calls main(argc, argv)
  7. After main() returns, startup closes DOSBase and exits

Without a startup module (for libraries, device drivers):

void __saveds __startup entry(void)
{
    /* A6 = ExecBase guaranteed */
    /* Must manually open DOSBase if needed */
}

#pragma statements

Seven pragmas control library calls and diagnostics:

Pragma Purpose
#pragma libcall Call library function via register ABI
#pragma flibcall Library call with floating-point registers
#pragma amicall Aztec C-compatible library call
#pragma regcall Register-based call (Aztec compat)
#pragma syscall System call
#pragma tagcall Tag-based (TagItem) call
#pragma msg Control diagnostic message severity

#pragma msg — diagnostic control

#pragma msg 123 warn      /* make message 123 a warning */
#pragma msg 123 ignore    /* suppress message 123 */
#pragma msg 123 error     /* make message 123 an error */
#pragma msg 123 warn push /* save current state, then change */
#pragma msg 123 pop       /* restore previous state */

Only works on messages numbered 1–299 (C compiler messages, not C++ translator).

Stack management

Default stack: 4000 bytes (stkneed = 400). This is often enough but can overflow with deep recursion or large local arrays.

Solution How When
stackext keyword Per-function stack extension Deep recursion in one function
stackext option Entire program Many functions need more stack
Increase stkneed extern long stkneed = 8192; All functions need more
nostackcheck Disable checking Release builds (minor speed gain)

Never set stkneed below 400. The stackext keyword adds overhead (extra register + entry code), so use selectively.

CodeProbe debugger (cdbg)

Source-level debugger with:

cdbg program          # load program
Command Action
break function Breakpoint at function
break file.c:42 Breakpoint at source line
watch variable Break when variable changes
step / next Single step (into/over)
continue Resume execution
print expr Evaluate expression
backtrace Call stack
list Show source around PC

CodeProbe supports debugging shared libraries (Chapter 5) and multitasking programs (Chapter 6) — both essential for AmigaOS where most programs spawn multiple tasks.

Optimization levels

Level Effect Recommended use
0 No optimization Debugging
1 Basic peephole Quick dev builds
2 Standard Development builds
3 Aggressive (inlining, loop opts) Release candidates
4 Maximum (may alter FP precision) Release builds

Trade-off: higher optimization = slower compilation, harder to debug.

See Also


Sources: SAS Institute Inc., "SAS/C Development System User's Guide" Volumes 1+2, Version 6.50 (1993). Raw: raw/sasc/sasc-reference-extract.md; raw/sasc/sasc-syslib-ref.md Updated: 2026-08-09 Updated: 2026-08-08