fix(verify): fix non-amd64 JIT trampolines and validate under qemu

This commit is contained in:
2026-08-31 12:34:50 +02:00
parent a5a59d6503
commit 94c4756d47
10 changed files with 77 additions and 43 deletions
+23 -16
View File
@@ -11,10 +11,13 @@ Unreleased changes on the `development` branch.
### Added
- **Multi-architecture debugger.** `gasm debug` works on arm64, riscv64
and loong64 in addition to amd64. Each architecture has its own ptrace
register access, disassembler (`golang.org/x/arch`), register display,
and stop-info handler. The REPL is fully arch-neutral.
- **Multi-architecture debugger.** `gasm debug` carries
per-architecture ptrace register access, disassemblers
(`golang.org/x/arch`), register display, FP register views and
stop-info handlers for arm64, riscv64 and loong64, and the REPL is
arch-neutral. Sessions are runtime-validated on amd64; the other
hosts execute through the now-working JIT trampolines, but their
ptrace loops have not seen hardware yet.
- **Headless debugging.** `gasm debug --script` runs REPL commands from a
file (or stdin) and exits; `--timeout` kills the debuggee when a run
hangs, with the watchdog armed before the ptrace attach. `--cover` runs
@@ -43,18 +46,22 @@ Unreleased changes on the `development` branch.
architectures via hand-written assembly trampolines
(`trampoline_{arm64,riscv64,loong64}.s`) that save the Go stack, switch
to a prepared stack, and branch to the JIT function.
- **ABI checks architecture port (partial).** The ABI-checking
machinery is architecture-neutral (`ABIReport` with `FPClobbered`,
`GClobbered`, `RedZoneHit`; renamed from the amd64-only field names)
and per-architecture checked trampolines exist for arm64, riscv64 and
loong64 alongside amd64, restoring the frame pointer and the goroutine
pointer before returning into Go code. Runtime execution of the
non-amd64 JIT paths is not yet reliable (arm64 and loong64 fault on the
return path and riscv64 returns a wrong result under qemu-user), so
`gasm verify` keeps JIT execution gated to amd64 kernels on amd64
hosts; other kernels take the toolchain-comparison path exactly as
before. A qemu-user harness and GOARCH-guarded tests are in the tree
to validate the trampolines once their return path is fixed.
- **ABI checks on all architectures.** `gasm verify -abi` and the ABI
half of `-fuzz` now work on arm64, riscv64 and loong64 via
per-architecture checked trampolines: sentinels planted in the
registers the Go ABI fixes across calls (amd64 `BP`/`R14`, arm64
`R29`/`R28`, riscv64 `X27`, loong64 `R22`) are verified on return and
the saved registers restored before Go code resumes, with the
below-SP canary on every architecture. The root cause of the broken
non-amd64 calls was a stack misalignment: the trampolines advanced SP
past the linkage slot while the kernels read their first argument at
SP+8. riscv64 is validated end to end under qemu-user; arm64 shares
the fix and matches the observed frame convention; loong64 stays
ground-truth-only until hardware validation (the Go runtime cannot
start under the available loong64 emulators). `verify.Load` now
assembles each file with the encoder its name suffix calls for. The
`ABIReport` fields are renamed to the architecture-neutral
`FPClobbered` and `GClobbered`.
- **Hardware watchpoints on all architectures.** arm64 uses DBGWVR/DBGWCR
via `PTRACE_SETREGSET` with `NT_ARM_HW_BREAK`; riscv64 and loong64 use
`PTRACE_POKEUSER` to access trigger/debug registers.