amiga-bootcamp/13_toolchain/gcc_amiga.md
Ilia Sharin 9f5d9de1ed docs: expand 7 Tier 3 articles to Deep quality
- gcc_amiga.md: 101→606 lines — pipeline, Docker, platform builds, flags, antipatterns, FAQ
- trackdisk.md: 178→428 lines — MFM encoding, 16-command reference, antipatterns, FPGA impact
- console.md: 244→470 lines — decision guide, TUI/progress cookbooks, antipatterns, pitfalls
- layers.md: 224→739 lines — ClipRect engine, LVO API, backfill hooks, 4 antipatterns, optimization
- text_fonts.md: 215→708 lines — ColorFont, Compugraphic outlines, 3 cookbooks, 4 antipatterns
- windows.md: 370→778 lines — 5 antipatterns, decision guide, 3 cookbooks, modern analogies
- menus.md: 378→695 lines — render chain diagram, 5 antipatterns, lifecycle cookbook, 6 FAQ
2026-05-12 22:04:16 -04:00

27 KiB

← Home · Toolchain

m68k-amigaos-gcc — GCC Cross-Compiler for AmigaOS

In 2025, building Amiga software looks nothing like 1993. The bebbo toolchain — GCC 6.5 retargeted for m68k-amigaos — cross-compiles on Linux, macOS, and Windows, producing native Amiga hunk executables from modern C and C++ source. It replaced the ancient GCC 2.95 cross-compiler that lived on Aminet for two decades, bringing modern optimization, C++14 support, and a Docker-based workflow that takes under five minutes to set up.

The toolchain ships with vasm as its default assembler and vlink as its linker. GCC emits assembly, vasm assembles it, and vlink produces the final hunk executable. This replaces the aging GNU as and ld that produced unreliable Amiga binaries.


Architecture

Compiler Pipeline

flowchart LR
    subgraph "Frontend"
        SRC["Source (.c/.cc)"]
        GCC["m68k-amigaos-gcc<br>GCC 6.5"]
        PP["Preprocessor (cpp)"]
    end

    subgraph "Backend"
        ASM["Assembly (.s)"]
        VASM["vasmm68k_mot"]
        OBJ["Object (.o)"]
    end

    subgraph "Linker"
        VL["vlink"]
        EXE["Amiga HUNK"]
    end

    SRC --> GCC
    GCC --> PP --> ASM --> VASM --> OBJ
    OBJ --> VL --> EXE

bebbo's GCC is based on GCC 6.5.0 with a custom m68k-amigaos backend. Unlike the original GCC 2.95 cross-compiler (which used GNU as and ld), bebbo's fork integrates vasm and vlink as the default assembler and linker. This produces more reliable Amiga hunk-format executables.

What Ships in the Toolchain

Component Binary Purpose
GCC C compiler m68k-amigaos-gcc C frontend, optimizer, code generator
GCC C++ compiler m68k-amigaos-g++ C++ frontend (supports C++14)
Assembler vasmm68k_mot Motorola-syntax assembler (replaces GNU as)
Linker vlink Multi-format linker (replaces GNU ld)
Archiver m68k-amigaos-ar Static library (.a) creation
Strip m68k-amigaos-strip Symbol removal
objdump m68k-amigaos-objdump Disassembly and inspection
NDK headers /opt/amiga/m68k-amigaos/ndk-include/ AmigaOS API definitions
libnix /opt/amiga/m68k-amigaos/lib/ Lightweight C runtime

Installation

Quick Start: Docker (All Platforms)

The fastest path to a working toolchain on any OS:

# Pull the pre-built image:
docker pull amigadev/m68k-amigaos-gcc

# Compile a single file:
docker run --rm -v "$(pwd):/work" amigadev/m68k-amigaos-gcc \
    m68k-amigaos-gcc -noixemul -o hello hello.c

# Interactive shell with toolchain available:
docker run --rm -it -v "$(pwd):/work" amigadev/m68k-amigaos-gcc bash

Note

