Skip to content

[AUTOMATED] Pin the goroutine g register as a typed global (option goreg, default on with the golang spec) - #1276

Merged
mahaloz merged 1 commit into
mainfrom
multilang-go-greg
Oct 26, 2026
Merged

mahaloz merged 1 commit into
mainfrom
multilang-go-greg

Conversation

@mahaloz

@mahaloz mahaloz commented Oct 26, 2026

Copy link
Copy Markdown
Contributor

With the golang cspec selected, the goroutine register still rendered as a phantom local in a quarter of all functions — declared, read, never assigned:

go build -ldflags="-s -w" -o hello main.go
kuna decompile hello runtime.unlock2 --json --option goreg off | grep r14
#   long v3; // r14 ... *(long *)(v3 + 0x10) = -0x522;
kuna decompile hello runtime.unlock2 --json | grep stackguard
#   g->stackguard0 = 0xfffffffffffffade;   // the preemption request, as the runtime spells it

The fix:

  • At spec build, when the golang compiler spec is active, the g register (amd64 R14, arm64 x28 — both stated by the vendored register.info; x86-32 golang is TLS-based and correctly gets none) joins the global scope exactly the way a cspec <global><register/> entry would, with a type- and name-locked g symbol — the vendored specs stay pristine.
  • runtime.g and runtime.gobuf shell types are synthesized with only source-verified fields: the liblink-stated release-stable prefix (stackguard0, _panic, m), the gobuf at 0x38, and the go1.22-pinned tail through goid; accesses past the shell render as anchored offsets off g rather than phantom arithmetic.
  • goreg on|off, default on; inert without the golang spec by construction (it requires goabi's selection).

Measured on a stripped go1.22 build (1,543 functions): functions declaring a phantom // r14 local 267 → 23; functions reading named g-> fields 7 → 297; wall +1.1% (budget 5%), inert off-Go.

Tests: verify_goreg e2e over a real stripped build pins both directions on runtime.unlock2; hermetic unit tests pin the shell offsets against the runtime source and the golang-id gate. Datatests 675/675 unchanged.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WoTv7T2Ep5hmbZcyYSMk1g

… goreg, default on)

Under the Go register ABI the current goroutine lives in a pinned register
(R14 on amd64, x28 on arm64 - the vendored golang register.info values); the
cspec lists it unaffected and no pentry names it, so every access rendered as
a phantom local (v3; // r14) fed by unexplained arithmetic. With the golang
cspec active (goabi), the register's storage now joins the global scope (the
cspec <global><register/> mechanism applied kuna-side; the vendored spec
stays pristine) and a type+name-locked `g` symbol typed runtime.g * maps over
it. runtime.g / runtime.gobuf are synthesized shells carrying exactly the
fields the go1.22 runtime source states for the register-ABI era (liblink
prefix stable across releases; tail go1.22-pinned; past-prefix accesses stay
anchored as offsets off g). Load-time env bridge KUNA_GOREG (the goabi seam);
structurally inert off-Go; a golang target with no pinned register (x86-32,
TLS) is untouched.

Measured on the stripped go1.22 hello-world (1,543 fns): phantom // r14
functions 267 -> 23, named g-> field readers 7 -> 297, runtime.unlock2
renders g->stackguard0 = 0xfffffffffffffade exactly as the runtime source
spells the preemption request. Speed: interleaved min-of-3 decompile-all on
the witness 18.79 s on vs 18.59 s off (+1.1%, a load-time symbol install;
budget 5%).

Gates: make test PARITY OK, make test-stages PARITY OK (baseline re-record:
the renamed catalog #15), make rust-test exit 0 (clean), make check-spec OK,
make test-cli 306/306, make lint clean, kuna catalog --check OK. E2E
verify_goreg (own [[test]]: the off arm mutates env) builds a real stripped
go binary and pins both directions; unit tests pin the shell offsets against
the runtime source and the golang-id gate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WoTv7T2Ep5hmbZcyYSMk1g
@mahaloz
mahaloz merged commit 9a602c9 into main Oct 26, 2026
9 checks passed
@mahaloz
mahaloz deleted the multilang-go-greg branch October 26, 2026 01:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant