docs: record the deferred GOOBJ external-symbols decision
This commit is contained in:
@@ -0,0 +1,56 @@
|
|||||||
|
# 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:** deferred (v0.15.0, 2026-08-02). The GOOBJ emitter resolves only
|
||||||
|
symbols defined in the file being assembled; a reference to any other symbol
|
||||||
|
is rejected.
|
||||||
|
|
||||||
|
**Why it is deferred.** GOOBJ symbol references are *positional*: a
|
||||||
|
reference is a `{PkgIdx, SymIdx}` pair, where `SymIdx` is the index of the
|
||||||
|
symbol in the *referenced package's* symbol-definition table. That ordering
|
||||||
|
is not derivable from the reference site — it lives in the referenced
|
||||||
|
package's gc export data (the iexport binary format, which evolves with the
|
||||||
|
toolchain). `cmd/asm` reads it with `cmd/internal` readers gasm cannot
|
||||||
|
import, so emitting external references means either parsing export data
|
||||||
|
ourselves or taking a dependency that does.
|
||||||
|
|
||||||
|
**What works today.** Single-package objects: every symbol the file defines
|
||||||
|
(as `TEXT` or `GLOBL`, static or exported) and every reference to them.
|
||||||
|
This covers the production use case — the go-flac / go-lz4 kernels carry no
|
||||||
|
`FUNCDATA`/`PCDATA`, hence no references into `runtime`, and the Go side
|
||||||
|
references the assembly symbols, never the reverse. Such a package builds
|
||||||
|
with its assembly object replaced by a gasm-emitted one.
|
||||||
|
|
||||||
|
**The options, when we return.**
|
||||||
|
|
||||||
|
1. **`golang.org/x/tools/go/gcexportdata` as a production dependency.**
|
||||||
|
The straightforward path: read each imported package's export file
|
||||||
|
(paths from `-importcfg` or `go list -export`), assign symbol indices in
|
||||||
|
its symbol order, write `PkgIndex`/`Autolib` entries (fingerprints from
|
||||||
|
the export files' build IDs) and positional references. Robust across
|
||||||
|
toolchain versions — `x/tools` tracks the format. **Cost:** the first
|
||||||
|
production dependency beyond the standard library, an explicit deviation
|
||||||
|
from the "production code depends only on the standard library"
|
||||||
|
principle in the README. Requires the user's explicit agreement.
|
||||||
|
2. **A minimal iexport parser of our own.** Preserves self-containment.
|
||||||
|
Substantial effort and inherently fragile: the format is an internal
|
||||||
|
contract that changes with Go releases, so the parser needs a
|
||||||
|
version-gated fallback and regression tests against several toolchains.
|
||||||
|
3. **Shell out to the toolchain for symbol metadata.** Consistent with the
|
||||||
|
existing GOOBJ preamble probe (which already runs `go tool asm`), but no
|
||||||
|
toolchain command exposes a package's symbols *in definition-index
|
||||||
|
order* — `go tool nm` sorts differently — so this does not solve the
|
||||||
|
core problem on its own; it would only feed option 1 or 2.
|
||||||
|
|
||||||
|
**Trigger to reopen.** An assembly file that needs a cross-package
|
||||||
|
reference — in practice `FUNCDATA $…, runtime·…(SB)` (stack maps / GC
|
||||||
|
metadata written in assembly), or any kernel that calls into another
|
||||||
|
package directly. Until then, option 3's limitation is moot and the
|
||||||
|
single-package emitter suffices.
|
||||||
Reference in New Issue
Block a user