diff --git a/CHANGELOG.md b/CHANGELOG.md index f52f35a..e93aa75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/README.md b/README.md index 465123d..a5f37a8 100644 --- a/README.md +++ b/README.md @@ -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, diff --git a/cmd/gasm/main.go b/cmd/gasm/main.go index 30509ba..3caf76d 100644 --- a/cmd/gasm/main.go +++ b/cmd/gasm/main.go @@ -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 { diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 1c6ac97..5f827ba 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -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 diff --git a/justfile b/justfile index b66fac3..d1dc650 100644 --- a/justfile +++ b/justfile @@ -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