The Docker image is maintained at hub.docker.com/r/amigadev/m68k-amigaos-gcc. It includes the full toolchain, NDK headers, and libnix runtime.

Source Repositories

bebbo's original repository was removed from GitHub. Use the maintained forks:

Mirror URL Notes
BlitterStudio https://github.com/BlitterStudio/amiga-gcc Most active, primary fork
Codeberg https://codeberg.org/bebbo/amiga-gcc Official mirror
Pre-built Windows installer http://franke.ms/download/setup-amiga-gcc.exe MSYS2-based, includes GUI installer

Linux

Ubuntu / Debian — Prerequisites

sudo apt install make wget git gcc g++ lhasa libgmp-dev libmpfr-dev \
    libmpc-dev flex bison gettext texinfo ncurses-dev autoconf rsync \
    libreadline-dev

Fedora — Prerequisites

sudo dnf install wget gcc gcc-c++ python git perl-Pod-Simple gperf patch \
    autoconf automake make makedepend bison flex ncurses-devel gmp-devel \
    mpfr-devel libmpc-devel gettext-devel texinfo rsync readline-devel

CentOS / RHEL — Prerequisites

sudo yum install wget gcc gcc-c++ python git perl-Pod-Simple gperf patch \
    autoconf automake make makedepend bison flex ncurses-devel gmp-devel \
    mpfr-devel libmpc-devel gettext-devel texinfo rsync readline-devel

Build

git clone https://github.com/BlitterStudio/amiga-gcc.git
cd amiga-gcc
make update

# Build everything (adjust -j to your core count):
make all -j$(nproc)
# Installs to /opt/amiga/ by default

# If /opt/amiga is not writable by your user:
sudo mkdir /opt/amiga
sudo chgrp users /opt/amiga
sudo chmod 775 /opt/amiga
sudo usermod -a -G users $USER   # then log out and back in

# Or install to a user-writable location:
make all -j$(nproc) PREFIX=$HOME/amiga

Add to your shell profile:

export PATH=/opt/amiga/bin:$PATH

Build time: ~10 minutes on a modern Linux box with -j4 or higher.


macOS

macOS requires Xcode Command Line Tools and Homebrew. The default /bin/bash is too old (macOS ships bash 3.2); you must use Homebrew's bash.

Prerequisites

# Install Xcode CLI tools (if not already installed):
xcode-select --install

# Install Homebrew (https://brew.sh) if not already installed,
# then install the required packages:
brew install bash wget make lhasa gmp mpfr libmpc flex gettext \
    gnu-sed texinfo gcc@12 make autoconf bison

Build

git clone https://github.com/BlitterStudio/amiga-gcc.git
cd amiga-gcc
make update

# CRITICAL: macOS default bash is too old — always use Homebrew's bash:
make all -j$(sysctl -n hw.ncpu) SHELL=$(brew --prefix)/bin/bash

# If the build fails with system clang errors, force Homebrew's GCC:
CC=gcc-12 CXX=g++-12 make all -j$(sysctl -n hw.ncpu) SHELL=$(brew --prefix)/bin/bash

Add to your shell profile:

export PATH=/opt/amiga/bin:$PATH

Apple Silicon (M1 / M2 / M3 / M4)

Native builds on Apple Silicon are directly supported — no Rosetta needed. The build compiles the m68k cross-compiler toolchain and does not run any m68k code on the host, so the host architecture is irrelevant.

The only Apple Silicon caveat: some Homebrew packages install into /opt/homebrew/ instead of /usr/local/. The $(brew --prefix) calls above handle this automatically.

Building GDB on macOS

GDB requires a newer bison than macOS provides. Use the Homebrew version:

export PATH=$(brew --prefix bison)/bin:$PATH
make gdb SHELL=$(brew --prefix)/bin/bash

Windows

Three options, in order of recommendation:

MSYS2 provides a Unix-like build environment on Windows with native performance (no virtualization).

# Install MSYS2 from https://www.msys2.org/, then open an MSYS2 terminal:
pacman -S git base-devel gcc flex gmp-devel mpc-devel mpfr-devel \
    ncurses-devel rsync autoconf automake

