amiga-bootcamp/13_toolchain/vasm_vlink.md
2026-04-26 14:46:18 -04:00

29 KiB
Raw Permalink Blame History

← Home · Toolchain

vasm & vlink — Portable Assembler and Linker for Amiga

Overview

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:

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 6800068060, 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 ARMv1v4, 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)

# vasm — assembler
wget http://sun.hasenbraten.de/vasm/release/vasm.tar.gz
tar xzf vasm.tar.gz && cd vasm

# 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
# 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

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 — Comprehensive Reference

Basic Invocation

vasmm68k_mot -Fhunk -o output.o input.s

Complete Flag Reference

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 (\@).

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.


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:

; 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:

; 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 #0127, DnMOVEQ #n, Dn
ADDQ/SUBQ ADDI #18, DnADDQ #n, Dn
CLR MOVE.L #0, DnCLR.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

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.


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.

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

# 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:

/* 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:

# 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)

; hello.s — Minimal AmigaOS executable using vasm mot-syntax
        SECTION code,CODE

start:
        move.l  4.w,a6              ; SysBase → A6
        lea     dosname(pc),a1      ; library name
        moveq   #0,d0               ; any version
        jsr     -552(a6)            ; OpenLibrary()

        tst.l   d0
        beq.s   .exit               ; library not found
        move.l  d0,a6               ; DOSBase → A6

        ; 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               ; return code
        rts

dosname: dc.b "dos.library",0
msg:     dc.b "Hello Amiga!",10
        EVEN

Build and link:

vasmm68k_mot -Fhunk -o hello.o hello.s
vlink -bamigahunk -o hello hello.o

Example 2: Multi-File Project with Data Section

; 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:

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_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
// 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:

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

; 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
/* rom.cmd — Linker script for ROM binary */
MEMORY
{
    ROM: ORIGIN=0x00F80000  LENGTH=512K
}

SECTIONS
{
    .text :
    {
        *(.text .text.*)
    } > ROM
}
vasmm68k_mot -Fhunk -o rom.o rom.s
vlink -brawbin -T rom.cmd -o kickstart.rom rom.o

Example 5: Macros and Conditional Assembly

; 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:

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 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 Library jump table generation Used with fd2pragma → C headers

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
  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
  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:

# 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:

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:

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:

# 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:

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 (19851995)

In the Amiga's commercial era, developers chose between several closed-source assemblers:

Assembler Era Developer Fate
AssemPro 19861990 Softec Abandoned
A68k 19871992 Alpha Software Abandoned
ArgAsm 19871991 Argonaut Software Abandoned
Devpac 19891994 HiSoft Abandoned
AsmOne 19911996 Rune Gram-Madsen Abandoned
Barfly 19932000 K. J. Down Abandoned
PhxAss 19931998 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

Official Sources

GitHub Mirrors & Community Repos

Repository Description
retro-vault/vasm Git mirror of vasm — updated regularly
retro-vault/vlink Git mirror of vlink — updated regularly
StarWolf3000/vasm-mirror Git mirror of vasm (formerly hosted at mbitsnbites)
dbuchwald/vasm Git mirror with CI integration
ezrec/vasm Mirror with additional CPU backends
kusma/amiga-dev Pre-packaged Amiga dev environment (VBCC + vasm + vlink + PosixLib)
  • vbcc — C compiler that uses vasm/vlink as its assembler/linker
  • gcc_amiga.md — bebbo's GCC toolchain (configurable to use vasm/vlink)
  • FD files — FD/SFD file format; fd2pragma generates C headers used with vbcc+vasm
  • Makefiles — Makefile patterns for vasm/vlink and mixed C+asm projects
  • HUNK Format — The executable format vlink outputs and vasm can emit
  • Debugging — Tools that work with vasm/vlink output (Enforcer, SnoopDOS, FS-UAE GDB)
  • Register Conventions — ABI for C↔asm interop with vbcc

Community Resources