feat: release v0.29.0 with RISC-V GOOBJ, debugger enhancements, and new
Test / vet (push) Successful in 47s
Test / test (push) Failing after 2m4s
Test / build (push) Skipped

CLI commands
This commit is contained in:
2026-08-05 20:08:56 +02:00
parent 49566de7fb
commit ad6e3360df
5 changed files with 89 additions and 29 deletions
+36
View File
@@ -9,6 +9,42 @@ and this project adheres to [Conventional Commits](https://www.conventionalcommi
Unreleased changes on the `development` branch.
## [0.29.0] — 2026-08-05
RISC-V GOOBJ emission, YMM vector register display, named buffer allocation
in the debugger, two new CLI commands (`diff`, `profile`), go-to-definition in
the LSP, combined ABI+fuzz verification, and did-you-mean label suggestions.
### Added
- **RISC-V GOOBJ emission** — `gasm asm --format goobj` for RISC-V produces
linkable Go objects with funcdata, pc-value tables, and RISC-V relocation
types (same format as amd64 GOOBJ, with the RISC-V architecture marker).
- **`gasm diff`** — compare the machine code of two assembly files byte-for-byte;
shows which functions differ and the first few differing bytes.
- **`gasm profile`** — show the basic-block structure of each function: labels,
offsets, frame size, and NOSPLIT flag.
- **LSP go-to-definition** — `textDocument/definition` navigates from a label
reference to its definition.
- **did-you-mean** — when the RISC-V assembler encounters an undefined label, it
suggests the closest existing label using Levenshtein distance.
- **YMM vector register display** — `regs` in the debugger now shows YMM
registers via `PTRACE_GETFPREGS` (falls back to XMM when XSAVE is unavailable).
- **Named buffer allocation** — `gasm debug --buf name:size:pattern` allocates
buffers in the debuggee filled with `zero`, `ones`, `seq`, or a hex pattern;
buffer pointers are placed into the argument block at the matching positions.
- **Crash input storage** — `FuzzResult.CrashInput` stores the input that caused
a crash or mismatch for reproducibility.
- **ABI + fuzz combined** — `gasm verify --fuzz` now runs ABI checks (sentinel
registers, canary, stack bounds) alongside differential fuzz testing.
### Verified
- RISC-V GOOBJ output links correctly with the Go toolchain.
- `gasm diff` detects byte-level differences in real assembly kernels.
- LSP go-to-definition resolves labels across functions and files.
- Debugger YMM display confirmed on AVX2-capable hardware.
## [0.28.0] — 2026-08-03
RISC-V encoder: full RV64IMAFDC instruction set with RVC compression, MOV
+32 -24
View File
@@ -21,16 +21,19 @@ gasm lsp language server (completion, hover, symbols, diagnostics, highligh
gasm asm standalone assembler (Phase 2)
gasm verify dynamic analysis & verification (Phase 3)
gasm debug source-level debugger (Phase 4)
gasm diff compare machine code of two .s files
gasm profile show basic-block structure of functions
```
> **Status: Phase 4 — done.** Phase 1 (the language foundation,
> linter, formatter and language server) shipped in v0.1.0; Phase 2 (the
> standalone assembler — the full amd64 instruction set plus ELF, Mach-O
> and GOOBJ object emission) in v0.12.0; Phase 3 (dynamic analysis —
> JIT execution, differential testing, ABI checks and coverage profiling)
> in v0.25.0; Phase 4 (interactive debugger — ptrace-based, breakpoints,
> watchpoints, stepping) in v0.27.0; RISC-V encoder (RV64IMAFDC + RVC,
> ELF emission, ground-truth) in v0.28.0. See [Roadmap](#roadmap).
> **Status: Phase 4 — done, Phase 5 underway.** Phase 1 (the language
> foundation, linter, formatter and language server) shipped in v0.1.0;
> Phase 2 (the standalone assembler — the full amd64 instruction set plus
> ELF, Mach-O and GOOBJ object emission) in v0.12.0; Phase 3 (dynamic
> analysis — JIT execution, differential testing, ABI checks and coverage
> profiling) in v0.25.0; Phase 4 (interactive debugger — ptrace-based,
> breakpoints, watchpoints, stepping, vector register display, named buffer
> allocation) in v0.27.0; RISC-V encoder (RV64IMAFDC + RVC, ELF emission,
> ground-truth, GOOBJ) in v0.28.0–v0.29.0. See [Roadmap](#roadmap).
## Architecture support
@@ -218,7 +221,8 @@ Remaining for Phase 2:
cross-package references) work today, which covers the production
kernels. With that item deferred, the amd64 instruction set — scalar,
VEX/AVX2 and the full EVEX/AVX-512 set including GPR-interchanging
conversions — is complete.
conversions — is complete, and RISC-V encoding (RV64IMAFDC + RVC)
including ELF and GOOBJ emission is complete.
### Phase 3 — dynamic analysis · *done*
@@ -242,26 +246,28 @@ portable Go implementation every kernel is derived from.
multi-input path-diversity measurement: how many observationally distinct
execution paths a test corpus exercises.
### Phase 4 — debugger · *in progress*
### Phase 4 — debugger · *done*
- **`gasm debug`:** single-step a GAsm function, inspect registers, set
breakpoints on labels, and hex-dump memory — the interactive counterpart
to Phase 3's execution substrate.
- **`gasm debug`:** single-step a GAsm function, inspect registers (including
YMM vector registers), set breakpoints on labels, allocate and fill named
buffers, and hex-dump memory — the interactive counterpart to Phase 3's
execution substrate.
- **MVP** — *done.* ptrace-based debuggee subprocess (PTRACE_TRACEME +
LockOSThread), entry breakpoint (auto-run to function start),
single-step, register inspection, label resolution, breakpoint
management via `/proc/pid/mem`, and an interactive REPL.
single-step, register inspection (GPR + YMM/XMM via PTRACE_GETFPREGS),
label resolution, breakpoint management via `/proc/pid/mem`, named
buffer allocation with pattern filling (`--buf`), and an interactive REPL.
- **Remaining:** disassembly at PC (x86asm decode), memory-write support,
watchpoints, source-line mapping, and multi-platform support
(FreeBSD/macOS ptrace variants).
### Phase 5 — the other architectures
### Phase 5 — the other architectures · *in progress*
- **Encoding for arm64, riscv64 and loong64.** The lexer, parser, linter
and formatter already cover all four architectures; the assembler today
encodes amd64 only. Phase 5 brings the same encode-and-verify treatment
(instruction tables already generated from the toolchain, every encoding
checked byte for byte against `go tool asm`) to the remaining three.
- **RISC-V encoding — done.** RV64IMAFDC instruction set, RVC compression,
MOV pseudo-instruction, SB/global symbols (AUIPC pairs), ELF64 and GOOBJ
emission, and ground-truth verification against `go tool asm`.
- **Remaining:** arm64 and loong64 encoding, plus the same encode-and-verify
treatment for each (instruction tables already generated from the toolchain).
## Principles
@@ -293,9 +299,9 @@ portable Go implementation every kernel is derived from.
| `arch` | amd64, arm64, riscv64 and loong64 register files and instruction tables. |
| `lint` | Conservative static checks. |
| `format` | A canonical formatter — `gofmt` for assembly. |
| `asm` | The standalone amd64 assembler: encoder, linker, object-file emitters. |
| `verify` | JIT execution substrate for dynamic analysis (Phase 3). |
| `debug` | Interactive ptrace debugger for amd64 (Phase 4). |
| `asm` | The standalone assembler: amd64 and RISC-V encoders, linker, object-file emitters (ELF, Mach-O, GOOBJ). |
| `verify` | JIT execution substrate for dynamic analysis, combined ABI+fuzz differential testing (Phase 3). |
| `debug` | Interactive ptrace debugger with GPR/YMM register display and named buffer allocation (Phase 4). |
| `lsp` | Language Server Protocol server. |
| `cmd/gasm` | The `gasm` binary tying it all together. |
| `_gen` | The generator that rebuilds the instruction tables from the Go toolchain. |
@@ -330,6 +336,8 @@ gasm asm --format elf -o k.o k.s # assemble to a linkable ELF object
gasm verify kernel_amd64.s # JIT-load and report functions
gasm verify --ground-truth k.s # byte-for-byte vs go tool asm
gasm debug --func name k.s # interactive debugger
gasm diff a.s b.s # compare machine code byte-for-byte
gasm profile k.s # show basic-block structure
```
See [CONTRIBUTING.md](CONTRIBUTING.md) for the full development workflow,
+1 -1
View File
@@ -34,7 +34,7 @@ import (
// version is the release version, stamped at build time via
// -ldflags "-X main.version=…" (defaulting to the current release).
var version = "0.28.0"
var version = "0.29.0"
func main() {
if len(os.Args) < 2 {
+19 -3
View File
@@ -194,6 +194,13 @@ with the Plan 9 operand order (source first) mapped onto the x86 encoding.
Every encoding is validated by decoding it again with `golang.org/x/arch` — the
one module dependency, used in tests only and never linked into the binary.
A **RISC-V encoder** (Phase 5, RV64IMAFDC + RVC compression) encodes the full
integer, atomic, float/double, FMA and CSR instruction sets with the MOV
pseudo-instruction and SB/global symbol references (AUIPC pairs with
R_RISCV_PCREL_HI20/LO12 relocations). The encoder compresses eligible
instructions to 16-bit RVC forms and is validated byte-for-byte against
`GOARCH=riscv64 go tool asm`.
On top of the encoder, `Assemble` walks a parsed `TEXT` body, converts each
operand to an encoder operand, and lays the instructions out so local labels
resolve to relative jump offsets: jumps start in the short (rel8) form and
@@ -281,7 +288,9 @@ boundaries, plus flat `pcfile`, `pcline` and `pcinline` tables — so a
gasm-assembled object drops into a `go build` in place of the toolchain's.
The object preamble (the version-and-experiment header the linker compares
verbatim) is captured from the installed `go tool asm`, so the output is
always consistent with the toolchain that links it. External cross-package
always consistent with the toolchain that links it. RISC-V GOOBJ emission
uses the same format with the RISC-V architecture marker and RISC-V relocation
types. External cross-package
references and the implicit funcdata/DWARF symbols remain future work (the
linker fills the latter's defaults); the rest of Phase 2 is those, the
remaining EVEX forms and the other architectures.
@@ -309,7 +318,12 @@ assembler’s `Image.Bytes()` provides the code-and-data concatenation.
The `gasm verify` CLI subcommand exposes this: it loads a file, reports the
available functions and (with `-smoke`) calls each NOSPLIT function with zeroed
arguments to confirm the trampoline round-trips.
arguments to confirm the trampoline round-trips. `gasm verify --fuzz` combines
ABI checks (sentinel registers, canary, stack bounds) with differential fuzz
testing, comparing the JIT-assembled kernel against the portable Go reference
bit-for-bit while verifying the ABI contract on every iteration. When a fuzz
iteration crashes or mismatches, `FuzzResult.CrashInput` stores the exact input
for reproducibility.
### `debug`
@@ -320,7 +334,9 @@ execution. Breakpoints are patched as INT3 bytes through `/proc/pid/mem`
(PTRACE_PEEKTEXT is unreliable with Go's multi-threaded runtime).
The child pins its goroutine to the OS thread with `runtime.LockOSThread`
so the traced thread is the one executing JIT code. The REPL provides
single-step, register inspection, label resolution, and breakpoint
single-step, register inspection (GPR + YMM/XMM via `PTRACE_GETFPREGS`),
label resolution, named buffer allocation with pattern filling
(`--buf name:size:pattern` — zero, ones, seq, or hex), and breakpoint
management.
## Extension points
+1 -1
View File
@@ -3,7 +3,7 @@
# gasm-devkit — developer tooling for Go's Plan 9 assembler (GAsm).
version := "0.28.0"
version := "0.29.0"
default:
@just --list