# Clone and build:
git clone https://github.com/BlitterStudio/amiga-gcc.git
cd amiga-gcc
make update

# IMPORTANT: cd into an absolute path — MSYS2 has a bug where
# relative paths can cause file-not-found errors during build:
cd /c/Users/you/amiga-gcc
make all -j4

Add to your Windows PATH: %USERPROFILE%\msys64\opt\amiga\bin (adjust if MSYS2 is installed elsewhere).

Warning

You must cd into an absolute MSYS2 path (e.g. /c/msys64/home/test/amiga-gcc/) before running make. Building from a relative path fails because some source files aren't found correctly — this is an MSYS2 path translation bug.

WSL — Ubuntu on Windows

If you already use WSL (Windows Subsystem for Linux), the build is identical to Ubuntu:

# In WSL Ubuntu terminal:
sudo apt install make wget git gcc g++ lhasa libgmp-dev libmpfr-dev \
    libmpc-dev flex bison gettext texinfo ncurses-dev autoconf rsync \
    libreadline-dev

git clone https://github.com/BlitterStudio/amiga-gcc.git
cd amiga-gcc && make update && make all -j$(nproc)

The toolchain ends up in /opt/amiga/ inside WSL. To access compiled binaries from Windows Explorer, look in \\wsl$\\Ubuntu\\opt\\amiga\\bin.

Cygwin (Legacy)

Cygwin works but is significantly slower than MSYS2 or WSL. The build can take over an hour on the same hardware that completes in 10 minutes under MSYS2.

# Install Cygwin from https://cygwin.com/, then in the Cygwin terminal:
wget https://raw.githubusercontent.com/transcode-open/apt-cyg/master/apt-cyg
install apt-cyg /bin
apt-cyg install gcc-core gcc-g++ python git perl-Pod-Simple gperf patch \
    automake make makedepend bison flex libncurses-devel python-devel \
    gettext-devel libgmp-devel libmpc-devel libmpfr-devel rsync

git clone https://github.com/BlitterStudio/amiga-gcc.git
cd amiga-gcc && make update && make all -j$(nproc)

Pre-built Installer

For those who want a zero-build option, there is a community-maintained Windows installer:

Note

The pre-built installer may lag behind the latest Git commits. Check the version after installing with m68k-amigaos-gcc --version.


Post-Install Verification

After building or installing by any method, verify the toolchain:

# Check GCC version:
m68k-amigaos-gcc --version
# Expected: gcc (GCC) 6.5.0 + Amiga patches

# Check assembler:
vasmm68k_mot -V

# Check linker:
vlink -V

# Compile and inspect a test binary:
echo 'int main(void) { return 0; }' > test.c
m68k-amigaos-gcc -noixemul -m68000 -o test test.c
m68k-amigaos-objdump -d test | head -20
rm -f test test.c

Platform Comparison

Aspect Linux macOS Windows MSYS2 Windows WSL Docker
Build time ~10 min ~15 min ~15-20 min ~10 min N/A (pre-built)
Host compiler System GCC/Clang Homebrew GCC MSYS2 GCC Ubuntu GCC N/A
Shell requirement Any bash Homebrew bash MSYS2 bash Any bash Any
Path quirks None /opt/homebrew on ARM Absolute paths only None Volume mounts
Apple Silicon N/A Native, no Rosetta N/A N/A Via Rosetta
Setups for beginners Easy Medium Medium Easy Easiest
Updates make update && make all Same + SHELL= Same + absolute cd Same as Linux docker pull

Compilation Flags

CPU Target Flags

Flag Target Instructions Available Typical Use
-m68000 68000 Baseline A500, A1000, CDTV — smallest code
-m68020 68020 MULS.L, DIVS.L, 32-bit math A1200, A3000 — best default
-m68030 68030 + MMU instructions Accelerated A1200
-m68040 68040 + hardware FPU A4000, CyberStorm
-m68060 68060 + superscalar 060 accelerators
-m68881 68881/68882 FPU coprocessor For 68000/020 with FPU

