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 ## [0.32.0] — 2026-08-31
### Added ### Added
+13 -3
View File
@@ -16,7 +16,8 @@ developer tooling to Plan 9 assembly on amd64, arm64, riscv64 and loong64.
directly. directly.
- **Formatter.** `gasm fmt` canonicalises indentation, operand spacing, - **Formatter.** `gasm fmt` canonicalises indentation, operand spacing,
per-function mnemonic alignment and blank-line layout: `gofmt` for assembly, 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 - **Linter.** `gasm lint` runs 18 conservative static checks, among them
`undefined-label`, `abi-argsize` (declared frame vs the `// func` signature), `undefined-label`, `abi-argsize` (declared frame vs the `// func` signature),
`register-clobber` (Go ABI register liveness over the control-flow graph), `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 - **Standalone assembler.** `gasm asm` encodes all four architectures without
the Go toolchain and writes raw images, linkable ELF objects (with DWARF5 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` 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 - **Dynamic verification.** `gasm verify` JIT-loads assembled functions into
executable memory: smoke calls, ABI checks (sentinel registers, red-zone executable memory: smoke calls, ABI checks (sentinel registers, red-zone
canary), differential fuzzing against the `go tool asm` build, and 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, push and pull diagnostics, semantic-token highlighting, go-to-definition,
find references, rename, formatting, inlay hints, code actions, signature find references, rename, formatting, inlay hints, code actions, signature
help, document highlights, workspace symbol search, #include document 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 - **Comparators and audits.** `gasm diff` compares the machine code of two
assembly files byte-for-byte, `gasm profile` shows basic-block structure, assembly files byte-for-byte, `gasm profile` shows basic-block structure,
`gasm audit-instructions` diffs the encoder against the installed toolchain, `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 ```sh
gasm fmt # reformat every .s below here, like go fmt gasm fmt # reformat every .s below here, like go fmt
gasm fmt -w kernel_amd64.s # canonicalise one file in place 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 lint *.s # static checks
gasm asm --format elf -o k.o k.s # assemble to a linkable ELF object 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 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 --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 verify --fuzz k.s # differential fuzz vs the go tool asm build
gasm debug --func name k.s # interactive debugger 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 // version is the release version, stamped at build time via
// -ldflags "-X main.version=…" (defaulting to the current release). // -ldflags "-X main.version=…" (defaulting to the current release).
var version = "0.32.0" var version = "0.33.0"
func main() { func main() {
if len(os.Args) < 2 { 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 R_ADDRARM64 relocations). Like the other encoders it is validated
byte-for-byte against `GOARCH=arm64 go tool asm`. 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 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 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 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 Parse FILE and report syntax errors on stderr. On success, prints how
many declarations and TEXT functions the file contains. 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, Canonicalise the formatting of Plan 9 assembly sources: indentation,
operand spacing, per-function mnemonic alignment, and blank-line layout. 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 | | Flag | Description |
|------|-------------| |------|-------------|
| `-w` | Write result to the source file (default: print to stdout) | | `-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 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 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`) | | `-p` | Package path (required for `--format goobj`) |
| `-o` | Write output to file (default: hex dump to stdout) | | `-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>` ## `gasm verify [flags] <file.s>`
Assemble FILE, map it into executable memory, and run dynamic checks. 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). # gasm-devkit — developer tooling for Go's Plan 9 assembler (GAsm).
version := "0.32.0" version := "0.33.0"
default: default:
@just --list @just --list