chore: prepare release v0.33.0
Release / build (amd64, linux) (push) Successful in 49s
Release / build (arm64, linux) (push) Successful in 43s
Release / build (loong64, linux) (push) Successful in 46s
Release / build (riscv64, linux) (push) Successful in 45s
Test / vet (push) Successful in 47s
Release / release (push) Successful in 18s
Test / test (push) Successful in 2m39s
Test / build (push) Successful in 43s

This commit is contained in:
2026-09-14 23:36:19 +02:00
parent 40476546df
commit fff9f75595
6 changed files with 101 additions and 6 deletions
+56
View File
@@ -11,6 +11,62 @@ and this project adheres to [Conventional Commits](https://www.conventionalcommi
-
## [0.33.0] — 2026-09-14
### Added
- **Stack-split guards in `gasm asm`.** Every framed function now gets
the morestack prologue check and the trailing morestack block
(`CALL runtime.morestack_noctxt`), byte-identical to the toolchain's
`stacksplit` output on all four architectures: the small, medium and
big frame classes, auto-NOSPLIT leaves, the materialised constants of
large frames (arm64 `R27`, riscv64 `X31`, loong64 `R30`) and the
arm64 extrasize rule. Assembled objects are therefore linkable for
split functions, not only `NOSPLIT` leaves.
- **`gasm dis`.** Standalone disassembly through `golang.org/x/arch`:
a `.s` file is assembled and listed per `TEXT` function with local
labels at their real offsets, or raw bytes from a file or stdin are
disassembled linearly (`-a` selects the architecture). The debugger
shares the same decoder instead of carrying its own.
- **`gasm fmt -l` and `-d`.** Check mode lists files whose formatting
differs; diff mode prints a unified diff from the project's own
LCS-based differ, with GNU header semantics.
- **LSP cross-file navigation.** Go-to-definition and find references
fall back from local labels to the `TEXT` functions of every open
document, and rename follows the same cross-file matching.
- **Large frame offsets on riscv64 and arm64.** Frame-relative loads
and stores beyond the signed 12-bit immediate range materialise the
address through the toolchain temp register (riscv64 `X31`, arm64
`R27`) instead of silently truncating the offset (riscv64) or
rejecting the instruction (arm64); arm64 frame sizes now add the
toolchain's extrasize exactly (+8 when the frame leaves an alignment
gap, +16 when it is already aligned).
- **Tail calls `JMP sym(SB)`** on all four architectures (amd64 `E9`,
arm64 `B`, riscv64 `JAL X0`, loong64 `B`) with the call relocation.
- **Live oracle-parity tests.** Kernel files covering every guard
class, large-offset pattern and tail call are assembled by gasm and
by the installed `go tool asm` and compared byte-for-byte on all four
architectures, alongside the existing pinned-byte tests.
### Fixed
- The v0.32.0 review findings: the parser rejects malformed `TEXT`
frames and parses signed frame sizes; amd64 frame adjustments above
127 bytes encode with imm32; arm64 and loong64 relocation encodings
match the toolchain; the linter guards unnamed `TEXT` directives and
refreshes its textflag table; the LSP recovers from handler panics
and decodes client URIs; watchpoint slot state moved into the debug
session; dead verify code removed; em and en dashes replaced across
sources.
- `gasm asm --format goobj`: internal calls to `TEXT` symbols of the
same file resolve on every architecture (the reference check accepted
only the amd64 call kind).
- `gasm asm --format elf` on loong64: branch relocations now map to
`R_LARCH_B26` instead of falling into `R_LARCH_PCALA_HI20`.
- arm64 large-prologue `ADD`/`SUB` use the extended-register encoding
the toolchain picks, and the morestack block saves the link register
with the toolchain's `OR` form on loong64.
## [0.32.0] — 2026-08-31
### Added
+13 -3
View File
@@ -16,7 +16,8 @@ developer tooling to Plan 9 assembly on amd64, arm64, riscv64 and loong64.
directly.
- **Formatter.** `gasm fmt` canonicalises indentation, operand spacing,
per-function mnemonic alignment and blank-line layout: `gofmt` for assembly,
operating recursively on directories the way `go fmt` does.
operating recursively on directories the way `go fmt` does. `-l` lists
files whose formatting differs and `-d` prints a unified diff.
- **Linter.** `gasm lint` runs 18 conservative static checks, among them
`undefined-label`, `abi-argsize` (declared frame vs the `// func` signature),
`register-clobber` (Go ABI register liveness over the control-flow graph),
@@ -24,7 +25,11 @@ developer tooling to Plan 9 assembly on amd64, arm64, riscv64 and loong64.
- **Standalone assembler.** `gasm asm` encodes all four architectures without
the Go toolchain and writes raw images, linkable ELF objects (with DWARF5
debug sections) or the Go toolchain's own GOOBJ format, which `go build`
consumes in place of the toolchain's output.
consumes in place of the toolchain's output. Framed functions get the
stack-split guard and the morestack block, byte-identical to the
toolchain's, so split functions link too.
- **Disassembler.** `gasm dis` lists a `.s` file's functions at their real
offsets after assembling, or disassembles raw bytes from a file or stdin.
- **Dynamic verification.** `gasm verify` JIT-loads assembled functions into
executable memory: smoke calls, ABI checks (sentinel registers, red-zone
canary), differential fuzzing against the `go tool asm` build, and
@@ -36,7 +41,8 @@ developer tooling to Plan 9 assembly on amd64, arm64, riscv64 and loong64.
push and pull diagnostics, semantic-token highlighting, go-to-definition,
find references, rename, formatting, inlay hints, code actions, signature
help, document highlights, workspace symbol search, #include document
links and folding ranges over stdio.
links and folding ranges over stdio; definition, references and rename
work across every open document.
- **Comparators and audits.** `gasm diff` compares the machine code of two
assembly files byte-for-byte, `gasm profile` shows basic-block structure,
`gasm audit-instructions` diffs the encoder against the installed toolchain,
@@ -102,9 +108,13 @@ gasm verify --call add --args a=2,b=3 hello_amd64.s # JIT-call it with argumen
```sh
gasm fmt # reformat every .s below here, like go fmt
gasm fmt -w kernel_amd64.s # canonicalise one file in place
gasm fmt -l *.s # list files whose formatting differs
gasm fmt -d kernel_amd64.s # print a unified diff instead
gasm lint *.s # static checks
gasm asm --format elf -o k.o k.s # assemble to a linkable ELF object
gasm asm --format goobj -p pkg/path -o k.o k.s # Go object, consumed by go build
gasm dis k.s # assemble, then list each function
gasm dis -a amd64 - < dump.bin # disassemble raw bytes from stdin
gasm verify --ground-truth k.s # byte-for-byte vs go tool asm
gasm verify --fuzz k.s # differential fuzz vs the go tool asm build
gasm debug --func name k.s # interactive debugger
+1 -1
View File
@@ -38,7 +38,7 @@ import (
// version is the release version, stamped at build time via
// -ldflags "-X main.version=…" (defaulting to the current release).
var version = "0.32.0"
var version = "0.33.0"
func main() {
if len(os.Args) < 2 {
+12
View File
@@ -237,6 +237,18 @@ STP+SUB for large frames) and SB/global symbol references (ADRP+ADD pairs with
R_ADDRARM64 relocations). Like the other encoders it is validated
byte-for-byte against `GOARCH=arm64 go tool asm`.
On top of the per-architecture encoders, every framed function carries the
**stack-split guard**: the prologue check against `g.stackguard0` (small,
medium and large frame classes, the medium and large classes materialising
their offset through the architecture's temporary register and the large
class adding the SP-underflow branch) and the trailing morestack block
(save the link register, `CALL runtime.morestack_noctxt`, jump back to the
function entry). The auto-NOSPLIT rule, the frame classes, the large-frame
prologue and epilogue forms and the tail calls match the toolchain's
`stacksplit` and `preprocess` output byte for byte; a parity suite
assembles kernel files with gasm and the installed `go tool asm` and diffs
the bytes on all four architectures.
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
+18 -1
View File
@@ -22,7 +22,7 @@ one token per line. FILE may be `-` to read standard input.
Parse FILE and report syntax errors on stderr. On success, prints how
many declarations and TEXT functions the file contains.
## `gasm fmt [-w] [path...]`
## `gasm fmt [-w|-l|-d] [path...]`
Canonicalise the formatting of Plan 9 assembly sources: indentation,
operand spacing, per-function mnemonic alignment, and blank-line layout.
@@ -30,6 +30,8 @@ operand spacing, per-function mnemonic alignment, and blank-line layout.
| 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 |
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
@@ -62,6 +64,21 @@ Assemble FILE to machine code (amd64, arm64, riscv64, loong64).
| `-p` | Package path (required for `--format goobj`) |
| `-o` | Write output to file (default: hex dump to stdout) |
## `gasm dis [-a arch] <file>`
Disassemble machine code to instruction text (via `golang.org/x/arch`).
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).
| Flag | Description |
|------|-------------|
| `-a` | Architecture for raw input without a `_arch.s` name |
## `gasm verify [flags] <file.s>`
Assemble FILE, map it into executable memory, and run dynamic checks.
+1 -1
View File
@@ -3,7 +3,7 @@
# gasm-devkit — developer tooling for Go's Plan 9 assembler (GAsm).
version := "0.32.0"
version := "0.33.0"
default:
@just --list