docs: bring the document set into the standard shape
Test / test (push) Successful in 2m28s

Assisted-by: GLM 5.3 Flash
This commit is contained in:
2026-09-17 20:33:18 +02:00
parent 03d6d4da54
commit c834d98210
7 changed files with 700 additions and 477 deletions
+387 -162
View File
@@ -1,215 +1,440 @@
# CLI Reference
# Command line
Repository: [sourcedock.dev/petrbalvin/gasm-devkit](https://sourcedock.dev/petrbalvin/gasm-devkit)
The reference below is taken from the program's own `--help`. If the two disagree, the
program is right and this file is a defect.
`gasm` is a single binary with subcommands. Run `gasm --help` for an
overview, or `gasm <command> -h` for a command's usage and flags.
## Synopsis
## Global Flags
```sh
gasm [global flags] <command> [command flags] [arguments]
```
| Flag | Description |
|------|-------------|
| `-h`, `--help` | Show help |
| `-V`, `--version` | Print the version |
## Commands
## `gasm tokens <file>`
| Command | Purpose |
|---|---|
| `tokens` | print the lexical token stream |
| `parse` | parse a file and report syntax errors |
| `fmt` | canonicalise the formatting of `.s` files |
| `lint` | run the static checks |
| `asm` | assemble `.s` files to machine code |
| `dis` | disassemble machine code or an assembled file |
| `verify` | JIT-assemble and run the dynamic checks |
| `debug` | interactive source-level debugger |
| `diff` | compare the machine code of two `.s` files |
| `profile` | show the basic-block structure of the functions |
| `audit-instructions` | diff the encoder against the toolchain's name table |
| `scaffold` | generate a differential test skeleton for a kernel |
| `lsp` | run the language server over stdio |
| `version` | print the version |
Print the lexical token stream of FILE: position, token kind, and text,
one token per line. FILE may be `-` to read standard input.
## tokens
## `gasm parse <file>`
```text
Usage: gasm tokens <file>
```
Parse FILE and report syntax errors on stderr. On success, prints how
many declarations and TEXT functions the file contains.
Print the lexical token stream of FILE: position, token kind and text, one
token per line. FILE may be `-` to read standard input.
## `gasm fmt [-w|-l|-d] [path...]`
```sh
gasm tokens hello_amd64.s
```
Canonicalise the formatting of Plan 9 assembly sources: indentation,
operand spacing, per-function mnemonic alignment, and blank-line layout.
```text
1:1 # "#"
1:2 IDENT "include"
1:10 STRING "\"textflag.h\""
```
| Flag | Description |
|------|-------------|
| `-w` | Write result to the source file (default: print to stdout) |
| `-l` | List files whose formatting differs, one per line; write nothing |
| `-d` | Print a unified diff of the canonical formatting instead |
## parse
With no arguments, or with a directory argument, every `.s` file below
it is reformatted in place and the names of changed files are listed
(`go fmt` style). `.` and `_` directories are skipped.
```text
Usage: gasm parse <file>
```
## `gasm lint <file...>`
Parse FILE and report syntax errors on stderr. On success, print how many
declarations and TEXT functions the file contains.
Run static checks and print diagnostics as
`file:line:col: severity: message [code]`. Exit status is non-zero when
an error-severity diagnostic is found.
```sh
gasm parse hello_amd64.s
```
| Flag | Description |
|------|-------------|
| `-disable` | Comma-separated rule codes to disable |
```text
hello_amd64.s: OK, 2 declarations, 1 functions
```
## fmt
```text
Usage: gasm fmt [-w|-l|-d] [path...]
```
| Flag | Default | Effect |
|---|---|---|
| `-w` | off | write the result back to the source file |
| `-l` | off | list the files whose formatting differs; write nothing |
| `-d` | off | print a unified diff of the canonical formatting instead |
`-l` and `-d` are mutually exclusive. With no arguments, or with a directory
argument, every `.s` file below it is reformatted in place and the names of the
changed files are listed, the way `go fmt` does; `.` and `_` directories are
skipped. Explicit file arguments print to stdout unless `-w` is given.
```sh
gasm fmt -l kernel_amd64.s
```
Empty output means every file is formatted, which is the shape a CI check
wants; `-d` shows what would change:
```sh
gasm fmt -d ugly_amd64.s
```
```text
--- ugly_amd64.s
+++ ugly_amd64.s
@@ -2,8 +2,8 @@
// func add(a, b int) int
TEXT ·add(SB), NOSPLIT, $0-24
- MOVQ a+0(FP), AX
- ADDQ b+8(FP), AX
+ MOVQ a+0(FP), AX
+ ADDQ b+8(FP), AX
```
## lint
```text
Usage: gasm lint <file...>
```
| Flag | Default | Effect |
|---|---|---|
| `-disable` | empty | comma-separated rule codes to disable |
Diagnostics are printed as `file:line:col: severity: message [code]`. The exit
status is non-zero when an error-severity diagnostic is found; warnings (the
register-clobber audit, for example) do not affect it.
Rules: `unknown-instruction`, `operand-count`, `undefined-label`,
`duplicate-label`, `missing-ret`, `missing-textflag-include`,
`abi-argsize`, `unreachable-code`, `register-clobber`,
`funcdata-pcdata`, `unused-label`, `invalid-textflag`,
`stack-imbalance`, `register-width-mismatch`, `abi0-register-args`,
`nonportable-register-name` and `unencodable-instruction`.
`nonportable-register-name`, `unencodable-instruction` and
`reserved-register-write`.
## `gasm asm [--format raw|elf|goobj] [-p pkg] [-o out] <file>`
```sh
gasm lint kernel_amd64.s
```
Assemble FILE to machine code (amd64, arm64, riscv64, loong64).
## asm
| Flag | Description |
|------|-------------|
| `--format` | Output format: `raw` (default), `elf`, `goobj` |
| `-p` | Package path (required for `--format goobj`) |
| `-o` | Write output to file (default: hex dump to stdout) |
```text
Usage: gasm asm [--format raw|elf|goobj] [-p pkg] [-o out] <file>
```
## `gasm dis [-a arch] <file>`
| Flag | Default | Effect |
|---|---|---|
| `-format` | `raw` | output format: `raw` (concatenated image), `elf` or `goobj` (Go object) |
| `-p` | empty | package path for `--format goobj`, qualifying the exported symbols |
| `-o` | empty | write the output to this file instead of a hex dump on stdout |
Disassemble machine code to instruction text (via `golang.org/x/arch`).
Supported architectures: amd64 (VEX/AVX2 and EVEX/AVX-512 included), arm64,
riscv64 (RV64IMAFDC and RVC) and loong64, selected from the file's `_arch.s`
suffix. `raw` concatenates the functions and the data section into one
self-consistent image; `elf` emits a relocatable object that links with the
system toolchain; `goobj` emits the Go toolchain's own object format, which
`cmd/link` consumes directly.
With a `.s` file, the file is assembled first and the listing follows the
real layout: one block per `TEXT` function, local labels printed at their
offsets. The architecture comes from the file name suffix, or from `-a`.
With any other file, or `-` for standard input, the bytes are
disassembled linearly and `-a` selects the architecture (amd64, arm64,
riscv64 or loong64).
```sh
gasm asm hello_amd64.s
```
| Flag | Description |
|------|-------------|
| `-a` | Architecture for raw input without a `_arch.s` name |
```text
add: 16 bytes
0000: 48 8b 44 24 08 48 03 44 24 10 48 89 44 24 18 c3
```
## `gasm verify [flags] <file.s>`
## dis
Assemble FILE, map it into executable memory, and run dynamic checks.
```text
Usage: gasm dis [-a arch] <file>
```
| Flag | Description |
|------|-------------|
| `--ground-truth` | Compare machine code byte-for-byte against `go tool asm` |
| `--fuzz` | Differential fuzz: JIT both gasm and go-tool-asm, compare outputs |
| `-n` | Fuzz iterations per function (default: 1000) |
| `--abi` | Run ABI-checking calls (sentinel registers + red zone) |
| `--abi-n` | Number of ABI check iterations with varied inputs (default: 100) |
| `--profile` | List basic-block structure per function |
| `--smoke` | Call each NOSPLIT function with zeroed args |
| `--call <func>` | Invoke a single function with `--buf` instead of the sweeps |
| `--buf <spec>` | Buffer spec for `--call`: `name:size:pattern[,name:size:pattern]` |
| `--args <spec>` | Scalar args for `--call`: `name=value[,name=value]` (decimal or `0x` hex) |
| `--repeat <n>` | Number of times to repeat a `--call` invocation (default: 1) |
| `--save-corpus <dir>` | With `--fuzz`: write each failing input to DIR as replayable JSON |
| `--replay <dir>` | Re-run saved corpus entries (JSON in DIR), one child process per entry |
| Flag | Default | Effect |
|---|---|---|
| `-a` | empty | architecture for raw input without a `_arch.s` name |
The `--fuzz` mode runs each function in a subprocess; a partial function
(e.g. a decoder that faults on malformed input) is reported as
`CRASH` without killing the parent. Use `--call` with `--buf` to invoke
partial functions with valid data instead.
With a `.s` file the file is assembled first and the listing follows the real
layout: one block per `TEXT` function, local labels printed at their offsets.
With any other file, or `-` for standard input, the bytes are disassembled
linearly and `-a` selects the architecture (amd64, arm64, riscv64 or loong64).
The `--call` mode parses the `// func` signature, allocates the requested
buffers (`zero`, `ones`, `seq`, or a hex blob), builds the ABI0 argument
block with buffer pointers/lengths/capacities at the matching parameter
offsets, and prints the arg block before and after the call, showing
return values and any output written to the buffers. Scalar parameters
are supplied with `--args` (decimal, or `0x` hex) at their ABI0 offsets.
```sh
gasm dis hello_amd64.s
```
The `--save-corpus` mode records the logical arguments (buffer contents and
scalars, not raw pointers) of every failing fuzz input as JSON. `--replay`
rebuilds a live argument block from each entry and calls it in its own child
process, reporting `OK`, `CRASH (reproduced)` or `FAIL` per entry and
exiting non-zero when any entry fails.
```text
add: 16 bytes
0000: 48 8b 44 24 08 mov rax, qword ptr [rsp+0x8]
0005: 48 03 44 24 10 add rax, qword ptr [rsp+0x10]
000a: 48 89 44 24 18 mov qword ptr [rsp+0x18], rax
000f: c3 ret
```
## `gasm debug [--func <name>] [--buf spec] [--script file] <file.s>`
## verify
Interactive debugger for JIT-assembled functions (amd64, arm64, riscv64,
loong64). Requires a compiled binary on `$PATH` (not `go run`).
```text
Usage: gasm verify [-smoke] [-abi] [-fuzz] [-ground-truth] [-profile] [-call] <file.s>
```
| Flag | Description |
|------|-------------|
| `--func` | Function to debug (required) |
| `--buf` | Buffer spec: `name:size:pattern[,name:size:pattern]` |
| `--args <file>` | File containing the ABI0 argument block |
| `--script <file>` | Run REPL commands from a file (one per line) and exit; `-` reads stdin |
| `--timeout <dur>` | Kill the debuggee after this duration (e.g. `30s`); for headless `--script` runs |
| `--cover` | Run to completion with a breakpoint on every instruction; report which executed, how often, and which labels were reached |
| Flag | Default | Effect |
|---|---|---|
| `--ground-truth` | off | compare the machine code byte-for-byte against `go tool asm` |
| `--fuzz` | off | differential fuzz against the `go tool asm` build |
| `-n` | 1000 | fuzz iterations per function |
| `--abi` | off | ABI-checking calls: sentinel registers and a red-zone canary |
| `--abi-n` | 100 | ABI check iterations with varied inputs |
| `--profile` | off | list the basic-block structure per function |
| `--smoke` | off | call each NOSPLIT function with zeroed arguments |
| `--call` | empty | invoke a single function with `--buf` instead of the sweeps |
| `--buf` | empty | buffer spec for `--call`: `name:size:pattern[,name:size:pattern]` |
| `--args` | empty | scalar args for `--call`: `name=value[,name=value]` (decimal or `0x` hex) |
| `--repeat` | 1 | number of times to repeat a `--call` invocation |
| `--save-corpus` | empty | with `--fuzz`: write each failing input to this directory as replayable JSON |
| `--replay` | empty | re-run saved corpus entries, one child process per entry |
The JIT checks run when the host matches the file's architecture; the
toolchain comparison works everywhere. `--fuzz`, `--smoke` and `--abi` run each
function in its own child process, so a partial function that faults on random
input is reported as `CRASH` instead of ending the sweep; `--call` with `--buf`
invokes such a function with valid data. loong64 stays on the ground-truth path
until hardware validation.
```sh
gasm verify --ground-truth hello_amd64.s
```
```text
hello_amd64.s: 1 functions JIT-loaded
add: MATCH (16 bytes)
ground truth: 1/1 functions byte-identical
add: 16 bytes, args=24, frame=0 NOSPLIT
```
```sh
gasm verify --call add --args a=2,b=3 hello_amd64.s
```
```text
add: 16 bytes, args=24
signature: func add(a int, b int) int
scalars:
a = 2
b = 3
args before: 02 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 (24 bytes)
args after: 02 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 05 00 00 00 00 00 00 00 (24 bytes)
call 1: OK
```
## debug
```text
Usage: gasm debug <file.s> --func <name>
```
| Flag | Default | Effect |
|---|---|---|
| `-func` | empty | the function to debug, required |
| `-buf` | empty | buffer spec: `name:size:pattern[,name:size:pattern]` (zero, ones, seq or hex) |
| `-args` | empty | file containing the ABI0 argument block |
| `-script` | empty | run REPL commands from a file, one per line, and exit; `-` reads stdin |
| `-timeout` | 0 | kill the debuggee after this duration, for headless `-script` runs |
| `-cover` | off | run to completion with a breakpoint on every instruction and report which executed |
The debugger spawns the debuggee from the `gasm` binary on `$PATH`, so install
it first with `just install`; `go run` does not work for the traced child.
Requires Linux (ptrace) and all four architectures are supported.
REPL commands:
| Command | Description |
|---------|-------------|
| `break <label\|addr> [if <reg> <op> <val>]` | Set a breakpoint, optionally conditional |
| `delete <label\|addr>` | Remove a breakpoint |
| `info break` | List all breakpoints |
| `step [n]`, `s` | Single-step n instructions |
| `next`, `n` | Step over CALL |
| `finish`, `fin` | Run until the function returns |
| `continue`, `c` | Run until breakpoint, watchpoint or exit |
| `disas [n]`, `u` | Disassemble n instructions at PC |
| `regs` | Print general-purpose + vector/FP registers |
| `where` | Show source line and nearest label at PC |
| `stack` | Show stack near RSP (return address + ABI0 args) |
| `bt`, `backtrace` | Backtrace (current frame + return address) |
| `x [addr] [len]` | Hex-dump memory |
| `w <addr> <val...>` | Write bytes to memory |
| `set <reg> <value>` | Set a register |
| `watch <addr> [r\|w] [size]` | Set a hardware watchpoint (write by default) |
| `unwatch [<slot>]` | Clear one or all watchpoints |
| `labels`, `l` | List function labels and offsets |
| `help`, `h`, `?` | Show command help |
| `quit`, `q` | Kill the debuggee and exit |
| Command | Effect |
|---|---|
| `break <label\|addr> [if <reg> <op> <val>]` | set a breakpoint, optionally conditional |
| `delete <label\|addr>` | remove a breakpoint |
| `info break` | list the breakpoints |
| `step [n]`, `s` | single-step n instructions |
| `next`, `n` | step over a CALL |
| `finish`, `fin` | run until the function returns |
| `continue`, `c` | run until a breakpoint, watchpoint or exit |
| `disas [n]`, `u` | disassemble n instructions at the PC |
| `regs` | print the general-purpose and vector/FP registers |
| `where` | show the source line and the nearest label at the PC |
| `stack` | show the stack near RSP, the return address and the ABI0 args |
| `bt`, `backtrace` | backtrace: the current frame and the return address |
| `x [addr] [len]` | hex-dump memory |
| `w <addr> <val...>` | write bytes to memory |
| `set <reg> <value>` | set a register |
| `watch <addr> [r\|w] [size]` | set a hardware watchpoint, write by default |
| `unwatch [<slot>]` | clear one watchpoint or all of them |
| `labels`, `l` | list the function's labels and offsets |
| `help`, `h`, `?` | show the command help |
| `quit`, `q` | kill the debuggee and exit |
## `gasm diff [--map old=new,...] <file1.s> <file2.s>`
```sh
gasm debug --func add --cover hello_amd64.s
```
Compare the machine code produced by assembling two files. Shows which
functions differ and the first few differing bytes. Useful for verifying
that two implementations produce identical code, or for tracking encoding
changes between Go assembler versions.
## diff
| Flag | Description |
|------|-------------|
| `--map` | Comma-separated `old=new` pairs to match functions with different names |
```text
Usage: gasm diff <file1.s> <file2.s>
```
Without `--map`, functions are paired by exact name. With `--map`, a
function named `old` in the first file is compared against the function
named `new` in the second file (e.g. `--map wideCopyAVX2=wideCopyAVX512`
pairs AVX2 and AVX-512 variants regardless of suffix).
| Flag | Default | Effect |
|---|---|---|
| `-map` | empty | comma-separated `old=new` pairs to match functions with different names |
## `gasm profile <file.s>`
Functions are paired by exact name unless `--map` says otherwise, so
`--map wideCopyAVX2=wideCopyAVX512` pairs two variants regardless of suffix.
The exit status is non-zero when anything differs.
Show the basic-block structure of functions in an assembly file. Lists
each function's labels, their offsets, and the block boundaries. This is
the static structure; for runtime execution counts, use `gasm verify
--fuzz` which exercises the code paths.
```sh
gasm diff hello_amd64.s hello_amd64.s
```
## `gasm audit-instructions [amd64|arm64|riscv64|loong64]`
```text
add: identical (16 bytes)
all functions identical
```
Compare the gasm encoder for the given architecture (default amd64)
against the installed `go tool asm` and print the diff: superset
encodings (gasm-only spellings, shippable via `gasm asm --format goobj`),
known-but-unencodable names (the encoder backlog) and go-only names
(feature gaps). The Go side is probed black-box with a battery of operand
shapes per mnemonic, so the audit tracks whatever toolchain
`go env GOROOT` provides. On non-amd64 architectures the backlog is an
over-approximation: a name counts as encodable only when a probe shape
assembles cleanly, so a name whose real forms the battery misses lands
in the backlog.
## profile
## `gasm scaffold differential <file.s>`
```text
Usage: gasm profile <file.s>
```
Print a differential test skeleton for every `// func` signature in
FILE. The generated test seeds random states, drives the kernel and a
portable reference (`<name>Portable`), and compares outputs
byte-for-byte. Write the reference bodies, place the file in the
kernel's package, and run it in CI.
Show the basic-block structure of each function: its labels, their offsets and
the block boundaries. This is the static structure; for runtime execution
counts use `gasm debug --cover`, and for input coverage `gasm verify --fuzz`.
## `gasm lsp`
```sh
gasm profile hello_amd64.s
```
Run the language server over standard input/output (JSON-RPC 2.0 with
Content-Length framing). Point an LSP-capable editor at the binary and
associate it with `.s` files. The target architecture is inferred from
the file-name suffix (`_amd64.s`, `_arm64.s`, `_riscv64.s`,
`_loong64.s`).
```text
add: 16 bytes, args=24, frame=0 NOSPLIT
basic blocks: 1
```
Provides: completion, hover, document symbols, push and pull
diagnostics, semantic tokens, go-to-definition, find references, rename,
document formatting, inlay hints, code actions, signature help, document
highlights, workspace symbol search, #include document links, and
folding ranges for function bodies.
## audit-instructions
```text
Usage: gasm audit-instructions [amd64|arm64|riscv64|loong64]
```
Compare the gasm encoder for the given architecture (default amd64) against the
installed `go tool asm` and print the diff: superset encodings (gasm-only
spellings, shippable via `gasm asm --format goobj`), known-but-unencodable
names (the encoder backlog) and go-only names (feature gaps). The Go side is
probed black-box with a battery of operand shapes per mnemonic, so the audit
tracks whatever toolchain `go env GOROOT` provides. On non-amd64
architectures the backlog is an over-approximation: a name counts as encodable
only when a probe shape assembles cleanly, so a name whose real forms the
battery misses lands in the backlog.
```sh
gasm audit-instructions amd64
```
```text
gasm table (amd64, families excluded): 1542 mnemonics
gasm encodable: 580 go tool asm recognized: 1542
shared: 580
```
## scaffold
```text
Usage: gasm scaffold differential <file.s>
```
Print a differential test skeleton for every `// func` signature in FILE. The
generated test seeds random states, drives the kernel and a portable reference
(`<name>Portable`), and compares the outputs byte-for-byte. Write the reference
bodies, place the file in the kernel's package, and run it in CI.
```sh
gasm scaffold differential kernel_amd64.s > kernel_differential_test.go
```
## lsp
```text
Usage: gasm lsp
```
Run the language server over standard input/output, JSON-RPC 2.0 with
`Content-Length` framing. Point an LSP-capable editor at the binary and
associate it with `.s` files; the target architecture is inferred from the
file-name suffix (`_amd64.s`, `_arm64.s`, `_riscv64.s`, `_loong64.s`).
Provides: completion, hover, document symbols, push and pull diagnostics,
semantic tokens, go-to-definition, find references, rename, document
formatting, inlay hints, code actions, signature help, document highlights,
workspace symbol search, #include document links, and folding ranges for
function bodies. Definition, references and rename work across every open
document.
## version
```text
Usage: gasm version
```
Print the version the toolchain recorded for the build, the same string as
`gasm --version`: the tag on a tagged checkout, a pseudo-version naming the
commit below one, with `+dirty` appended on a dirty tree and `(devel)` outside
version control.
## Global flags
| Flag | Default | Effect |
|---|---|---|
| `-h`, `--help` | off | print the usage |
| `-V`, `--version` | off | print the version |
## Exit codes
| Code | Meaning |
|---|---|
| `0` | success |
| `1` | a failure the program detected: a parse or assembly error, an error-severity lint diagnostic, a mismatch in `verify`, a file that cannot be read |
| `2` | the arguments were wrong: a missing or extra argument, an unknown command or format, an invalid `--map` pair |
## Examples
Assemble a kernel, check it, and run it:
```sh
gasm lint kernel_amd64.s
gasm fmt -l kernel_amd64.s
gasm asm -o kernel.bin kernel_amd64.s
gasm verify --ground-truth kernel_amd64.s
```
Link the kernel into a Go program through the toolchain's own object format:
```sh
gasm asm --format goobj -p example.com/kernel -o kernel.o kernel_amd64.s
```
Find which labels a failing kernel reaches, headlessly:
```sh
gasm debug --func decodeBlockAVX2 --cover --script cmds.txt --timeout 30s kernel_amd64.s
```