Welcome to the zasm developer community. This guide provides the technical foundation required to build the toolchain, understand the pipeline, and contribute.
zasm is not a general-purpose compiler; it is a Deterministic Binary Factory. We prioritize:
- Predictability: Identical source always produces identical, hashable WASM.
- Auditability: A human should be able to read the generated WAT and map it to the ZASM source.
- Safety: The host is protected by the WASM sandbox; the guest is protected by
zlntstatic analysis.
To build the core toolchain, you need a standard C development environment:
- Build Tools:
make,gccorclang. - Parser Generators:
flex(lexical analyzer) andbison(parser). - WASM Tooling:
wat2wasm(from wabt) if you want.wasmoutput.zruncan run.watdirectly.
For reproducible tooling across macOS and Linux, install the pinned versions used by this repo:
scripts/install-tools.sh
source tools/env.shzem --emit-cert generates cert.smt2 and a prove.sh helper.
- Current default:
prove.shonly checks UNSAT viacvc5. - External proof checking (e.g. Alethe + Carcara) is currently disabled because it has been brittle across tool versions; see
src/zem/DEFECTS.md.
On macOS (recommended) for the UNSAT check:
scripts/install-proof-tools.shOr install manually:
brew install cvc5There is also an optional test test/zem_emit_cert_prove.sh that runs prove.sh locally.
It is disabled by default; enable with ZEM_ENABLE_PROOF_TEST=1.
Edit tools/versions.env if you need to update the pinned tool versions.
git clone https://github.com/frogfish/zasm
cd zasm
make
zrun allows you to execute .wat files locally using the Wasmtime engine. It requires the Wasmtime C API.
export WASMTIME_C_API_DIR=/path/to/wasmtime-c-api
make zrun
The source lives under src/, specs under docs/spec/, tools under docs/tools/, with examples in examples/ and reusable modules in lib/.
See docs/project_structure.md for the canonical repository map and conventions.
The toolchain operates as a series of UNIX filters. Data flows through standard streams, allowing for easy composition and linting.
- Authoring: Create
.zasmsource files. - Assembly (
zas): Converts text to JSONL IR. - Verification (
zlnt): Inspects the IR for register-contract violations. - Linking/Lowering (
zld): Resolves labels and produces structured WAT. - Emission (
wat2wasm): Produces the final.wasmbinary.
Command Line Execution:
cat main.asm lib/itoa.asm | bin/zas | bin/zlnt
cat main.asm lib/itoa.asm | bin/zas | bin/zld > build/app.wat
All I/O in the standard system ABI revolves around the "Slice." Instead of passing pointers and assuming null-terminators, we pass an explicit (ptr, len) pair.
- DE: Points to the start of the data in linear memory.
- BC: Contains the length of the data (number of bytes).
lib/hello.asm:
; SPDX-FileCopyrightText: 2025 Frogfish
; SPDX-License-Identifier: MIT
print_hello:
LD HL, msg
LD DE, msg_len
LD BC, DE
LD DE, HL
LD HL, #1
CALL zi_write ; zABI hostcall for output
RET
msg: STR "Hello, zasm!", 10
; STR auto-defines msg_len for you.
zld manages the layout of your module's memory deterministically.
- Static Data: Starts at a fixed offset (usually
8to avoid null-pointer accidents). RESB(Reserve Bytes): Moves the data cursor forward for uninitialized space.__heap_base:zldautomatically exports this global to tell the host where safe dynamic allocation can begin.
Because zld calculates offsets and label positions in a single stable pass over the JSONL IR, the resulting WAT is bit-for-bit identical regardless of the host OS or build timestamp.
zlnt is the gatekeeper of the toolchain. It performs Data-Flow Analysis on the IR before it is linked.
- Register Use Errors: Errors if
zi_*hostcalls are called without required registers being defined.
| Error | Cause | Solution |
|---|---|---|
zas: syntax error |
Malformed ZASM or unknown mnemonic. | Verify against docs/spec/isa.md. |
zld: unknown symbol |
A CALL or JR targets a non-existent label. |
Ensure all library files are included in the cat pipe. |
zrun: trap |
Guest code accessed memory out of bounds. | Use zlnt to verify HL pointers and segment sizes. |
Linker Collision |
Multiple files define the same label. | Use unique prefixes or namespacing for library functions. |
We welcome contributions that respect the "Boring Correctness" philosophy:
- Frontend DSLs: Build a compiler that targets the JSONL IR.
- Standard Libraries: Contribute MIT-licensed
.zasmhelpers (e.g.,math,base64,json-parser). - Linter Rules: Add new safety checks to
zlnt.