Amiga-Specific Flags

Flag Purpose
-noixemul Use libnix runtime — no ixemul.library dependency. Always use this unless you need POSIX compatibility.
-fbaserel Base-relative addressing (small data model). Reduces code size, uses A4 as data base pointer.
-resident Generate resident-capable code (for libraries and devices).
-fomit-frame-pointer Frees A5 from frame-pointer duty. Safe for AmigaOS code — do not use with -pg profiling.
-malways-restore-a4 Force A4 save/restore in every function (needed for small data model with callbacks).
-mrestore-a4 Save/restore A4 only when needed (less conservative than -malways-restore-a4).

Optimization Flags

Flag Effect Use When
-O0 No optimization Debugging — all variables in memory
-O1 Basic optimization Development — fast compile, some speedup
-O2 Full optimization Release — best speed/size balance
-O3 Aggressive optimization Inner loops — may increase code size
-Os Optimize for size Memory-constrained — smallest binary
-fomit-frame-pointer Eliminate frame pointer All release builds — frees A5


Startup Code & Runtime Libraries

libnix is a minimal C runtime that requires no shared library on the target Amiga. It is the default when using -noixemul. Programs linked with libnix run on any Amiga with no extra dependencies.

flowchart LR
    ENTRY["_start entry"] --> CRT0["crt0.o"] --> PREMAIN["__main()"] --> MAIN["main()"] --> EXIT["exit() / _exit()"]
    style CRT0 fill:#e8f4fd,stroke:#2196f3,color:#333
Startup Module Use For Auto-Opens Libraries
libnix (default) CLI programs None — minimal overhead
libnix + -resident Shared libraries / devices None
Custom crt0.o Bootblock, tracker-loader None — you own the entry point

ixemul (Legacy)

ixemul provides a Unix-like C runtime (malloc(), printf(), POSIX file I/O) but requires the ixemul.library to be installed on the target Amiga. This is useful for porting Unix software but creates a runtime dependency.

/* WITHOUT -noixemul (ixemul mode): */
#include <stdio.h>  /* ixemul provides standard C I/O */

int main(void) {
    printf("Hello via ixemul\n");  /* Works like any Unix program */
    return 0;
}

Warning

Never ship ixemul-linked programs to end users unless you also ship ixemul.library. For standalone Amiga programs, always use -noixemul.

Startup Decision Guide

Scenario Startup Flags
CLI tool, standalone libnix CLI -noixemul
Workbench tool libnix WB startup -noixemul + handle WBStartup message
Shared library libnix resident -noixemul -resident
Bootblock / custom loader No runtime -noixemul -nostartfiles + custom crt0.o
Unix port ixemul Omit -noixemul


Inline/Pragma System Calls

GCC uses inline assembly stubs in <inline/*.h> headers to map C function calls directly onto the AmigaOS register-based calling convention. The <proto/*.h> headers include the appropriate inline or pragma version automatically.

/* Use proto headers (recommended — auto-selects best available mechanism): */
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/graphics.h>

/* The proto header expands Open() into an inline asm stub like: */
/*   MOVE.L name, D1
     MOVE.L mode, D2
     MOVEA.L _DOSBase, A6
     JSR -30(A6)          */

How Inline Stubs Work

GCC's inline headers use __asm() extensions to place arguments in the correct registers:

/* Simplified version of what inline/dos.h contains: */
static __inline BPTR Open(CONST_STRPTR name, LONG accessMode)
{
    register BPTR res __asm("d0");     /* return value in D0 */
    register CONST_STRPTR r_d1 __asm("d1") = name;
    register LONG r_d2 __asm("d2") = accessMode;
    __asm volatile (
        "movea.l %1,%%a6\n\t"
        "jsr -30(%%a6)"
        : "=r"(res)
        : "r"(DOSBase), "r"(r_d1), "r"(r_d2)
        : "d0", "d1", "d2", "a0", "a1", "memory"
    );
    return res;
}

See compiler_stubs.md for a cross-compiler comparison of stub generation.



Practical Examples

Minimal CLI Program

/* hello.c — minimal Amiga CLI program with libnix */
#include <proto/dos.h>
#include <proto/exec.h>

int main(void)
{
    BPTR output = Output();  /* get stdout handle */
    char msg[] = "Hello, Amiga!\n";
    Write(output, msg, sizeof(msg) - 1);
    return 0;
}
m68k-amigaos-gcc -noixemul -m68000 -Os -o hello hello.c

Workbench Program with Tooltypes

/* wbapp.c — program that runs from both CLI and Workbench */
#include <proto/dos.h>
#include <proto/exec.h>
#include <workbench/startup.h>
#include <stdio.h>   /* only with ixemul; use RawDoFmt() with libnix */

int main(int argc, char **argv)
{
    if (argc == 0)
    {
        /* Launched from Workbench — argv points to WBStartup */
        struct WBStartup *wb = (struct WBStartup *)argv;
        struct WBArg *arg = &wb->sm_ArgList[0];
        /* arg->wa_ToolTypes contains the tooltype array */
    }
    else
    {
        /* Launched from CLI */
        Printf("Running from CLI with %ld arguments\n", argc);
    }
    return 0;
}
m68k-amigaos-gcc -noixemul -m68000 -O2 -o wbapp wbapp.c

Shared Library Skeleton

/* mylib.c — minimal shared library for AmigaOS */
#include <proto/exec.h>
#include <exec/libraries.h>
#include <exec/resident.h>

/* The library function table */
LONG MyLibFunction(ULONG val)
{
    return val * 2;
}

/* Function table — NULL terminated */
static const APTR funcTable[] = {
    (APTR)LIBENT_0,     /* Open() — auto-generated */
    (APTR)LIBENT_1,     /* Close() — auto-generated */
    (APTR)LIBENT_2,     /* Expunge() — auto-generated */
    (APTR)LIBENT_3,     /* Reserved */
    (APTR)MyLibFunction,
    (APTR)-1            /* end of table */
};

/* Library init table */
static const struct LibInitTable {
    APTR *libBase;
    APTR *funcTable;
    APTR *dataTable;
    APTR (*init)(APTR libBase, BPTR segList, struct ExecBase *sysBase);
} libInit = {
    (APTR *)NULL,  /* filled by MakeLibrary */
    (APTR *)funcTable,
    (APTR *)NULL,  /* data table */
    NULL           /* init function */
};
m68k-amigaos-gcc -noixemul -resident -m68000 -O2 -o mylib.library mylib.c

CMake Integration

# CMakeLists.txt for m68k-amigaos-gcc

cmake_minimum_required(VERSION 3.14)
project(MyAmigaApp C)

set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR m68k)

set(TOOLPREFIX "m68k-amigaos-")
set(CMAKE_C_COMPILER   "${TOOLPREFIX}gcc")
set(CMAKE_AR           "${TOOLPREFIX}ar")
set(CMAKE_STRIP        "${TOOLPREFIX}strip")

# No standard library — we use libnix
set(CMAKE_C_FLAGS "-noixemul -m68000 -O2 -Wall -Wextra")

add_executable(myapp main.c util.c)

# Strip the final binary
add_custom_command(TARGET myapp POST_BUILD
    COMMAND ${CMAKE_STRIP} $<TARGET_FILE:myapp>)
mkdir build && cd build
cmake -DCMAKE_TOOLCHAIN_FILE=../toolchain-m68k-amigaos.cmake ..
make

GCC vs VBCC Decision Guide

flowchart TD
    START{"Starting a new project?"} --> CPP{"Need C++?"}
    CPP -->|Yes| GCC{"Use GCC"}
    CPP -->|No| GNU{"Need GNU extensions?\n(__attribute__, typeof, etc.)"}
    GNU -->|Yes| GCC
    GNU -->|No| SPEED{"Compile speed matters?"}
    SPEED -->|Yes| VBCC{"Use VBCC"}
    SPEED -->|No| REG{"Need explicit register control?"}
    REG -->|Yes| VBCC
    REG -->|No| EITHER{"Either compiler works\nUse what the project already uses"}
Criterion GCC bebbo VBCC
C++ support Yes (C++14) No
C standard C11 C89 (+ partial C99)
GNU extensions Yes No
Compile speed Slow (large optimizer) Fast
Code quality Good (mature backend) Excellent (tight m68k code)
Register control __asm("d1") inline __reg("d1") storage class
Linker vlink (default) vlink
Debug info HUNK_DEBUG + GDB remote HUNK_DEBUG
Active maintenance Yes (BlitterStudio) Yes (Volker Barthelmann)
AmigaOS 4 / MorphOS Yes Yes
Smallest binary With -Os With -size (often smaller)

See vbcc.md for the VBCC deep dive.


Best Practices

  1. Always use -noixemul for standalone programs — ixemul requires a runtime library
  2. Target -m68000 unless you know your audience has an accelerator — A500 is the largest installed base
  3. Use -Os for size-constrained programs; -O2 for performance-critical code
  4. Add -fomit-frame-pointer in release builds to free A5 for general use
  5. Strip release binaries with -s or m68k-amigaos-strip
  6. Use proto/*.h headers — never call raw LVO offsets manually in C
  7. Set up a Makefile or CMake build — see makefiles.md for templates
  8. Keep NDK headers up to date — NDK 3.9 is the last official release
  9. Test on both FS-UAE and real hardware — timing-sensitive code behaves differently
  10. For mixed C + assembly, use GCC for C and vasm for asm, link with vlink

Named Antipatterns

"The ixemul Dependence" — Shipping Without -noixemul

/* BAD: Compiles fine, but requires ixemul.library on the target */
#include <stdio.h>
int main(void) {
    printf("Hello\n");  /* ixemul provides printf */
    return 0;
}
/* Build: m68k-amigaos-gcc -o hello hello.c   (missing -noixemul!) */
/* CORRECT: Uses AmigaOS native I/O, no dependencies */
#include <proto/dos.h>
int main(void) {
    Write(Output(), "Hello\n", 6);
    return 0;
}
/* Build: m68k-amigaos-gcc -noixemul -o hello hello.c */

"The Phantom Frame Pointer" — A5 Corruption

/* BAD: Without -fomit-frame-pointer, A5 is used as frame pointer.
   If your code or an OS callback corrupts A5, every local variable
   in the calling chain becomes garbage. */
void callback(void) {
    /* A5 points to caller's frame — but we were called from OS code */
    int x = 42;  /* stored at A5+offset — WRONG frame! */
}
/* CORRECT: Use -fomit-frame-pointer so A5 is free,
   and explicitly save/restore registers in callbacks */
void callback(void) {
    register int x __asm("d3") = 42;  /* in register, not on frame */
    /* ... */
}
/* Build: m68k-amigaos-gcc -noixemul -fomit-frame-pointer ... */

"The Wrong CPU" — 68020 Code on 68000

# BAD: Compiles with 68020 instructions, crashes on A500
m68k-amigaos-gcc -noixemul -m68020 -O2 -o game game.c
# The binary contains MULS.L, DIVS.L — illegal on 68000
# CORRECT: Target the lowest common denominator
m68k-amigaos-gcc -noixemul -m68000 -O2 -o game game.c
# Or use runtime detection and provide two code paths

"The Chip RAM Blind Spot" — Allocating Fast for DMA

/* BAD: AllocMem with MEMF_FAST — not accessible by custom chip DMA */
APTR bitmap_data = AllocMem(width * height / 8, MEMF_FAST);
/* Blitter cannot reach this memory! Silent corruption or crash. */
/* CORRECT: DMA-visible memory must be Chip RAM */
APTR bitmap_data = AllocMem(width * height / 8, MEMF_CHIP | MEMF_CLEAR);
/* Now Blitter, Copper, and bitplane DMA can access it */

Warning

This is not a GCC-specific bug — it is the single most common Amiga programming mistake. Any data touched by custom chip DMA must be in Chip RAM. See memory_types.md.


Pitfalls & Common Mistakes

1. Stack Size Too Small

Symptom: Random crashes after running for a while, especially in functions with large local arrays.

Cause: AmigaOS default stack size is only 4,096 bytes for CLI programs and 4,000 bytes for Workbench programs. GCC does not warn about stack overflow.

Fix: Set stack size explicitly in the icon or via the Stack command:

# In CLI:
Stack 10000
myapp

# Or embed in .info icon with icon tool type:
STACK=10000

2. Volatile Hardware Registers

Symptom: Blitter or Copper register writes disappear or happen in the wrong order.

Cause: GCC's optimizer eliminates or reorders memory accesses to non-volatile pointers.

Fix: Always use volatile for hardware registers:

#include <hardware/custom.h>
extern volatile struct Custom custom;  /* NDK does this for you */

/* For custom register pointers: */
volatile UWORD *myReg = (volatile UWORD *)0xDFF100;
*myReg = 0xFF;  /* guaranteed emit */

3. Big-Endian Data in File Formats

Symptom: File I/O reads wrong values on modern x86 development machines.

Cause: The 68000 is big-endian. When testing file parsing code on the host (x86), byte order is reversed. Cross-compiled code runs correctly on Amiga, but unit tests on the host may fail.

Fix: Use explicit byte-swap functions or test only on the target:

#include <exec/types.h>  /* UWORD, ULONG are defined here */

/* Reading a big-endian ULONG from a file — works on both host and target */
ULONG read_be32(UBYTE *buf) {
    return ((ULONG)buf[0] << 24) | ((ULONG)buf[1] << 16) |
           ((ULONG)buf[2] << 8)  |  (ULONG)buf[3];
}

4. Missing NDK Include Paths

Symptom: fatal error: proto/exec.h: No such file or directory

Cause: bebbo's toolchain installs NDK headers in /opt/amiga/m68k-amigaos/ndk-include/, which is not a default GCC search path.

Fix: Add the include path explicitly:

m68k-amigaos-gcc -noixemul -I/opt/amiga/m68k-amigaos/ndk-include -o app app.c
# Or use the Makefile template from makefiles.md

5. Mixing GCC and VBCC Object Files

Symptom: Link errors, undefined references to internal runtime functions.

Cause: GCC and VBCC use different internal calling conventions for their runtime helpers (division, stack checking, etc.).

Fix: Compile the entire project with one compiler. If mixing assembly, use vasm and link with vlink.


FAQ

Q: What version of GCC does bebbo's toolchain use? A: GCC 6.5.0 with a custom m68k-amigaos backend. This is much newer than the ancient GCC 2.95 that was the standard for decades.

Q: Can I compile C++ for Amiga? A: Yes — use m68k-amigaos-g++ with the same flags. C++14 is supported. Note that C++ exceptions and RTTI increase code size significantly on m68k.

Q: Where are bebbo's original repos? A: bebbo removed his repositories from GitHub. Use the BlitterStudio fork or the Codeberg mirror.

Q: Can I use GCC inline assembly for OS calls? A: Yes, but prefer <proto/*.h> headers — they handle the register allocation correctly. See compiler_stubs.md for the full comparison.

Q: How do I debug cross-compiled programs? A: Use FS-UAE with GDB remote debugging (-s flag), or add kprintf() / Printf() tracing. The -g flag emits HUNK_DEBUG symbols.

Q: Does GCC support AmigaOS 4 or MorphOS? A: GCC bebbo targets AmigaOS 3.x (m68k). For AmigaOS 4 (PPC), use the official SDK. For MorphOS, use the MorphOS SDK with GCC.

Q: What is the difference between -fbaserel and small data model? A: -fbaserel enables base-relative addressing where frequently-accessed global data is accessed relative to A4. This reduces code size but requires A4 to be set up correctly — handled by libnix startup code.


References

Toolchain