4.7 KiB
Deferred decisions
Design decisions deliberately postponed, with enough context to pick them up again without re-deriving the analysis. Each entry records what is deferred, why, the options on the table, and the trigger that should reopen it.
GOOBJ external (cross-package) symbol references
Status: resolved (v0.29.0+, 2026-08-07).
Approach taken. Instead of parsing the compiler's iexport data (which
would have required either golang.org/x/tools or an in-house parser), the
resolver reads the GOOBJ data directly from the target package's .a
archive. The .a file contains a _go_.o member whose GOOBJ s is the
same one gasm writes; the parser reuses the same layout (blkSymdef,
blkNonpkgdef, the string table), so no new dependency was needed.
How it works.
go list -json -export <pkg>finds the target package's.afile.extractGOOBJreads the ar archive, finds the_go_.omember, skips the"go object …\n!\n"preamble and parses the GOOBJ header.goobjFile.symbols()walksblkSymdefandblkNonpkgdefin definition order (the same order the linker uses) to build the symbol-to-index mapping.resolveExternalSymbolswires the resolved{PkgIdx, SymIdx}into the GOOBJ emission.
The resolver is invoked automatically when img.Externals is non-empty; it
runs go list as a subprocess (consistent with toolchainObjectPreamble
which already calls go tool asm). All symbol data is cached per package
for the lifetime of the GOOBJ emission.
2026-08-30 non-amd64 JIT execution trampolines
Status: open (blocks runtime verification on arm64, riscv64 and loong64 hosts).
State. The per-architecture trampolines compile for all targets, the
kernels they execute are byte-for-byte correct against go tool asm, and
under qemu-aarch64 the arm64 kernel demonstrably executes and stores its
result correctly. The failure is on the return path into Go code: arm64
and loong64 take a SIGSEGV after the kernel's RET (the Go-side unwind
through leaveJIT and its interposed ABIInternal wrapper is the suspect),
and riscv64 returns cleanly but with an untouched result area. amd64 is
unaffected (the checked trampoline saves and restores BP/R14 and the flow
is validated end to end).
Evidence harness. verify/jit_arch_test.go (plain call) and
verify/abi_arch_test.go (checked call) are GOARCH-guarded tests; build
the test binary per target (GOARCH=arm64 go test -c -o v.test ./verify/)
and run it under qemu-aarch64-static from the verify/ directory. A
minimal reproducer pattern lives in the qemu exploration notes: verify
loads, the kernel executes, the fault follows the return.
Fix direction. Compare the amd64 checked trampoline (GLOBL/DATA raw
address, explicit SP/BP/R14 save-restore) against the arm64/riscv64/
loong64 leaveJIT unwind, in particular the interaction with the
ABIInternal wrapper that reflect.ValueOf(leaveJIT).Pointer() returns.
The plain-call path (no sentinels) fails the same way, so the checked
path is not the variable.
2026-08-29 tooling round
lint abi0-register-args: flags kernels whose// funcparameters are never read from the FP frame. Motivated by a real latent bug: kernels reading arguments from registers pass every test while the autogeneratedF.abi0wrapper happens to leave the caller's register values intact, and break on a toolchain upgrade.lint nonportable-register-name: the RAX/EAX register spellings are a gasm extension; go tool asm rejects them, so files using them only link through the gasm goobj path.lint unencodable-instruction: a mnemonic in the architecture table thatasm.Encodablerejects is flagged at edit time instead of failing at assembly time.audit-instructions: black-box diff of the encoder against go tool asm. As of this round the tables fully overlap on names; the audit exists to catch drift in both directions (future supersets and future gaps).scaffold differential: generates the direct-call differential skeleton (two independent seed sets, output and in-place buffer comparison) that a pipeline-level fuzz can never replace.verify --args: scalar arguments for-call, closing the repro gap where only buffers could be supplied.debug --script/--timeout/--cover: headless debugging with a watchdog armed before the ptrace attach (untracing sandboxes hang the attach), and label-level block coverage for the "did my test ever enter that branch" question.- Superset policy remains: gasm may accept spellings and encodings go tool
asm lacks, but such kernels ship only via
gasm asm --format goobj; the audit reports the superset surface. The register-alias superset is warned about by lint because the defaultgo buildpath cannot consume it.