[← Home](../README.md) · [Toolchain](README.md) # 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](vasm_vlink.md) as its default assembler and [vlink](vasm_vlink.md) 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 ```mermaid flowchart LR subgraph "Frontend" SRC["Source (.c/.cc)"] GCC["m68k-amigaos-gcc
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](vasm_vlink.md) and [vlink](vasm_vlink.md) 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: ```bash # 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](https://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 ```bash 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 ```bash 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 ```bash 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 ```bash 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: ```bash 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 ```bash # 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 ```bash 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: ```bash 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: ```bash export PATH=$(brew --prefix bison)/bin:$PATH make gdb SHELL=$(brew --prefix)/bin/bash ``` --- ### Windows Three options, in order of recommendation: #### MSYS2 (Recommended) [MSYS2](https://www.msys2.org/) provides a Unix-like build environment on Windows with native performance (no virtualization). ```bash # 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: ```bash # 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. ```bash # 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: - **Download:** http://franke.ms/download/setup-amiga-gcc.exe - Includes the full toolchain, NDK headers, libnix, and an MSYS2-based runtime - Install and add the `bin/` directory to your `PATH` > [!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: ```bash # 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 (Recommended) **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. ```mermaid 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. ```c /* WITHOUT -noixemul (ixemul mode): */ #include /* 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 `` headers to map C function calls directly onto the AmigaOS register-based calling convention. The `` headers include the appropriate inline or pragma version automatically. ```c /* Use proto headers (recommended — auto-selects best available mechanism): */ #include #include #include /* 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: ```c /* 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](../04_linking_and_libraries/compiler_stubs.md) for a cross-compiler comparison of stub generation. --- --- ## Practical Examples ### Minimal CLI Program ```c /* hello.c — minimal Amiga CLI program with libnix */ #include #include int main(void) { BPTR output = Output(); /* get stdout handle */ char msg[] = "Hello, Amiga!\n"; Write(output, msg, sizeof(msg) - 1); return 0; } ``` ```bash m68k-amigaos-gcc -noixemul -m68000 -Os -o hello hello.c ``` ### Workbench Program with Tooltypes ```c /* wbapp.c — program that runs from both CLI and Workbench */ #include #include #include #include /* 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; } ``` ```bash m68k-amigaos-gcc -noixemul -m68000 -O2 -o wbapp wbapp.c ``` ### Shared Library Skeleton ```c /* mylib.c — minimal shared library for AmigaOS */ #include #include #include /* 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 */ }; ``` ```bash m68k-amigaos-gcc -noixemul -resident -m68000 -O2 -o mylib.library mylib.c ``` ### CMake Integration ```cmake # 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} $) ``` ```bash mkdir build && cd build cmake -DCMAKE_TOOLCHAIN_FILE=../toolchain-m68k-amigaos.cmake .. make ``` --- ## GCC vs VBCC Decision Guide ```mermaid 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](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](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](vasm_vlink.md) for asm, link with vlink --- ## Named Antipatterns ### "The ixemul Dependence" — Shipping Without -noixemul ```c /* BAD: Compiles fine, but requires ixemul.library on the target */ #include int main(void) { printf("Hello\n"); /* ixemul provides printf */ return 0; } /* Build: m68k-amigaos-gcc -o hello hello.c (missing -noixemul!) */ ``` ```c /* CORRECT: Uses AmigaOS native I/O, no dependencies */ #include 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 ```c /* 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! */ } ``` ```c /* 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 ```bash # 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 ``` ```bash # 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 ```c /* 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. */ ``` ```c /* 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](../01_hardware/common/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: ```bash # 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: ```c #include 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: ```c #include /* 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: ```bash 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](vasm_vlink.md) 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](https://github.com/BlitterStudio/amiga-gcc) or the [Codeberg mirror](https://codeberg.org/bebbo/amiga-gcc). **Q: Can I use GCC inline assembly for OS calls?** A: Yes, but prefer `` headers — they handle the register allocation correctly. See [compiler_stubs.md](../04_linking_and_libraries/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 - BlitterStudio fork: https://github.com/BlitterStudio/amiga-gcc - Codeberg mirror: https://codeberg.org/bebbo/amiga-gcc - Docker image: https://hub.docker.com/r/amigadev/m68k-amigaos-gcc ### Related Knowledge Base Articles - [vasm & vlink](vasm_vlink.md) — assembler and linker used by this toolchain - [VBCC](vbcc.md) — alternative cross-compiler comparison - [SAS/C](sasc.md) — native AmigaOS compiler (historical) - [Makefiles](makefiles.md) — build templates for GCC cross-compilation - [NDK](ndk.md) — NDK versions and include paths - [Compiler Stubs](../04_linking_and_libraries/compiler_stubs.md) — how GCC generates library call stubs - [Register Conventions](../04_linking_and_libraries/register_conventions.md) — AmigaOS register ABI - [Compiler Fingerprints](../05_reversing/compiler_fingerprints.md) — recognizing GCC output in disassembly