mirror of
https://github.com/alfishe/amiga-bootcamp.git
synced 2026-06-13 00:26:28 +00:00
More content added
This commit is contained in:
parent
5fac29ccd5
commit
8133b3a6cb
90 changed files with 7794 additions and 705 deletions
|
|
@ -9,9 +9,10 @@ Development tools for building Amiga software, from native compilers to modern c
|
|||
| File | Description |
|
||||
|---|---|
|
||||
| [gcc_amiga.md](gcc_amiga.md) | m68k-amigaos-gcc cross-compiler: bebbo's toolchain, Docker setup, CPU targets, libnix/ixemul startup |
|
||||
| [vbcc.md](vbcc.md) | **VBCC: Volker Barthelmann's portable C compiler — `__reg()` storage class, AmigaOS/MorphOS/AROS targets, vlink integration, cross-compilation** |
|
||||
| [sasc.md](sasc.md) | SAS/C 6.x: pragma format with register encoding, compiler/linker flags, __saveds/__asm idioms, SAS/C vs GCC comparison |
|
||||
| [stormc.md](stormc.md) | StormC native IDE: C/C++ with exceptions, integrated debugger, PowerPC support, version history |
|
||||
| [vasm_vlink.md](vasm_vlink.md) | vasm assembler and vlink linker |
|
||||
| [vasm_vlink.md](vasm_vlink.md) | **vasm assembler & vlink linker: modular architecture (CPU/syntax/output modules), Devpac/PhxAss compatibility, optimization system, linker scripts, multi-file projects, C↔asm interop, 30+ output formats, cross-platform workflows** |
|
||||
| [fd_files.md](fd_files.md) | FD/SFD file format and LVO generation |
|
||||
| [pragmas.md](pragmas.md) | Compiler pragmas and inline stubs: SAS/C pragmas, GCC inline asm, proto headers, fd2pragma |
|
||||
| [ndk.md](ndk.md) | NDK versions (3.1/3.9/3.2): contents, downloads, cross-compiler integration |
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ flowchart TD
|
|||
| Tool | Type | Requires | Best For |
|
||||
|---|---|---|---|
|
||||
| **Enforcer** | MMU memory watchdog | 68020+ with MMU | Catching NULL ptr, illegal reads/writes |
|
||||
| **MuForce** | MMU memory watchdog | 68040/060 | Same as Enforcer, optimised for 040/060 |
|
||||
| **MuForce** | MMU memory watchdog | 68040/060 | Same as Enforcer, optimized for 040/060 |
|
||||
| **MuGuardianAngel** | Stack overflow detector | 68040/060 | Catching stack overflow crashes |
|
||||
| **BareFoot** | Serial kernel debugger | Serial cable + terminal | Exec internals, boot crashes, system hangs |
|
||||
| **wack / SAD** | ROM-resident debugger | Guru Meditation (crash) | Post-crash analysis, ROM debugging |
|
||||
|
|
|
|||
|
|
@ -40,8 +40,8 @@ m68k-amigaos-gcc -noixemul -o hello hello.c
|
|||
# -m68040 — target 68040
|
||||
# -m68060 — target 68060
|
||||
# -m68881 — use 68881/68882 FPU
|
||||
# -Os — optimise for size
|
||||
# -O2 — optimise for speed
|
||||
# -Os — optimize for size
|
||||
# -O2 — optimize for speed
|
||||
# -fomit-frame-pointer — free up A5
|
||||
# -fbaserel — base-relative addressing (small data model)
|
||||
# -resident — generate resident-capable code
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
## Overview
|
||||
|
||||
SAS/C (originally Lattice C) was the dominant commercial C compiler for AmigaOS from the mid-1980s through the mid-1990s. Version **6.58** is the final release. It produces highly optimised 68k code with deep AmigaOS integration, including pragma-based system calls, SAS-specific debug formats, and a built-in profiler.
|
||||
SAS/C (originally Lattice C) was the dominant commercial C compiler for AmigaOS from the mid-1980s through the mid-1990s. Version **6.58** is the final release. It produces highly optimized 68k code with deep AmigaOS integration, including pragma-based system calls, SAS-specific debug formats, and a built-in profiler.
|
||||
|
||||
Most existing Amiga source code and documentation assumes SAS/C conventions. Understanding its idioms is essential for working with legacy codebases.
|
||||
|
||||
|
|
@ -90,7 +90,7 @@ lc -v -O -b0 -j73 main.c util.c LINK TO myapp
|
|||
| Flag | Meaning |
|
||||
|---|---|
|
||||
| `-v` | Verbose output |
|
||||
| `-O` | Enable global optimiser |
|
||||
| `-O` | Enable global optimizer |
|
||||
| `-b0` | Small data model (A4-relative, max 64 KB globals) |
|
||||
| `-b1` | Large data model (absolute addressing) |
|
||||
| `-j30` | Generate 68030 code |
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
| Version | Year | Key Features |
|
||||
|---|---|---|
|
||||
| StormC 1.0 | 1996 | Initial release, C compiler, basic IDE |
|
||||
| StormC 2.0 | 1997 | C++ support, improved optimiser |
|
||||
| StormC 2.0 | 1997 | C++ support, improved optimizer |
|
||||
| StormC 3.0 | 1998 | Full C++ with exceptions, STL, PowerPC support |
|
||||
| StormC 4.0 | 1999 | Final version, OS 3.5 integration |
|
||||
|
||||
|
|
@ -60,7 +60,7 @@ stormc -O2 -m68020 -o myapp main.c util.c
|
|||
; -m68020 Target 68020+
|
||||
; -m68040 Target 68040
|
||||
; -m68060 Target 68060
|
||||
; -O0 to -O3 Optimisation level
|
||||
; -O0 to -O3 Optimization level
|
||||
; -g Debug info
|
||||
; -c Compile only (no link)
|
||||
; -I<path> Include path
|
||||
|
|
@ -78,7 +78,7 @@ stormc -O2 -m68020 -o myapp main.c util.c
|
|||
| **IDE** | No (CLI + editor) | No (CLI + any editor) | **Yes (native GUI)** |
|
||||
| **Debugger** | External (CodeProbe) | GDB remote | **Integrated** |
|
||||
| **Cross-compile** | No (native only) | **Yes (Linux/macOS host)** | No (native only) |
|
||||
| **Optimiser quality** | Excellent | Good | Good |
|
||||
| **Optimizer quality** | Excellent | Good | Good |
|
||||
| **PowerPC** | No | No | Yes (v3+) |
|
||||
| **Availability** | Abandonware | Free / open source | Abandonware |
|
||||
| **Legacy code compat** | High (dominant compiler) | Moderate (GCC differences) | Moderate |
|
||||
|
|
|
|||
|
|
@ -1,113 +1,842 @@
|
|||
[← Home](../README.md) · [Toolchain](README.md)
|
||||
|
||||
# vasm and vlink — Assembler and Linker
|
||||
# vasm & vlink — Portable Assembler and Linker for Amiga
|
||||
|
||||
## Overview
|
||||
|
||||
**vasm** is a modern, free, multi-target assembler with excellent Amiga support. **vlink** is its companion linker. Together they form the primary open-source toolchain for 68k Amiga development.
|
||||
**vasm** is a modern, free, portable assembler by Frank Wille and Volker Barthelmann.
|
||||
|
||||
**vlink** is its companion linker.
|
||||
|
||||
Together they form the primary open-source toolchain for 68k Amiga development — replacing the proprietary Devpac/PhxAss assemblers and the aging `blink` linker from SAS/C.
|
||||
|
||||
**vasm** compiles on any host (Linux, macOS, Windows, AmigaOS, MorphOS, Atari TOS) and targets 17+ CPU families with 4 syntax dialects and 30+ output formats.
|
||||
|
||||
Unlike legacy assemblers tied to one platform, vasm's modular architecture lets you **cross-assemble** Amiga executables from a modern development machine. Combined with vlink's multi-format linking, GNU-style linker scripts, and support for Amiga hunk, ELF, a.out, and raw binary formats, this toolchain bridges retro development with modern CI/CD workflows.
|
||||
|
||||
---
|
||||
|
||||
## Architecture — The Modular Engine
|
||||
|
||||
### Three Independent Module Layers
|
||||
|
||||
vasm separates concerns into three orthogonal modules. You pick one of each at compile time:
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "Compile-Time Selection"
|
||||
CPU["CPU Module<br/>m68k, ppc, arm, x86, z80, 6502…"]
|
||||
SYNTAX["Syntax Module<br/>mot, std, madmac, oldstyle"]
|
||||
OUTPUT["Output Module<br/>hunk, elf, a.out, bin, vobj…"]
|
||||
end
|
||||
|
||||
subgraph "Runtime Pipeline"
|
||||
SRC["Source<br/>.s / .asm"] --> PARSE["Syntax Parser<br/>(SYNTAX module)"]
|
||||
PARSE --> ENCODE["Opcode Encoder<br/>(CPU module)"]
|
||||
ENCODE --> OPT["Optimizer<br/>(CPU module)"]
|
||||
OPT --> EMIT["Object Emitter<br/>(OUTPUT module)"]
|
||||
EMIT --> OBJ["Object / Binary<br/>.o / raw"]
|
||||
end
|
||||
|
||||
CPU -.-> ENCODE
|
||||
SYNTAX -.-> PARSE
|
||||
OUTPUT -.-> EMIT
|
||||
|
||||
style CPU fill:#e8f4fd,stroke:#2196f3
|
||||
style SYNTAX fill:#fff9c4,stroke:#f9a825
|
||||
style OUTPUT fill:#e8f5e9,stroke:#4caf50
|
||||
```
|
||||
|
||||
This design means the M68k backend works identically whether you write Motorola syntax (Devpac-compatible), GNU-as style (`std`), Atari MadMac syntax, or old-style 8-bit mnemonics. Adding a new CPU requires only a new CPU module — all existing syntax and output modules work immediately.
|
||||
|
||||
### CPU Modules
|
||||
|
||||
| Module | Target | Amiga Relevance |
|
||||
|---|---|---|
|
||||
| **m68k** | 68000–68060, CPU32, 68881/2, 68851 MMU, Apollo 68080 | Primary Amiga target |
|
||||
| **ppc** | POWER, 40x, 440, 6xx, 7xx, Book-E, e300, e500 | WarpOS / AmigaOS 4 |
|
||||
| **coldfire** | V2, V3, V4, V4e | Amiga clone hardware |
|
||||
| **arm** | ARMv1–v4, THUMB | Cross-platform / emulator tools |
|
||||
| **x86** | IA32 8/16/32-bit (AT&T syntax) | AROS / cross-tools |
|
||||
| **6502** | 6502, 65C02, 65816, Mega65 | Retro platforms |
|
||||
| **z80** | Z80, 8080, 8085, GBZ80 | Retro platforms |
|
||||
|
||||
### Syntax Modules
|
||||
|
||||
| Module | Style | Equivalent To |
|
||||
|---|---|---|
|
||||
| **mot** | Motorola 68k | Devpac, PhxAss, AsmOne, Barfly |
|
||||
| **std** | GNU-as AT&T | `m68k-elf-as`, `powerpc-elf-as` |
|
||||
| **madmac** | Atari MadMac | Atari ST assemblers (6502, 68k, Jaguar) |
|
||||
| **oldstyle** | Classic 8-bit | 6502/Z80 era assemblers |
|
||||
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
### From Source (All Platforms)
|
||||
|
||||
```bash
|
||||
# Build from source:
|
||||
# vasm — assembler
|
||||
wget http://sun.hasenbraten.de/vasm/release/vasm.tar.gz
|
||||
tar xzf vasm.tar.gz && cd vasm
|
||||
make CPU=m68k SYNTAX=mot # Motorola syntax
|
||||
# or:
|
||||
make CPU=m68k SYNTAX=madmac # Atari MadMac syntax
|
||||
|
||||
# vlink:
|
||||
# Build M68k with Motorola syntax (Amiga target):
|
||||
make CPU=m68k SYNTAX=mot
|
||||
# Produces: vasmm68k_mot
|
||||
|
||||
# Build with Devpac compatibility flags baked in:
|
||||
make CPU=m68k SYNTAX=mot
|
||||
# Use -devpac flag at runtime for full compatibility
|
||||
|
||||
# vlink — linker
|
||||
wget http://sun.hasenbraten.de/vlink/release/vlink.tar.gz
|
||||
tar xzf vlink.tar.gz && cd vlink && make
|
||||
tar xzf vlink.tar.gz && cd vlink
|
||||
make
|
||||
# Produces: vlink
|
||||
```
|
||||
|
||||
### Host-Specific Makefiles
|
||||
|
||||
vasm ships with platform-specific Makefiles for native Amiga and retro hosts:
|
||||
|
||||
| Makefile | Target Platform |
|
||||
|---|---|
|
||||
| `Makefile` | Linux / macOS / Unix (gcc) |
|
||||
| `Makefile.68k` | AmigaOS 68020+ (vbcc) |
|
||||
| `Makefile.OS4` | AmigaOS 4 (vbcc) |
|
||||
| `Makefile.MOS` | MorphOS (vbcc) |
|
||||
| `Makefile.WOS` | WarpOS (vbcc) |
|
||||
| `Makefile.TOS` | Atari TOS 68000 (vbcc) |
|
||||
| `Makefile.MiNT` | Atari MiNT 68020+ (vbcc) |
|
||||
| `Makefile.Win32` | Windows (MSVC) |
|
||||
| `Makefile.Win32FromLinux` | Cross-compile Windows binary from Linux |
|
||||
|
||||
### CMake Build
|
||||
|
||||
```bash
|
||||
mkdir build && cd build
|
||||
cmake -DVASM_CPU=m68k -DVASM_SYNTAX=mot ..
|
||||
make
|
||||
```
|
||||
|
||||
The resulting binary is named `vasm<CPU>_<SYNTAX>` — e.g. `vasmm68k_mot`, `vasmppc_std`.
|
||||
|
||||
### Pre-Built Binaries
|
||||
|
||||
Both daily snapshots and tagged release binaries are available from the official site for Windows, AmigaOS, MorphOS, and Linux. These are the easiest path for beginners.
|
||||
|
||||
---
|
||||
|
||||
## vasm Usage
|
||||
## vasm Usage — Comprehensive Reference
|
||||
|
||||
### Basic Invocation
|
||||
|
||||
```bash
|
||||
# Assemble to Amiga hunk object:
|
||||
vasmm68k_mot -Fhunk -o output.o input.s
|
||||
|
||||
# Common flags:
|
||||
# -Fhunk — output Amiga hunk format
|
||||
# -Fbin — raw binary
|
||||
# -Felf — ELF format
|
||||
# -m68000 — target 68000 (default)
|
||||
# -m68020 — target 68020+
|
||||
# -m68040 — target 68040
|
||||
# -m68060 — target 68060
|
||||
# -no-opt — disable optimisations
|
||||
# -I<path> — include path
|
||||
# -D<sym>=<val> — define symbol
|
||||
# -phxass — PhxAss compatibility mode
|
||||
# -devpac — Devpac compatibility mode
|
||||
```
|
||||
|
||||
---
|
||||
### Complete Flag Reference
|
||||
|
||||
## vlink Usage
|
||||
| Flag | Description |
|
||||
|---|---|
|
||||
| `-Fhunk` | Output Amiga hunk format object file |
|
||||
| `-Felf` | Output ELF object file |
|
||||
| `-Fbin` | Output raw binary (no headers, no relocations) |
|
||||
| `-Fvobj` | Output VOBJ (versatile object format, vlink-native) |
|
||||
| `-Faout` | Output a.out object file |
|
||||
| `-o <file>` | Output file name |
|
||||
| `-L <file>` | Generate listing file |
|
||||
| `-I<path>` | Add include path |
|
||||
| `-D<sym>=<val>` | Define symbol with value |
|
||||
| `-D<sym>` | Define symbol = 1 |
|
||||
| `-m68000` | Target 68000 (default) |
|
||||
| `-m68020` | Target 68020+ |
|
||||
| `-m68030` | Target 68030+ |
|
||||
| `-m68040` | Target 68040+ |
|
||||
| `-m68060` | Target 68060 |
|
||||
| `-no-opt` | Disable all assembler optimizations |
|
||||
| `-no-fpu` | Disable FPU instructions (68881/68882) |
|
||||
| `-no-mmu` | Disable MMU instructions (68851) |
|
||||
| `-devpac` | Devpac compatibility mode |
|
||||
| `-phxass` | PhxAss compatibility mode |
|
||||
| `-chklabels` | Warn on unused/redefined labels (default) |
|
||||
| `-nocase` | Case-insensitive symbols |
|
||||
| `-align` | Enable automatic alignment |
|
||||
| `-spaces` | Allow spaces in operands (Devpac compatible) |
|
||||
| `-ldots` | Accept `...` for local labels (PhxAss compatible) |
|
||||
| `-warnunaligned` | Warn on odd-address memory accesses |
|
||||
| `-quiet` | Suppress banner and progress |
|
||||
| `-version` | Print version and module info |
|
||||
|
||||
### Devpac Compatibility Mode (`-devpac`)
|
||||
|
||||
Enables the full Devpac dialect: unsigned right-shifts, named macro arguments, `OPT` directive parsing, `STRUCT`/`RS` directives with Devpac semantics, and Devpac-style local label scoping (`\@`).
|
||||
|
||||
```bash
|
||||
# Link hunk objects into executable:
|
||||
vlink -bamigahunk -o output input1.o input2.o -Llib -lexec -ldos
|
||||
|
||||
# Common flags:
|
||||
# -bamigahunk — output Amiga hunk executable
|
||||
# -brawbin1 — raw binary
|
||||
# -s — strip symbols
|
||||
# -L<path> — library search path
|
||||
# -l<lib> — link with library
|
||||
# -Rshort — use short (16-bit) relocations where possible
|
||||
vasmm68k_mot -Fhunk -devpac -o output.o input.s
|
||||
```
|
||||
|
||||
### PhxAss Compatibility Mode (`-phxass`)
|
||||
|
||||
Enables PhxAss-specific extensions: `NEAR CODE`/`NEAR DATA`, `OPT` as PhxAss directive, and PhxAss local label rules.
|
||||
|
||||
---
|
||||
|
||||
## Example: Minimal Amiga Executable
|
||||
## M68k CPU Module — Deep Dive
|
||||
|
||||
### Supported Instructions
|
||||
|
||||
Full 68000 through 68060 instruction sets including:
|
||||
- All integer instructions per CPU level
|
||||
- 68881/68882 FPU (`FMOVE`, `FADD`, `FMUL`, `FDIV`, `FSQRT`, etc.)
|
||||
- 68851 PMMU (`PLOAD`, `PTEST`, `PFLUSH`, `PMOVE`, etc.)
|
||||
- Apollo 68080 extensions (`MOVEIW`, `ADDIW`, `SUBIW`, `CMPIW`, `LPSTOP`)
|
||||
|
||||
### Automatically Selected Instruction Variants
|
||||
|
||||
When targeting higher CPUs, vasm selects the appropriate encoding automatically:
|
||||
|
||||
```asm
|
||||
; hello.s — minimal AmigaOS executable
|
||||
SECTION code,CODE
|
||||
; These produce different encodings depending on -m68000 vs -m68020:
|
||||
MOVE.L D0, (A0)+ ; 68000: MOVE.L (An)+ form
|
||||
; 68020+: uses scaled addressing if beneficial
|
||||
|
||||
MULS.L D1, D2:D3 ; 68000: ERROR (32-bit MULS requires 68020+)
|
||||
; 68020+: valid
|
||||
|
||||
BFEXTU (A0){4:8}, D0 ; 68000: ERROR
|
||||
; 68020+: valid bitfield extract
|
||||
|
||||
; Apollo 68080 special:
|
||||
ANDI.L #$FF, D0 ; -m68080: optimized to EXTUB.L D0
|
||||
```
|
||||
|
||||
### Addressing Mode Optimization
|
||||
|
||||
vasm automatically optimizes addressing modes:
|
||||
|
||||
```asm
|
||||
; Written by programmer:
|
||||
LEA label(PC), A0 ; PC-relative LEA
|
||||
MOVE.L label, D0 ; Absolute long → may relax to PC-relative
|
||||
|
||||
; vasm may rewrite:
|
||||
MOVE.L label, D0 ; → MOVE.L label(PC), D0 (shorter, position-independent)
|
||||
BRA far_target ; → JMP far_target if out of 16-bit range
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Optimization System
|
||||
|
||||
vasm performs multiple optimization passes by default. All optimizations are safe for position-independent code.
|
||||
|
||||
### Default Optimizations (always on)
|
||||
|
||||
| Optimization | Description |
|
||||
|---|---|
|
||||
| **Branch shortening** | Choose smallest encoding: `BRA.S` vs `BRA.W` vs `JMP` |
|
||||
| **Absolute → PC-relative** | Convert `MOVE.L abs, Dn` to `MOVE.L abs(PC), Dn` |
|
||||
| **Addressing mode** | Replace slower addressing with faster equivalent |
|
||||
| **LEA optimization** | Convert `LEA (An), An` to `MOVE.L An, An` |
|
||||
| **MOVEQ** | `MOVE.L #0–127, Dn` → `MOVEQ #n, Dn` |
|
||||
| **ADDQ/SUBQ** | `ADDI #1–8, Dn` → `ADDQ #n, Dn` |
|
||||
| **CLR** | `MOVE.L #0, Dn` → `CLR.L Dn` (or `MOVEQ #0, Dn`) |
|
||||
|
||||
### CPU-Specific Optimizations
|
||||
|
||||
```
|
||||
-m68020+: MOVE.W #0, (An)+ → CLR.W (An)+
|
||||
-m68040+: Use MOVE16 for block copies (when beneficial)
|
||||
-m68060: Avoid pipeline stalls (instruction reordering lite)
|
||||
-m68080: EXTUB.L, ADDIW/SUBIW, CMPIW, LPSTOP
|
||||
```
|
||||
|
||||
### Disabling Optimizations
|
||||
|
||||
```bash
|
||||
vasmm68k_mot -no-opt -Fhunk -o output.o input.s ; All optimizations off
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> Disabling optimizations is useful when comparing output with another assembler, or when generating exact byte-identical builds from known-good disassembly.
|
||||
|
||||
---
|
||||
|
||||
## vlink — Architecture & Usage
|
||||
|
||||
### Overview
|
||||
|
||||
vlink is a multi-format linker that can read and write 30+ object and executable formats. For Amiga development, its primary role is linking hunk-format object files into AmigaOS executables, but it also handles ELF→hunk conversion, binary output for ROM images, and cross-format linking.
|
||||
|
||||
### How vlink Differs from blink
|
||||
|
||||
| Feature | vlink | SAS/C blink |
|
||||
|---|---|---|
|
||||
| **Input formats** | hunk, ELF, a.out, VOBJ, TOS, o65 | hunk only |
|
||||
| **Output formats** | hunk, ELF, a.out, raw, hex, S-rec | hunk only |
|
||||
| **Linker scripts** | GNU-style `.cmd` files | Manual `FROM`/`TO` |
|
||||
| **Dead-code elimination** | `KEEP()` / garbage collection | None |
|
||||
| **Cross-platform** | Linux, macOS, Windows, Amiga | Amiga only |
|
||||
| **Active maintenance** | Yes (v0.18a, 2025) | No (abandoned 1990s) |
|
||||
|
||||
### Basic Invocation
|
||||
|
||||
```bash
|
||||
# Link hunk objects into Amiga executable:
|
||||
vlink -bamigahunk -o myapp input1.o input2.o -Llib -lexec -ldos
|
||||
|
||||
# Link with a linker script:
|
||||
vlink -bamigahunk -o myapp input.o -L. -T vlink.cmd
|
||||
```
|
||||
|
||||
### Complete Flag Reference
|
||||
|
||||
| Flag | Description |
|
||||
|---|---|
|
||||
| `-bamigahunk` | Output Amiga hunk executable |
|
||||
| `-brawbin` | Output raw binary |
|
||||
| `-belf32m68k` | Output ELF 32-bit M68k |
|
||||
| `-o <file>` | Output file name |
|
||||
| `-s` | Strip all symbols from output |
|
||||
| `-x` | Strip local symbols only |
|
||||
| `-r` | Relocatable output (partial link) |
|
||||
| `-L<path>` | Library search path |
|
||||
| `-l<lib>` | Link with library (`lib<lib>.a` or `<lib>.lib`) |
|
||||
| `-T <file>` | Use linker script |
|
||||
| `-Map <file>` | Generate link map |
|
||||
| `-Rshort` | Prefer short (16-bit) relocations |
|
||||
| `-minalign <n>` | Minimum section alignment |
|
||||
| `-nostdlib` | Don't link standard startup/libraries |
|
||||
| `-e <sym>` | Set entry point symbol |
|
||||
| `-defsym <sym>=<val>` | Define symbol |
|
||||
| `-baseoff` | Output base-relative (position-independent) |
|
||||
| `-kick1` | Kickstart 1.x compatible executable |
|
||||
| `-wfail` | Treat warnings as errors |
|
||||
|
||||
### Linker Scripts — GNU-Style Control
|
||||
|
||||
vlink linker scripts use a memory-regions + section-mapping model:
|
||||
|
||||
```ld
|
||||
/* vlink.cmd — Linker script for AmigaOS executable */
|
||||
|
||||
/* Define memory regions */
|
||||
MEMORY
|
||||
{
|
||||
CODE: ORIGIN=0x00000000 LENGTH=512K
|
||||
DATA: ORIGIN=0x00080000 LENGTH=256K
|
||||
}
|
||||
|
||||
/* Map input sections to output sections */
|
||||
SECTIONS
|
||||
{
|
||||
.text :
|
||||
{
|
||||
*(.text .text.*) /* All code sections */
|
||||
*(.rodata .rodata.*) /* Read-only data */
|
||||
KEEP(*(.init .init.*)) /* Never garbage-collect init */
|
||||
KEEP(*(.fini .fini.*))
|
||||
} > CODE
|
||||
|
||||
.data :
|
||||
{
|
||||
*(.data .data.*)
|
||||
*(COMMON)
|
||||
} > DATA
|
||||
|
||||
.bss (NOLOAD) :
|
||||
{
|
||||
*(.bss .bss.*)
|
||||
} > DATA
|
||||
|
||||
/* Constructor/destructor lists */
|
||||
VBCC_CONSTRUCTORS
|
||||
}
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> When no linker script is provided, vlink uses sensible defaults: all code sections merged into one HUNK_CODE, all data into HUNK_DATA, and BSS into HUNK_BSS.
|
||||
|
||||
### Library Resolution
|
||||
|
||||
vlink resolves library references using the standard Amiga naming conventions:
|
||||
|
||||
```bash
|
||||
# These are equivalent on Amiga:
|
||||
vlink -lamiga myapp.o -Llib:
|
||||
# Links against lib:amiga.lib
|
||||
|
||||
# -l<name> searches for <name>.lib or lib<name>.a in -L paths
|
||||
vlink -lexec -ldos myapp.o -Llib: -L.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Complete Worked Examples
|
||||
|
||||
### Example 1: Minimal Amiga Executable (Motorola Syntax)
|
||||
|
||||
```asm
|
||||
; hello.s — Minimal AmigaOS executable using vasm mot-syntax
|
||||
SECTION code,CODE
|
||||
|
||||
start:
|
||||
move.l 4.w,a6 ; ExecBase
|
||||
lea dosname(pc),a1
|
||||
moveq #0,d0
|
||||
jsr -552(a6) ; OpenLibrary
|
||||
tst.l d0
|
||||
beq.s .exit
|
||||
move.l d0,a6 ; DOSBase
|
||||
move.l 4.w,a6 ; SysBase → A6
|
||||
lea dosname(pc),a1 ; library name
|
||||
moveq #0,d0 ; any version
|
||||
jsr -552(a6) ; OpenLibrary()
|
||||
|
||||
jsr -60(a6) ; Output() → stdout handle
|
||||
move.l d0,d1
|
||||
lea msg(pc),a0
|
||||
move.l a0,d2
|
||||
moveq #12,d3
|
||||
jsr -48(a6) ; Write(fh, buf, len)
|
||||
tst.l d0
|
||||
beq.s .exit ; library not found
|
||||
move.l d0,a6 ; DOSBase → A6
|
||||
|
||||
move.l a6,a1
|
||||
move.l 4.w,a6
|
||||
jsr -414(a6) ; CloseLibrary
|
||||
; Write("Hello Amiga!\n") to stdout
|
||||
jsr -60(a6) ; Output() → stdout handle
|
||||
move.l d0,d1 ; D1 = file handle
|
||||
lea msg(pc),a0
|
||||
move.l a0,d2 ; D2 = buffer pointer
|
||||
moveq #13,d3 ; D3 = length
|
||||
jsr -48(a6) ; Write(fh, buf, len)
|
||||
|
||||
; Cleanup
|
||||
move.l a6,a1 ; DOSBase
|
||||
move.l 4.w,a6 ; SysBase → A6
|
||||
jsr -414(a6) ; CloseLibrary()
|
||||
|
||||
.exit:
|
||||
moveq #0,d0
|
||||
rts
|
||||
moveq #0,d0 ; return code
|
||||
rts
|
||||
|
||||
dosname: dc.b "dos.library",0
|
||||
msg: dc.b "Hello Amiga",10
|
||||
EVEN
|
||||
msg: dc.b "Hello Amiga!",10
|
||||
EVEN
|
||||
```
|
||||
|
||||
Build and link:
|
||||
|
||||
```bash
|
||||
vasmm68k_mot -Fhunk -o hello.o hello.s
|
||||
vlink -bamigahunk -o hello hello.o
|
||||
```
|
||||
|
||||
### Example 2: Multi-File Project with Data Section
|
||||
|
||||
```asm
|
||||
; main.s — Code hunk
|
||||
SECTION code,CODE
|
||||
xdef _start
|
||||
|
||||
_start:
|
||||
move.l 4.w,a6
|
||||
lea libname(pc),a1
|
||||
moveq #0,d0
|
||||
jsr -552(a6) ; OpenLibrary("dos.library")
|
||||
move.l d0,a5
|
||||
beq .exit
|
||||
|
||||
; Print pre-initialized string from data section
|
||||
jsr -60(a5) ; Output()
|
||||
move.l d0,d1
|
||||
lea message,a0 ; Absolute reference → needs reloc
|
||||
move.l a0,d2
|
||||
moveq #msg_len,d3
|
||||
jsr -48(a5) ; Write()
|
||||
|
||||
move.l a5,a1
|
||||
move.l 4.w,a6
|
||||
jsr -414(a6) ; CloseLibrary()
|
||||
.exit: moveq #0,d0
|
||||
rts
|
||||
|
||||
libname: dc.b "dos.library",0
|
||||
|
||||
; data.s — Data hunk
|
||||
SECTION data,DATA
|
||||
xdef message,msg_len
|
||||
|
||||
message: dc.b "Hello from DATA hunk!",10
|
||||
msg_len equ *-message
|
||||
```
|
||||
|
||||
Build:
|
||||
|
||||
```bash
|
||||
vasmm68k_mot -Fhunk -o main.o main.s
|
||||
vasmm68k_mot -Fhunk -o data.o data.s
|
||||
vlink -bamigahunk -o myapp main.o data.o
|
||||
```
|
||||
|
||||
### Example 3: Calling C from Assembly (vbcc Integration)
|
||||
|
||||
```asm
|
||||
; asm_part.s — Assembly file linked with C
|
||||
SECTION code,CODE
|
||||
xdef _Multiply
|
||||
; int32_t Multiply(int32_t a, int32_t b);
|
||||
; Args: D0 = a, D1 = b. Return: D0
|
||||
|
||||
_Multiply:
|
||||
muls.l d1,d0 ; D0 = a * b (requires 68020+)
|
||||
rts
|
||||
|
||||
xdef _SwapBytes
|
||||
; uint32_t SwapBytes(uint32_t val);
|
||||
; Args: D0 = val. Return: D0
|
||||
|
||||
_SwapBytes:
|
||||
ror.w #8,d0
|
||||
swap d0
|
||||
ror.w #8,d0
|
||||
rts
|
||||
```
|
||||
|
||||
```c
|
||||
// main.c — C file compiled with vbcc
|
||||
extern int32_t Multiply(int32_t a, int32_t b);
|
||||
extern uint32_t SwapBytes(uint32_t val);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int32_t result = Multiply(7, 6); // → 42
|
||||
uint32_t swapped = SwapBytes(0x12345678); // → 0x78563412
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
Build with vasm + vbcc + vlink:
|
||||
|
||||
```bash
|
||||
vasmm68k_mot -Fhunk -m68020 -o asm_part.o asm_part.s
|
||||
vc +aos68k -c main.c -o main.o
|
||||
vlink -bamigahunk -o program main.o asm_part.o -L$VBCC/ targets/m68k-amigaos/lib -lvc
|
||||
```
|
||||
|
||||
### Example 4: Linker Script for ROM Image
|
||||
|
||||
```asm
|
||||
; rom.s — Code for a ROM image (absolute addressing)
|
||||
SECTION rom_code,CODE
|
||||
org $00F80000 ; ROM base in Amiga address space
|
||||
|
||||
ROM_Entry:
|
||||
move.w #$4EF9,(ROM_Jump) ; JMP opcode
|
||||
lea InitCode(pc),a0
|
||||
move.l a0,(ROM_Jump+2)
|
||||
jmp InitCode
|
||||
ROM_Jump: ds.l 2
|
||||
|
||||
InitCode:
|
||||
; Hardware initialization
|
||||
lea $DFF000,a0
|
||||
move.w #$7FFF,$9A(a0) ; Disable all interrupts
|
||||
; ... more init ...
|
||||
rts
|
||||
```
|
||||
|
||||
```ld
|
||||
/* rom.cmd — Linker script for ROM binary */
|
||||
MEMORY
|
||||
{
|
||||
ROM: ORIGIN=0x00F80000 LENGTH=512K
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text :
|
||||
{
|
||||
*(.text .text.*)
|
||||
} > ROM
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
vasmm68k_mot -Fhunk -o rom.o rom.s
|
||||
vlink -brawbin -T rom.cmd -o kickstart.rom rom.o
|
||||
```
|
||||
|
||||
### Example 5: Macros and Conditional Assembly
|
||||
|
||||
```asm
|
||||
; macros.i — Include file demonstrating vasm macro features
|
||||
|
||||
; Debug print macro (conditional on DEBUG symbol)
|
||||
ifd DEBUG
|
||||
DEBUG_PRINT macro
|
||||
movem.l d0-d1/a0-a1,-(sp)
|
||||
move.l \1,d1 ; file handle
|
||||
lea \2(pc),a0 ; string
|
||||
move.l a0,d2
|
||||
moveq #\3,d3 ; length
|
||||
jsr -48(a6)
|
||||
movem.l (sp)+,d0-d1/a0-a1
|
||||
endm
|
||||
else
|
||||
DEBUG_PRINT macro
|
||||
; No-op when DEBUG not defined
|
||||
endm
|
||||
endc
|
||||
|
||||
; Struct definition using RS directives
|
||||
STRUCTURE Player,0
|
||||
LONG px,py ; Position
|
||||
WORD hp ; Hit points
|
||||
BYTE alive ; 0 = dead, 1 = alive
|
||||
BYTE pad
|
||||
LONG sprite_ptr ; Pointer to sprite data
|
||||
sizeof Player_SIZE
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Comparison with Other Amiga Assemblers
|
||||
|
||||
### Feature Matrix
|
||||
|
||||
| Feature | vasm | Devpac 3 | PhxAss 4 | AsmOne | Barfly |
|
||||
|---|---|---|---|---|---|
|
||||
| **Free / Open Source** | ✓ | ✗ | ✓ | ✗ | ✗ |
|
||||
| **Cross-platform host** | ✓ | ✗ | ✗ | ✗ | ✗ |
|
||||
| **M68k up to 68060** | ✓ | 68030 | 68040+FPU | 68060 | 68060 |
|
||||
| **68080 (Apollo)** | ✓ | ✗ | ✗ | ✗ | ✗ |
|
||||
| **Automatic optimizations** | ✓ | ✗ | ✗ | ✗ | ✗ |
|
||||
| **Branch relaxation** | ✓ | ✗ | ✗ | ✗ | ✓ |
|
||||
| **Macro system** | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| **Multiple output formats** | 30+ | 1 (hunk) | 1 (hunk) | 1 (hunk) | 2 |
|
||||
| **Linker** | vlink (multi-format) | blink | blink | blink | blink |
|
||||
| **Linker scripts** | ✓ | ✗ | ✗ | ✗ | ✗ |
|
||||
| **Active development** | ✓ (2026) | ✗ (1994) | ✗ (1998) | ✗ (1996) | ✗ (2000) |
|
||||
| **IDE / debugger** | ✗ | ✓ (MonAm) | ✗ | ✓ (built-in) | ✗ |
|
||||
|
||||
### When to Choose Each
|
||||
|
||||
| Assembler | Best For |
|
||||
|---|---|
|
||||
| **vasm** | Cross-development, modern CI/CD, multi-platform projects, optimizing for size |
|
||||
| **Devpac** | Native Amiga development with MonAm debugger, legacy source compatibility |
|
||||
| **PhxAss** | Legacy source that uses `NEAR CODE`/`NEAR DATA` or PhxAss-specific macros |
|
||||
| **AsmOne** | Interactive debugging on native hardware, quick test cycles |
|
||||
| **Barfly** | Legacy projects already using Barfly-specific features |
|
||||
|
||||
---
|
||||
|
||||
## Integration with the Amiga Toolchain
|
||||
|
||||
vasm and vlink are the assembler/linker pair used by **vbcc** and **bebbo's GCC 6.x toolchain**. The typical workflow:
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
subgraph "Compiler Path (C)"
|
||||
C_SRC["main.c"] --> VBCC["vbcc / gcc"]
|
||||
VBCC --> C_OBJ["main.o (hunk)"]
|
||||
end
|
||||
|
||||
subgraph "Assembler Path (Asm)"
|
||||
ASM_SRC["code.s"] --> VASM["vasmm68k_mot"]
|
||||
VASM --> ASM_OBJ["code.o (hunk)"]
|
||||
end
|
||||
|
||||
C_OBJ --> VLINK["vlink"]
|
||||
ASM_OBJ --> VLINK
|
||||
VLINK --> EXE["Executable (hunk)"]
|
||||
|
||||
style VASM fill:#fff9c4,stroke:#f9a825
|
||||
style VLINK fill:#e8f4fd,stroke:#2196f3
|
||||
```
|
||||
|
||||
### Companion Tools
|
||||
|
||||
| Tool | Role | Integration |
|
||||
|---|---|---|
|
||||
| [vbcc](vbcc.md) | C compiler | Uses vasm as assembler, vlink as linker |
|
||||
| **bebbo's GCC** | C/C++ cross-compiler | Uses vasm/vlink (configurable) |
|
||||
| **IRA** | Disassembler → reassembler | Emits vasm-compatible Motorola syntax |
|
||||
| **Aira Force** | Reassembler pipeline | Uses vasm as reassembly engine |
|
||||
| [FD files](fd_files.md) | Library jump table generation | Used with `fd2pragma` → C headers |
|
||||
|
||||
---
|
||||
|
||||
## Decision Guide — When to Use vasm/vlink
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["Starting an Amiga<br/>asm project?"] --> B{"Cross-compiling from<br/>modern OS?"}
|
||||
B -->|Yes| C["✅ vasm/vlink<br/>(only option)"]
|
||||
B -->|No| D{"Need optimizing<br/>assembler?"}
|
||||
D -->|Yes| E["✅ vasm/vlink"]
|
||||
D -->|No| F{"Need interactive<br/>debugger?"}
|
||||
F -->|Yes| G["AsmOne or Devpac<br/>(native only)"]
|
||||
F -->|No| H{"Legacy source<br/>compatibility?"}
|
||||
H -->|Devpac| I["vasm -devpac<br/>or Devpac 3"]
|
||||
H -->|PhxAss| J["vasm -phxass<br/>or PhxAss 4"]
|
||||
H -->|No| K["✅ vasm/vlink<br/>(recommended)"]
|
||||
|
||||
style C fill:#e8f5e9,stroke:#4caf50
|
||||
style E fill:#e8f5e9,stroke:#4caf50
|
||||
style K fill:#e8f5e9,stroke:#4caf50
|
||||
```
|
||||
|
||||
### When to Use vasm/vlink
|
||||
|
||||
1. **Cross-compiling** from Linux, macOS, or Windows — native assemblers won't run
|
||||
2. **New Amiga projects** — no legacy constraints, modern toolchain from day one
|
||||
3. **Integrating C and assembly** — vlink handles mixed-language linking cleanly
|
||||
4. **Automated builds / CI/CD** — command-line only, no GUI dependency
|
||||
5. **Targeting 68020+ features** — vasm has better 020/030/040/060 support than legacy assemblers
|
||||
6. **ROM / absolute code** — vlink linker scripts give precise memory layout control
|
||||
7. **Size optimization** — vasm's automatic optimization often produces smaller code than hand-tuned assembly
|
||||
|
||||
### When NOT to Use vasm/vlink
|
||||
|
||||
1. **Interactive debugging on native hardware** — AsmOne's built-in debugger (breakpoints, single-step, register dump) has no equivalent in the vasm/vlink workflow
|
||||
2. **Legacy source with undocumented Devpac quirks** — some old source relies on Devpac bugs or undocumented behavior that `-devpac` mode doesn't replicate
|
||||
3. **Macro-heavy PhxAss source** — PhxAss has a unique macro syntax parser; `-phxass` mode covers most but not all edge cases
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Always specify `-Fhunk` explicitly** — don't rely on defaults; be explicit about output format
|
||||
2. **Use `-devpac` for legacy source** — avoids porting Devpac-specific directives by hand
|
||||
3. **Let the optimizer work** — don't disable optimizations unless debugging output differences
|
||||
4. **Use `xdef`/`xref` consistently** — vasm enforces symbol visibility; undeclared `xref` symbols generate warnings (use `-chklabels` to catch typos)
|
||||
5. **Separate code and data into sections** — use `SECTION code,CODE` and `SECTION data,DATA` for proper hunk separation
|
||||
6. **Use a linker script for complex layouts** — ROM images, overlay systems, and custom memory maps benefit from explicit script control
|
||||
7. **Build both debug and release configurations** — use `-DDEBUG` for conditional debug code (see Example 5)
|
||||
8. **Pin tool versions for reproducibility** — vasm/vlink are actively developed; use the same version in CI that you develop with
|
||||
|
||||
### Antipatterns
|
||||
|
||||
| Antipattern | Why It's Wrong | Correct Approach |
|
||||
|---|---|---|
|
||||
| **The Vanishing Reference** | Using `xref` but forgetting to actually provide the symbol in another object → linker error at final link | `xdef` the symbol in exactly one source file; verify with `-Map` output |
|
||||
| **The Mixed Syntax** | Writing half Devpac, half GNU-as syntax in the same file | Pick one syntax module (`mot` or `std`) at project start and stick with it |
|
||||
| **The Naked ORG** | Using `org` without a linker script → sections overlap silently | Use linker scripts (`-T`) to define memory regions for absolute code |
|
||||
| **The Optimization Gambler** | Disabling optimizations everywhere for "consistency" → larger, slower code | Only disable per-file when debugging output differences; use `-no-opt` surgically |
|
||||
| **The Sectionless Source** | Not declaring sections → all code goes into a default unnamed section → no control over hunk layout | Always use `SECTION name,type` at the top of each file |
|
||||
|
||||
---
|
||||
|
||||
## Pitfalls
|
||||
|
||||
### 1. Case Sensitivity of Symbols
|
||||
|
||||
vasm symbols are case-sensitive by default. Devpac was case-insensitive. If you get "undefined symbol" errors when assembling old Devpac source:
|
||||
|
||||
```bash
|
||||
# Fix: enable case-insensitive mode
|
||||
vasmm68k_mot -Fhunk -nocase -o output.o input.s
|
||||
```
|
||||
|
||||
### 2. Section Attributes for Hunk Output
|
||||
|
||||
The hunk output module reads the **second argument** of the `SECTION` directive to determine the hunk type:
|
||||
|
||||
```asm
|
||||
SECTION code,CODE ; → HUNK_CODE ($3E9)
|
||||
SECTION data,DATA ; → HUNK_DATA ($3EA)
|
||||
SECTION bss,BSS ; → HUNK_BSS ($3EB) — zero-filled, no content emitted
|
||||
```
|
||||
|
||||
Using `SECTION text,CODE` (GNU convention) works but `SECTION mycode` (no type) produces a generic hunk that may confuse the Amiga loader.
|
||||
|
||||
### 3. Absolute vs PC-Relative References
|
||||
|
||||
vasm may convert absolute references to PC-relative silently. This is correct behavior but can surprise developers inspecting the binary:
|
||||
|
||||
```asm
|
||||
MOVE.L MyData, D0 ; May become MOVE.L MyData(PC), D0
|
||||
```
|
||||
|
||||
If you need an absolute reference (e.g., writing to custom chip registers at fixed addresses), it will remain absolute. Only relocatable symbols are eligible for conversion.
|
||||
|
||||
### 4. Library Resolution Order
|
||||
|
||||
vlink resolves libraries **left-to-right**. If `libA` depends on symbols from `libB`, `libB` must appear after `libA` on the command line:
|
||||
|
||||
```bash
|
||||
# WRONG: libA needs libB symbols, but libB is searched first
|
||||
vlink -bamigahunk -o app main.o -lB -lA
|
||||
|
||||
# CORRECT: libA searched first, then libB resolves its dependencies
|
||||
vlink -bamigahunk -o app main.o -lA -lB
|
||||
```
|
||||
|
||||
### 5. Kickstart 1.x Compatibility
|
||||
|
||||
AmigaOS 1.x (`kickstart 1.2`/`1.3`) has a simpler hunk loader. Use the `-kick1` flag to generate compatible executables:
|
||||
|
||||
```bash
|
||||
vlink -bamigahunk -kick1 -o app main.o -lamiga
|
||||
```
|
||||
|
||||
Without this flag, vlink may emit hunk structures (HUNK_RELRELOC32, HUNK_DEBUG, HUNK_BREAK) that Kickstart 1.x doesn't understand.
|
||||
|
||||
---
|
||||
|
||||
## Historical Context
|
||||
|
||||
### The Assembler Landscape (1985–1995)
|
||||
|
||||
In the Amiga's commercial era, developers chose between several closed-source assemblers:
|
||||
|
||||
| Assembler | Era | Developer | Fate |
|
||||
|---|---|---|---|
|
||||
| **AssemPro** | 1986–1990 | Softec | Abandoned |
|
||||
| **A68k** | 1987–1992 | Alpha Software | Abandoned |
|
||||
| **ArgAsm** | 1987–1991 | Argonaut Software | Abandoned |
|
||||
| **Devpac** | 1989–1994 | HiSoft | Abandoned |
|
||||
| **AsmOne** | 1991–1996 | Rune Gram-Madsen | Abandoned |
|
||||
| **Barfly** | 1993–2000 | K. J. Down | Abandoned |
|
||||
| **PhxAss** | 1993–1998 | Frank Wille | Became vasm foundation |
|
||||
|
||||
PhxAss, also by Frank Wille, was the direct ancestor of vasm. When vbcc (by Volker Barthelmann) needed a portable assembler that could run on any host, the PhxAss compiler code was refactored into the modular vasm architecture. The M68k + mot-syntax combination retains deep PhxAss/Devpac compatibility.
|
||||
|
||||
### Modern Relevance
|
||||
|
||||
vasm/vlink are now the de facto standard assembler/linker for:
|
||||
- The **Amiga demo scene** — size-constrained productions (4K/64K intros, demos)
|
||||
- **MiSTer FPGA** and Minimig development — cross-compiling from ARM/Linux
|
||||
- **AmigaOS 4** and **MorphOS** development — vasm targets PPC, vlink handles EHF and ELF
|
||||
- **Game preservation** — reassembling disassembled game code with IRA → vasm → vlink
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- vasm: http://sun.hasenbraten.de/vasm/
|
||||
- vlink: http://sun.hasenbraten.de/vlink/
|
||||
### Official Sources
|
||||
|
||||
- **vasm home**: http://sun.hasenbraten.de/vasm/
|
||||
- **vlink home**: http://sun.hasenbraten.de/vlink/
|
||||
- **vbcc home**: http://sun.hasenbraten.de/vbcc/ (vasm/vlink are part of this toolchain)
|
||||
- **vasm manual (PDF)**: http://sun.hasenbraten.de/vasm/release/vasm.pdf
|
||||
- **vlink manual (PDF)**: http://sun.hasenbraten.de/vlink/release/vlink.pdf
|
||||
|
||||
### GitHub Mirrors & Community Repos
|
||||
|
||||
| Repository | Description |
|
||||
|---|---|
|
||||
| [retro-vault/vasm](https://github.com/retro-vault/vasm) | Git mirror of vasm — updated regularly |
|
||||
| [retro-vault/vlink](https://github.com/retro-vault/vlink) | Git mirror of vlink — updated regularly |
|
||||
| [StarWolf3000/vasm-mirror](https://github.com/StarWolf3000/vasm-mirror) | Git mirror of vasm (formerly hosted at mbitsnbites) |
|
||||
| [dbuchwald/vasm](https://github.com/dbuchwald/vasm) | Git mirror with CI integration |
|
||||
| [ezrec/vasm](https://github.com/ezrec/vasm) | Mirror with additional CPU backends |
|
||||
| [kusma/amiga-dev](https://github.com/kusma/amiga-dev) | Pre-packaged Amiga dev environment (VBCC + vasm + vlink + PosixLib) |
|
||||
|
||||
### Related Articles in This Knowledge Base
|
||||
|
||||
- [vbcc](vbcc.md) — C compiler that uses vasm/vlink as its assembler/linker
|
||||
- [gcc_amiga.md](gcc_amiga.md) — bebbo's GCC toolchain (configurable to use vasm/vlink)
|
||||
- [FD files](fd_files.md) — FD/SFD file format; `fd2pragma` generates C headers used with vbcc+vasm
|
||||
- [Makefiles](makefiles.md) — Makefile patterns for vasm/vlink and mixed C+asm projects
|
||||
- [HUNK Format](../03_loader_and_exec_format/hunk_format.md) — The executable format vlink outputs and vasm can emit
|
||||
- [Debugging](debugging.md) — Tools that work with vasm/vlink output (Enforcer, SnoopDOS, FS-UAE GDB)
|
||||
- [Register Conventions](../04_linking_and_libraries/register_conventions.md) — ABI for C↔asm interop with vbcc
|
||||
|
||||
### Community Resources
|
||||
|
||||
- **English Amiga Board (EAB)**: Active forum with vasm/vlink troubleshooting threads
|
||||
- **Atari-Forum**: Cross-platform vasm/vlink discussions (many Amiga developers also target Atari)
|
||||
- **AmigaSource**: Curated link collection pointing to vasm/vlink resources
|
||||
- **Reaktor Crash Course**: Tutorial for Amiga assembly with vasm: https://www.reaktor.com/insights-and-events/crash-course-to-amiga-assembly-programming
|
||||
|
|
|
|||
703
13_toolchain/vbcc.md
Normal file
703
13_toolchain/vbcc.md
Normal file
|
|
@ -0,0 +1,703 @@
|
|||
[← Home](../README.md) · [Toolchain](README.md)
|
||||
|
||||
# VBCC — Volker Barthelmann's Portable C Compiler for AmigaOS
|
||||
|
||||
## Overview
|
||||
|
||||
**VBCC** is a portable, retargetable ISO C89 compiler created by **Volker Barthelmann** in the mid-1990s. It is the second most widely used cross-compiler for AmigaOS after GCC bebbo, and unlike GCC it was designed from the ground up as a lightweight, fast compiler with aggressively optimized code generation. The Amiga m68k backend (`vbccm68k`) is actively maintained and supports AmigaOS 3.x, AmigaOS 4, MorphOS, and AROS from a single toolchain.
|
||||
|
||||
The defining feature of VBCC on Amiga is the **`__reg()` storage class** — a compiler extension that lets C programmers explicitly place variables and function arguments in specific 68000 registers. This maps naturally onto the AmigaOS register-based library calling convention, making OS API calls intuitive without the macro gymnastics required by GCC inline assembly.
|
||||
|
||||
Key constraints:
|
||||
- **C89 only** — no C++, no GNU extensions (use `-c99` for limited C99 support)
|
||||
- **Cross-compiler** — runs on Linux, macOS, Windows; no native Amiga IDE
|
||||
- **vlink required** — VBCC does not use GNU `ld`; it links with `vlink` (also by the vbcc team)
|
||||
- **Config-driven** — target behavior is controlled by text config files in `vbcc/config/`
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
### Compiler Pipeline
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph "Frontend"
|
||||
SRC["Source (.c)"]
|
||||
VC["vc (driver)"]
|
||||
PP["Preprocessor"]
|
||||
FE["Parser / IR Generator"]
|
||||
end
|
||||
|
||||
subgraph "Backend"
|
||||
CG["vbccm68k\nCode Generator"]
|
||||
OPT["Peephole Optimizer"]
|
||||
end
|
||||
|
||||
subgraph "Linker"
|
||||
VL["vlink"]
|
||||
OBJ["Object (.o)"]
|
||||
EXE["Amiga HUNK"]
|
||||
end
|
||||
|
||||
SRC --> VC
|
||||
VC --> PP --> FE --> CG --> OPT --> OBJ
|
||||
OBJ --> VL --> EXE
|
||||
|
||||
style CG fill:#e8f4fd,stroke:#2196f3,color:#333
|
||||
style VL fill:#fff9c4,stroke:#f9a825,color:#333
|
||||
```
|
||||
|
||||
### The Config System
|
||||
|
||||
VBCC uses **text-based target configuration files** rather than hardcoded backend behavior. The driver `vc` reads `vbcc/config/` to determine which preprocessor, compiler, assembler, and linker to invoke:
|
||||
|
||||
```
|
||||
vbcc/
|
||||
bin/
|
||||
vc ; frontend driver
|
||||
vbccm68k ; m68k code generator
|
||||
config/
|
||||
m68k-amigaos ; AmigaOS 3.x target config
|
||||
m68k-amigaos4 ; AmigaOS 4 target
|
||||
ppc-amigaos ; PPC MorphOS / AmigaOS 4
|
||||
targets/
|
||||
m68k-amigaos/
|
||||
; startup code, runtime libraries
|
||||
```
|
||||
|
||||
The config file (`m68k-amigaos`) is a plain-text script that tells `vc`:
|
||||
- Which preprocessor flags to pass
|
||||
- Which code generator binary to run (`vbccm68k`)
|
||||
- Which assembler syntax to emit (Motorola)
|
||||
- Which linker (`vlink`) and which linker script
|
||||
- Default include paths and library paths
|
||||
|
||||
This design means adding a new Amiga-like target requires only a new config file and a backend — no recompilation of the compiler itself.
|
||||
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
### Linux / macOS Cross-Compiler Setup
|
||||
|
||||
```bash
|
||||
# 1. Download latest binaries from vbcc homepage:
|
||||
# http://sun.hasenbraten.de/vbcc/
|
||||
|
||||
# 2. Extract and set environment:
|
||||
export VBCC=/opt/vbcc
|
||||
export PATH=$VBCC/bin:$PATH
|
||||
|
||||
# 3. Untar the m68k-amigaos target archive into $VBCC/
|
||||
# This populates targets/m68k-amigaos/ with startup code and libs
|
||||
|
||||
# 4. Verify:
|
||||
vc +m68k-amigaos -v hello.c
|
||||
# Should compile and link to Amiga hunk format
|
||||
```
|
||||
|
||||
### Windows (MSYS2 / WSL)
|
||||
|
||||
The same binaries work under WSL. For native Windows, use the provided `vc.exe` and `vlink.exe` with MinGW or MSYS2 paths.
|
||||
|
||||
---
|
||||
|
||||
## The `__reg()` Storage Class
|
||||
|
||||
VBCC's most powerful Amiga-specific extension is `__reg()`, which places C variables in named CPU registers. This eliminates the need for inline assembly wrappers when calling AmigaOS libraries.
|
||||
|
||||
### Basic Syntax
|
||||
|
||||
```c
|
||||
/* Place a variable in register D0 */
|
||||
int __reg("d0") result;
|
||||
|
||||
/* Place a pointer in register A0 */
|
||||
char * __reg("a0") buffer;
|
||||
|
||||
/* Function with register arguments — matches AmigaOS .fd conventions */
|
||||
BPTR __reg("d0") MyOpen(
|
||||
__reg("d1") CONST_STRPTR name,
|
||||
__reg("d2") LONG accessMode);
|
||||
```
|
||||
|
||||
### AmigaOS Library Call Example
|
||||
|
||||
```c
|
||||
#include <proto/dos.h>
|
||||
|
||||
/* Without __reg() — compiler uses stack, stub fixes it up */
|
||||
/* With __reg() — compiler generates exact register layout */
|
||||
|
||||
struct DosLibrary *DOSBase;
|
||||
|
||||
void writeHello(void)
|
||||
{
|
||||
BPTR fh = Open("CON:0/0/640/200/Hello", MODE_NEWFILE);
|
||||
if (fh)
|
||||
{
|
||||
char msg[] = "Hello from VBCC\n";
|
||||
Write(fh, msg, sizeof(msg) - 1);
|
||||
Close(fh);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `<proto/dos.h>` header for VBCC uses `__reg()` internally:
|
||||
|
||||
```c
|
||||
/* proto/dos.h (VBCC version) — simplified */
|
||||
#pragma amicall(DOSBase, 0x1E, Open(__reg("d1") CONST_STRPTR name,
|
||||
__reg("d2") LONG accessMode))
|
||||
```
|
||||
|
||||
This produces the same machine code as hand-written assembly:
|
||||
|
||||
```asm
|
||||
; VBCC-generated code for Open("foo", MODE_OLDFILE):
|
||||
MOVEA.L _DOSBase, A6
|
||||
LEA .str_foo, A0
|
||||
MOVE.L A0, D1 ; name → D1
|
||||
MOVEQ #1002, D2 ; MODE_OLDFILE → D2
|
||||
JSR -30(A6) ; Open() LVO = -30
|
||||
; D0 = file handle
|
||||
```
|
||||
|
||||
### Register Allocation Rules
|
||||
|
||||
| Register | `__reg()` String | Safe For |
|
||||
|---|---|---|
|
||||
| D0 | `"d0"` | Return values, scratch |
|
||||
| D1–D7 | `"d1"` … `"d7"` | Arguments, local variables |
|
||||
| A0 | `"a0"` | Arguments, scratch pointers |
|
||||
| A1–A3 | `"a1"` … `"a3"` | Arguments |
|
||||
| A4 | `"a4"` | Small-data base (see below) |
|
||||
| A5 | `"a5"` | Frame pointer (rarely used) |
|
||||
| A6 | `"a6"` | Library base (OS calls only) |
|
||||
| A7 | `"a7"` | Stack pointer — **never use** |
|
||||
|
||||
> [!WARNING]
|
||||
> `__reg("a6")` is reserved for library base pointers during OS calls. Using it for general variables will corrupt the next `JSR -LVO(A6)` and crash. `__reg("a7")` is the stack pointer — the compiler will reject this or generate broken code.
|
||||
|
||||
---
|
||||
|
||||
## Pragmas and FD File Conversion
|
||||
|
||||
### VBCC Pragma Format
|
||||
|
||||
VBCC pragmas are simpler than SAS/C's numeric encoding:
|
||||
|
||||
```c
|
||||
/* dos_pragmas.h for VBCC */
|
||||
#pragma amicall(DOSBase, 0x1E, Open(d1,d2))
|
||||
#pragma amicall(DOSBase, 0x24, Close(d1))
|
||||
#pragma amicall(DOSBase, 0x2A, Read(d1,d2,d3))
|
||||
```
|
||||
|
||||
- `0x1E` = LVO offset (hex) — the compiler computes the actual JSR offset
|
||||
- `Open(d1,d2)` = function name and argument registers (left to right)
|
||||
- The compiler generates `__reg()` assignments automatically
|
||||
|
||||
### Converting FD Files with `cvinclude.pl`
|
||||
|
||||
VBCC ships `cvinclude.pl` — a Perl script that converts Amiga `.fd` files into VBCC pragma headers:
|
||||
|
||||
```bash
|
||||
# Generate VBCC pragmas from an FD file:
|
||||
cvinclude.pl -v -a dos_lib.fd > dos_pragmas.h
|
||||
|
||||
# Generate inline-style prototypes:
|
||||
cvinclude.pl -v -i exec_lib.fd > exec_inline.h
|
||||
```
|
||||
|
||||
| Tool | Input | Output | Compiler |
|
||||
|---|---|---|---|
|
||||
| `fd2pragma` | `.fd` | SAS/C `#pragma libcall` | SAS/C |
|
||||
| `fd2inline` | `.fd` | GCC inline asm | GCC |
|
||||
| `cvinclude.pl` | `.fd` | VBCC `#pragma amicall` | VBCC |
|
||||
|
||||
---
|
||||
|
||||
## Compilation Workflow
|
||||
|
||||
### Command-Line Usage
|
||||
|
||||
```bash
|
||||
# Compile and link in one step:
|
||||
vc +m68k-amigaos -o myapp myapp.c
|
||||
|
||||
# Compile only (object file):
|
||||
vc +m68k-amigaos -c -o myapp.o myapp.c
|
||||
|
||||
# Link separately:
|
||||
vlink -bamigahunk -o myapp myapp.o -L/opt/vbcc/targets/m68k-amigaos/lib -lamiga
|
||||
```
|
||||
|
||||
### Common Flags
|
||||
|
||||
| Flag | Description |
|
||||
|---|---|
|
||||
| `+m68k-amigaos` | Select AmigaOS 3.x target config |
|
||||
| `+m68k-amigaos4` | Select AmigaOS 4 target |
|
||||
| `-O` | Enable optimizations |
|
||||
| `-speed` | Optimize for speed (aggressive inlining, loop unrolling) |
|
||||
| `-size` | Optimize for code size |
|
||||
| `-m68000` | Target plain 68000 (default) |
|
||||
| `-m68020` | Target 68020+ |
|
||||
| `-m68030` | Target 68030 |
|
||||
| `-m68040` | Target 68040 |
|
||||
| `-m68060` | Target 68060 |
|
||||
| `-fpu` | Enable FPU instructions (68881/68882/040/060) |
|
||||
| `-c99` | Enable C99 features (limited support) |
|
||||
| `-I<path>` | Add include path |
|
||||
| `-L<path>` | Add library path |
|
||||
| `-l<lib>` | Link with library |
|
||||
| `-g` | Include debug info (HUNK_DEBUG) |
|
||||
| `-s` | Strip symbols |
|
||||
| `-v` | Verbose output |
|
||||
| `-k` | Keep intermediate files |
|
||||
|
||||
### CPU Target Decision Matrix
|
||||
|
||||
| Target | Use When | Code Size | Notes |
|
||||
|---|---|---|---|
|
||||
| `-m68000` | A500, A1000, A2000, CDTV | Smallest | No 32-bit multiply/divide in hardware |
|
||||
| `-m68020` | A1200, A3000, A4000/030 | Medium | `MULS.L`, `DIVS.L`, `BFEXTU` available |
|
||||
| `-m68030` | A4000/030, accelerated systems | Medium | Adds `MMU` instructions (rarely used) |
|
||||
| `-m68040` | 040 accelerators | Larger | Hardware FPU; disable with `-m68040 -no-fpu` for LC/EC |
|
||||
| `-m68060` | 060 accelerators | Largest | Superscalar; some instructions emulated in software |
|
||||
|
||||
---
|
||||
|
||||
## Startup Code and Runtime
|
||||
|
||||
VBCC provides several startup modules for different application types:
|
||||
|
||||
| Startup Module | Use For | Notes |
|
||||
|---|---|---|
|
||||
| `minstart.o` | Minimal CLI programs | No C library; smallest possible binary |
|
||||
| `amiga.o` / `startup.o` | Standard CLI programs | Opens DOS, sets up stdin/stdout |
|
||||
| `wbstart.o` | Workbench programs | Handles WBStartup message, tooltypes |
|
||||
| `libinit.o` | Shared libraries | RTF_AUTOINIT compatible entry point |
|
||||
|
||||
The startup module is linked automatically by the target config unless you override it.
|
||||
|
||||
```bash
|
||||
# Link with custom startup (no default C runtime):
|
||||
vc +m68k-amigaos -nostdlib -o raw.bin main.c minstart.o
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## VBCC vs. GCC vs. SAS/C
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph "Compiler"
|
||||
V["VBCC"]
|
||||
G["GCC bebbo"]
|
||||
S["SAS/C 6.58"]
|
||||
end
|
||||
|
||||
subgraph "Code Style"
|
||||
VREG["__reg(d1) args"]
|
||||
GASM["inline asm stubs"]
|
||||
SPRA["#pragma libcall"]
|
||||
end
|
||||
|
||||
subgraph "Output"
|
||||
HUNK["Amiga HUNK"]
|
||||
end
|
||||
|
||||
V --> VREG --> HUNK
|
||||
G --> GASM --> HUNK
|
||||
S --> SPRA --> HUNK
|
||||
|
||||
style V fill:#e8f4fd,stroke:#2196f3,color:#333
|
||||
style G fill:#c8e6c9,stroke:#2e7d32,color:#333
|
||||
style S fill:#fff9c4,stroke:#f9a825,color:#333
|
||||
```
|
||||
|
||||
| Feature | VBCC | GCC bebbo | SAS/C 6.58 | Clang/LLVM (conceptual) |
|
||||
|---|---|---|---|---|
|
||||
| **License** | Free (personal use) | GPL | Commercial (abandonware) | Apache 2.0 |
|
||||
| **Host OS** | Linux, macOS, Windows | Linux, macOS, Windows | AmigaOS only | Linux, macOS, Windows |
|
||||
| **C standard** | C89 (+ `-c99` partial) | C11 (GCC 6.5) | C89 | C11/C17/C23 |
|
||||
| **C++** | No | Yes | No | Yes (full C++20/23) |
|
||||
| **Register control** | `__reg()` | `__asm("d1")` inline | `#pragma libcall` | Not needed (no m68k backend) |
|
||||
| **Code quality** | Excellent, tight | Good, mature | Good (best for 1980s-era 68000) | Excellent (LLVM optimizer) |
|
||||
| **Optimizations** | Aggressive peephole | GCC -O3 | Global optimizer + peephole | Multi-pass SSA-based |
|
||||
| **Compile speed** | **Fast** | Slow | Medium | Medium-fast |
|
||||
| **Linker** | `vlink` | `vlink` or GNU `ld` | `blink` (integrated) | `lld` (or system linker) |
|
||||
| **Active dev** | Yes (2020s) | Yes (bebbo) | No (1990s) | Yes (very active) |
|
||||
| **AmigaOS 4** | Yes | Yes | No | No m68k backend |
|
||||
| **MorphOS** | Yes | Limited | No | No m68k backend |
|
||||
| **AROS** | Yes | Yes | No | No m68k backend |
|
||||
| **Debugging** | HUNK_DEBUG | HUNK_DEBUG + GDB remote | SAS stabs | DWARF (no Amiga output) |
|
||||
| **Architecture** | Single monolithic backend per target | Monolithic with frontend/middle/backend layers | Monolithic (native only) | Modular: frontend → IR → optimizer → backend |
|
||||
|
||||
### Architectural Similarities to Clang/LLVM
|
||||
|
||||
VBCC and Clang share a surprising number of design philosophies despite being separated by two decades and targeting opposite ends of the performance spectrum:
|
||||
|
||||
| Design Aspect | VBCC | Clang/LLVM | Why It's Similar |
|
||||
|---|---|---|---|
|
||||
| **Driver + backend split** | `vc` driver invokes `vbccm68k` | `clang` driver invokes LLVM backend | Both separate the user-facing interface from the code generator; the driver handles flags, preprocessing, and toolchain orchestration |
|
||||
| **Retargetable by design** | New target = new config file + backend binary | New target = new LLVM backend (TableGen `.td` files) | Both were architected from day one to support multiple architectures, unlike GCC which grew retargetability organically |
|
||||
| **Text-based target description** | `config/m68k-amigaos` plain-text scripts | LLVM TableGen `.td` files (declarative DSL) | Both externalize target knowledge into data rather than hardcoding it in the compiler source. VBCC's config is procedural; Clang's is declarative |
|
||||
| **Library-based architecture** | Backend is a separate binary (`vbccm68k`) | LLVM is a set of libraries (`libLLVMCore`, `libLLVMCodeGen`) | Both avoid monolithic compiler design. VBCC communicates via pipes/processes; LLVM communicates in-process via API calls |
|
||||
| **Focus on clean IR** | Simple three-address IR with virtual registers | LLVM IR (SSA-based, typed) | Both use an intermediate representation to decouple the frontend from code generation. VBCC's IR is much simpler (no SSA, no phi nodes) |
|
||||
| **Peephole optimization emphasis** | Primary optimization strategy | `llvm/lib/CodeGen/PeepholeOptimizer.cpp` | Both recognize that target-specific peephole patterns yield the biggest wins for simple ISAs like m68k |
|
||||
|
||||
### Where VBCC Diverges from Clang/LLVM
|
||||
|
||||
| Design Aspect | VBCC | Clang/LLVM | Practical Impact |
|
||||
|---|---|---|---|
|
||||
| **IR complexity** | Linear three-address code, no SSA | Full SSA with phi nodes, metadata, debug info | VBCC is much simpler to understand and debug; LLVM enables far more sophisticated optimizations (LTO, PGO, vectorization) |
|
||||
| **Optimization pipeline** | Single peephole pass | Multi-pass: SROA, GVN, LICM, inlining, vectorization, etc. | VBCC cannot match LLVM on complex C++ or compute-heavy workloads, but is perfectly adequate for the C89-level code typical of Amiga programs |
|
||||
| **Frontend language support** | C only (hand-written parser) | C, C++, ObjC, ObjC++, Swift, Rust, Julia, etc. | VBCC's parser is ~15,000 lines; Clang's is millions. The tradeoff is compile speed vs language coverage |
|
||||
| **ABI knowledge** | All ABI logic in the backend config | TargetInfo + ABIInfo in Clang, calling convention in LLVM backend | VBCC's approach is simpler and more transparent for AmigaOS's register-based convention; LLVM's is more general but harder to customize for exotic ABIs |
|
||||
| **Intermediate output** | Assembly text only (Motorola syntax) | LLVM IR (`.ll`), bitcode (`.bc`), assembly, object files | LLVM's multi-level IR enables link-time optimization and cross-module analysis; VBCC has no equivalent |
|
||||
| **Open source** | Source available on request, free for personal use | Fully open source (Apache 2.0) | LLVM can be forked, modified, and redistributed freely; VBCC is maintained by a single author with controlled distribution |
|
||||
|
||||
### When to Choose VBCC
|
||||
|
||||
- **Rapid iteration** — VBCC compiles significantly faster than GCC, making it ideal for edit-compile-test cycles
|
||||
- **Standards compliance** — stricter C89 checking than GCC; catches subtle portability bugs
|
||||
- **Clean assembly output** — easier to read and audit than GCC's heavily macro-expanded output
|
||||
- **Modern Amiga targets** — best support for AmigaOS 4, MorphOS, and AROS from one toolchain
|
||||
- **Smaller binaries** — with `-size`, VBCC often beats GCC on code density
|
||||
|
||||
### When to Choose GCC Instead
|
||||
|
||||
- **C++ required** — VBCC does not support C++ at all
|
||||
- **GNU extensions** — code using `__attribute__`, nested functions, or other GCCisms
|
||||
- **Existing GCC codebase** — projects already using bebbo toolchain or libnix
|
||||
- **GDB debugging** — GCC's GDB remote debugging is more mature than VBCC's limited debug output
|
||||
|
||||
---
|
||||
|
||||
## Practical Examples
|
||||
|
||||
### Minimal VBCC Program (CLI)
|
||||
|
||||
```c
|
||||
/* hello.c */
|
||||
#include <proto/dos.h>
|
||||
#include <proto/exec.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
Printf("Hello, AmigaOS from VBCC!\n");
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
vc +m68k-amigaos -O -o hello hello.c
|
||||
```
|
||||
|
||||
### Workbench Program with Tooltypes
|
||||
|
||||
```c
|
||||
/* wbhello.c */
|
||||
#include <proto/dos.h>
|
||||
#include <proto/exec.h>
|
||||
#include <workbench/startup.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct WBStartup *wbmsg = NULL;
|
||||
|
||||
if (argc == 0)
|
||||
{
|
||||
/* Launched from Workbench */
|
||||
wbmsg = (struct WBStartup *)argv;
|
||||
/* Read tooltypes from wbmsg->sm_ArgList->wa_ToolTypes */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Launched from CLI */
|
||||
Printf("Args: %ld\n", argc);
|
||||
}
|
||||
|
||||
Printf("VBCC Workbench program running\n");
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
vc +m68k-amigaos -O -o wbhello wbhello.c
|
||||
```
|
||||
|
||||
### Custom Register Function (Hand-Optimized Blitter Call)
|
||||
|
||||
```c
|
||||
/* blitfast.c — hand-optimized blitter call using __reg() */
|
||||
#include <hardware/custom.h>
|
||||
#include <hardware/blit.h>
|
||||
|
||||
extern volatile struct Custom custom;
|
||||
|
||||
/* Match the hardware register layout exactly */
|
||||
void __reg("d0") BlitWait(void)
|
||||
{
|
||||
/* Wait for blitter DMA to finish */
|
||||
while (custom.dmaconr & (1 << 14)) /* BBUSY bit */
|
||||
;
|
||||
}
|
||||
|
||||
void __reg("a0") SetupBlit(
|
||||
__reg("d0") UWORD bltcon0,
|
||||
__reg("d1") UWORD bltcon1,
|
||||
__reg("d2") APTR srcA,
|
||||
__reg("d3") APTR srcB,
|
||||
__reg("d4") APTR dst)
|
||||
{
|
||||
BlitWait();
|
||||
custom.bltcon0 = bltcon0;
|
||||
custom.bltcon1 = bltcon1;
|
||||
custom.bltapt = srcA;
|
||||
custom.bltbpt = srcB;
|
||||
custom.bltdpt = dst;
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
vc +m68k-amigaos -O -speed -o blitfast blitfast.c
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
> `__reg()` on function parameters is powerful but dangerous. If you mismatch the register with the actual hardware or OS expectation, you get silent corruption. Always verify against the `.fd` file or hardware register documentation.
|
||||
|
||||
---
|
||||
|
||||
## Best Practices & Antipatterns
|
||||
|
||||
### Best Practices
|
||||
|
||||
1. Always use `+m68k-amigaos` explicitly — do not rely on a default config
|
||||
2. Use `-O` or `-speed` for release builds; `-size` for tight memory constraints
|
||||
3. Prefer `__reg()` in performance-critical paths; let the compiler choose registers for general code
|
||||
4. Verify register assignments against NDK `.fd` files before hand-rolling OS calls
|
||||
5. Use `vlink` for linking — do not mix GNU `ld` with VBCC object files
|
||||
6. Set `VBCC` environment variable correctly — the driver searches paths relative to it
|
||||
7. Use `-g` for debug builds; VBCC emits HUNK_DEBUG compatible with most Amiga debuggers
|
||||
8. Test on real hardware or accurate emulator — VBCC's optimizer may reorder memory accesses in ways that behave differently on 68000 vs 68060
|
||||
9. For AmigaOS 4 or MorphOS, use the dedicated target configs (`+m68k-amigaos4`, `+ppc-morphos`)
|
||||
10. Keep a local copy of generated pragma headers — `cvinclude.pl` is a build dependency
|
||||
|
||||
### Named Antipatterns
|
||||
|
||||
#### "The Register Mismatch" — Wrong `__reg()` for OS Calls
|
||||
|
||||
```c
|
||||
/* BAD: D0 and D1 swapped — Open() expects name in D1, mode in D2 */
|
||||
BPTR __reg("d0") Open(__reg("d0") CONST_STRPTR name,
|
||||
__reg("d1") LONG mode);
|
||||
|
||||
/* The JSR -30(A6) will place name in D0 (wrong) and mode in D1 (wrong).
|
||||
Crash or silent corruption guaranteed. */
|
||||
```
|
||||
|
||||
```c
|
||||
/* CORRECT: Match the .fd specification exactly */
|
||||
/* dos_lib.fd: Open(name,accessMode)(d1,d2) */
|
||||
#pragma amicall(DOSBase, 0x1E, Open(d1,d2))
|
||||
```
|
||||
|
||||
#### "The GCC Refugee" — Using `__asm()` Inline for OS Calls
|
||||
|
||||
```c
|
||||
/* BAD: Porting GCC inline asm to VBCC — unnecessary and fragile */
|
||||
static __inline APTR AllocMem(ULONG size, ULONG flags)
|
||||
{
|
||||
register APTR _r __asm("d0"); /* GCC syntax — not VBCC! */
|
||||
/* ... */
|
||||
}
|
||||
```
|
||||
|
||||
```c
|
||||
/* CORRECT: Use VBCC's __reg() or proto headers */
|
||||
#include <proto/exec.h>
|
||||
APTR mem = AllocMem(1024, MEMF_CLEAR);
|
||||
```
|
||||
|
||||
#### "The Missing vlink" — Linking with GNU ld
|
||||
|
||||
```bash
|
||||
# BAD: GNU ld does not understand VBCC's HUNK output conventions
|
||||
m68k-amigaos-ld -o myapp myapp.o
|
||||
# Produces broken executable or link errors
|
||||
|
||||
# CORRECT: Use vlink
|
||||
vlink -bamigahunk -o myapp myapp.o -lamiga
|
||||
```
|
||||
|
||||
#### "The A6 Squatter" — Using `__reg("a6")` for Variables
|
||||
|
||||
```c
|
||||
/* BAD: A6 is sacred — it must always point to the library base during OS calls */
|
||||
struct MyData * __reg("a6") myptr;
|
||||
/* ... later ... */
|
||||
JSR -198(A6); /* Calls AllocMem with garbage in A6! Crash. */
|
||||
```
|
||||
|
||||
```c
|
||||
/* CORRECT: Use A2–A5 for persistent pointers */
|
||||
struct MyData * __reg("a2") myptr;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Pitfalls & Common Mistakes
|
||||
|
||||
### 1. Forgetting the Target Config
|
||||
|
||||
**Symptom:** `vc` compiles but emits x86 code, or fails with "unknown target".
|
||||
|
||||
**Cause:** The `vc` driver requires `+target` to select a backend. Without it, `vc` may default to the host architecture or error out.
|
||||
|
||||
**Fix:** Always specify the target:
|
||||
```bash
|
||||
vc +m68k-amigaos -o app app.c # Correct
|
||||
vc -o app app.c # Wrong — may default to host
|
||||
```
|
||||
|
||||
### 2. C99 Code in C89 Mode
|
||||
|
||||
**Symptom:** Errors like `// comments not allowed` or `variable declaration after statement`.
|
||||
|
||||
**Cause:** VBCC defaults to strict C89. `//` comments, mixed declarations, and `inline` keyword are not accepted.
|
||||
|
||||
**Fix:** Use `-c99` for partial C99 support, or rewrite to C89:
|
||||
```c
|
||||
/* C89 compatible */
|
||||
int i;
|
||||
for (i = 0; i < 10; i++) { }
|
||||
|
||||
/* Use /* */ comments exclusively unless -c99 is set */
|
||||
```
|
||||
|
||||
### 3. Missing `VBCC` Environment Variable
|
||||
|
||||
**Symptom:** `vc` cannot find config files, startup code, or standard headers.
|
||||
|
||||
**Cause:** `vc` resolves config paths relative to the `VBCC` environment variable. If unset, it searches relative to the binary location, which fails on many installations.
|
||||
|
||||
**Fix:**
|
||||
```bash
|
||||
export VBCC=/opt/vbcc
|
||||
export PATH=$VBCC/bin:$PATH
|
||||
```
|
||||
|
||||
### 4. Optimizer Reordering Hardware Register Accesses
|
||||
|
||||
**Symptom:** Blitter or CIA register writes happen in the wrong order, or hardware state reads return stale values.
|
||||
|
||||
**Cause:** VBCC's optimizer does not know that `volatile struct Custom` memory-mapped I/O has side effects. It may reorder or eliminate reads.
|
||||
|
||||
**Fix:** Always declare hardware pointers as `volatile`:
|
||||
```c
|
||||
extern volatile struct Custom custom; /* hardware/custom.h does this */
|
||||
```
|
||||
|
||||
For custom hardware structs not in the NDK, add `volatile` manually:
|
||||
```c
|
||||
volatile UWORD * const myreg = (volatile UWORD *)0xDFF100;
|
||||
*myreg = 0xFF; /* guaranteed emit, not optimized away */
|
||||
```
|
||||
|
||||
### 5. Mixing VBCC and GCC Object Files
|
||||
|
||||
**Symptom:** Link errors, undefined references, or runtime crashes.
|
||||
|
||||
**Cause:** VBCC and GCC use different calling conventions for their own internal runtime functions (division helpers, stack check prologues). Object files are ABI-incompatible at the runtime-library level.
|
||||
|
||||
**Fix:** Compile the entire project with one compiler. If mixing assembly (vasm) with C, use VBCC for C and vasm for asm, then link with `vlink`.
|
||||
|
||||
---
|
||||
|
||||
## Use Cases
|
||||
|
||||
### Software Built with VBCC
|
||||
|
||||
VBCC is the compiler of choice for many modern Amiga projects because it is actively maintained and produces reliable code:
|
||||
|
||||
| Project | Target | Notes |
|
||||
|---|---|---|
|
||||
| **ScummVM** (Amiga port) | AmigaOS 3 / 4 | Large C codebase; VBCC handles the strict C requirements well |
|
||||
| **DoomAttack** | AmigaOS 3 | 68000-optimized Doom port |
|
||||
| **Various SDL games** | AmigaOS 3 / MorphOS | SDL-Amiga wrappers compiled with VBCC |
|
||||
| **MUI 5 applications** | AmigaOS 3+ | MUI custom classes in C |
|
||||
| **AROS core** | AROS | VBCC is one of the supported compilers for AROS build |
|
||||
| **AmigaOS 4 system software** | AmigaOS 4 | Hyperion's SDK supports VBCC |
|
||||
|
||||
### Typical Project Types
|
||||
|
||||
- **Retro game development** — cross-compile on Linux, test in FS-UAE
|
||||
- **Utility/tools** — small CLI programs where compile speed matters
|
||||
- **Shared libraries** — `libinit.o` startup makes library authoring straightforward
|
||||
- **MorphOS/AROS ports** — single codebase compiles to multiple Amiga-like OSes
|
||||
|
||||
---
|
||||
|
||||
## FAQ
|
||||
|
||||
**Q: Does VBCC support C++?**
|
||||
A: No. VBCC is a C compiler only. For C++ on Amiga, use GCC bebbo or StormC.
|
||||
|
||||
**Q: Can I use VBCC as a native Amiga compiler?**
|
||||
A: The VBCC compiler itself does not run on AmigaOS — it is a cross-compiler. However, there have been ports of earlier versions. Modern development uses Linux/macOS/Windows hosts.
|
||||
|
||||
**Q: Why does my code compile with GCC but fail with VBCC?**
|
||||
A: VBCC is stricter about C89 compliance. Common issues: `//` comments, variable declarations after executable statements, missing function prototypes, and GNU `__attribute__` extensions.
|
||||
|
||||
**Q: How do I debug VBCC-compiled programs?**
|
||||
A: Use `-g` to emit HUNK_DEBUG information. Load the executable into an Amiga debugger (like the one in UAE/FS-UAE with symbol support) or use `kprintf()` tracing.
|
||||
|
||||
**Q: Can I mix VBCC-compiled C with vasm assembly?**
|
||||
A: Yes — this is the recommended combination. Compile C with `vc`, assemble with `vasmm68k_mot`, link with `vlink`. All three tools share compatible object formats.
|
||||
|
||||
**Q: What is the difference between `-speed` and `-O`?**
|
||||
A: `-O` enables standard optimizations. `-speed` enables aggressive optimizations that may increase code size (loop unrolling, function inlining). Use `-size` for the opposite tradeoff.
|
||||
|
||||
**Q: Does VBCC support 68060-specific optimizations?**
|
||||
A: Yes with `-m68060`. The backend avoids unimplemented instructions and uses the dual-pipeline effectively. However, it does not perform instruction scheduling to exploit superscalar execution — hand-tuning assembly may still outperform the compiler on tight inner loops.
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
### VBCC & Related Tools (Volker Barthelmann)
|
||||
|
||||
- VBCC homepage: http://sun.hasenbraten.de/vbcc/
|
||||
- VBCC manual (PDF): http://www.ibaug.de/vbcc/doc/vbcc.pdf
|
||||
- vlink linker: http://sun.hasenbraten.de/vlink/
|
||||
- vasm assembler: http://sun.hasenbraten.de/vasm/
|
||||
- Aminet `dev/c/vbcc` — target archives and updates
|
||||
|
||||
### Other Compilers & Tools Mentioned
|
||||
|
||||
- **GCC bebbo**: [gcc_amiga.md](gcc_amiga.md) · https://franke.ms/git/bebbo/amiga-gcc (mirror: https://github.com/AmigaPorts/m68k-amigaos-gcc)
|
||||
- **SAS/C**: [sasc.md](sasc.md) — SAS/C 6.x native compiler
|
||||
- **StormC**: [stormc.md](stormc.md) — StormC 4 IDE and compiler
|
||||
- **Clang/LLVM**: https://llvm.org/ · https://clang.llvm.org/
|
||||
- **GNU Binutils (ld)**: https://www.gnu.org/software/binutils/
|
||||
- **lld**: https://lld.llvm.org/ — LLVM linker
|
||||
- **GDB**: https://www.sourceware.org/gdb/ — GNU debugger
|
||||
- **libnix**: Aminet `dev/c/libnix` — lightweight Amiga C runtime library
|
||||
|
||||
### FD Toolchain
|
||||
|
||||
- `fd2pragma` / `fd2inline`: shipped with NDK 3.9 (`NDK_3.9/Tools/`)
|
||||
- `cvinclude.pl`: bundled with VBCC in `vbcc/bin/`
|
||||
|
||||
### Related Knowledge Base Articles
|
||||
|
||||
- [vasm_vlink.md](vasm_vlink.md) — vasm assembler and vlink linker
|
||||
- [register_conventions.md](../04_linking_and_libraries/register_conventions.md) — AmigaOS register calling conventions
|
||||
- [inline_stubs.md](../04_linking_and_libraries/inline_stubs.md) — `__reg()` and pragma mechanisms compared across compilers
|
||||
- [compiler_stubs.md](../04_linking_and_libraries/compiler_stubs.md) — compiler-specific library call generation
|
||||
- [compiler_fingerprints.md](../05_reversing/compiler_fingerprints.md) — recognizing VBCC-generated code in disassembly
|
||||
Loading…
Add table
Add a link
Reference in a new issue