diff options
| author | Cherry Mui <cherryyz@google.com> | 2025-11-25 13:54:18 -0500 |
|---|---|---|
| committer | Cherry Mui <cherryyz@google.com> | 2026-04-01 11:00:13 -0700 |
| commit | 46755cb4dea406093296ead4250ff5f7091c04a2 (patch) | |
| tree | 4558617545a2c0b2dc924d2f95c15655ccb74ee3 /src/cmd/link/internal | |
| parent | 8ea160279ff6700282f254d6b74fb02f8a316abe (diff) | |
| download | go-46755cb4dea406093296ead4250ff5f7091c04a2.tar.xz | |
cmd/compile, cmd/link: add linknamestd directive for std-only linknames
In the standard library, there are a number of linknames, for
sharing symbols within the standard library. They are not supposed
to be accessed externally. But currently there is no good
mechanism to prevent that. In the linker we have a blocklist of
linknames, which forbids linkname references other than explicitly
allowed packages. The blocklist is manually maintained, requiring
periodic manual update.
To move away from that manually maintained blocklist, this CL
introduces a new directive, linknamestd, that marks a linkname
for use within the standard library only. The linker will allow
references within the standard library and forbid others.
For a proof of concept, runtime.coroswitch is removed from the
blocklist, and replaced with linknamestd. An external reference to
it is still disallowed by the linker, as tested with
cmd/link.TestCheckLinkname with testdata/linkname/coro.go.
Change-Id: I0d0f8746b8835d8cdcfc3ff835d22a551da5f038
Reviewed-on: https://go-review.googlesource.com/c/go/+/749942
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: David Chase <drchase@google.com>
Diffstat (limited to 'src/cmd/link/internal')
| -rw-r--r-- | src/cmd/link/internal/loader/loader.go | 25 |
1 files changed, 16 insertions, 9 deletions
diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go index 9ac2b9201d..100ebd4dce 100644 --- a/src/cmd/link/internal/loader/loader.go +++ b/src/cmd/link/internal/loader/loader.go @@ -2220,7 +2220,7 @@ type loadState struct { } type linknameVarRef struct { - pkg string // package of reference (not definition) + pkg *oReader // package of reference (not definition) name string sym Sym } @@ -2257,7 +2257,7 @@ func (st *loadState) preloadSyms(r *oReader, kind int) { } gi := st.addSym(name, v, r, i, kind, osym) r.syms[i] = gi - if kind == nonPkgDef && osym.IsLinkname() && r.DataSize(i) == 0 && strings.Contains(name, ".") { + if kind == nonPkgDef && (osym.IsLinkname() || osym.IsLinknameStd()) && r.DataSize(i) == 0 && strings.Contains(name, ".") { // This is a linknamed "var" "reference" (var x T with no data and //go:linkname x). // We want to check if a linkname reference is allowed. Here we haven't loaded all // symbol definitions, so we don't yet know all the push linknames. So we add to a @@ -2268,7 +2268,7 @@ func (st *loadState) preloadSyms(r *oReader, kind int) { // This use of linkname is usually for referencing C symbols, so allow symbols // with no "." in its name (not a regular Go symbol). // Linkname is always a non-package reference. - st.linknameVarRefs = append(st.linknameVarRefs, linknameVarRef{r.unit.Lib.Pkg, name, gi}) + st.linknameVarRefs = append(st.linknameVarRefs, linknameVarRef{r, name, gi}) } if osym.Local() { l.SetAttrLocal(gi, true) @@ -2346,12 +2346,12 @@ func loadObjRefs(l *Loader, r *oReader, arch *sys.Arch) { v := abiToVer(osym.ABI(), r.version) gi := l.LookupOrCreateSym(name, v) r.syms[ndef+i] = gi - if osym.IsLinkname() { + if osym.IsLinkname() || osym.IsLinknameStd() { // Check if a linkname reference is allowed. // Only check references (pull), not definitions (push), // so push is always allowed. // Linkname is always a non-package reference. - l.checkLinkname(r.unit.Lib.Pkg, name, gi) + l.checkLinkname(r, name, gi) } if osym.Local() { l.SetAttrLocal(gi, true) @@ -2405,8 +2405,7 @@ func abiToVer(abi uint16, localSymVersion int) int { // even if it has a linknamed definition. var blockedLinknames = map[string][]string{ // coroutines - "runtime.coroswitch": {"iter"}, - "runtime.newcoro": {"iter"}, + "runtime.newcoro": {"iter"}, // fips info "go:fipsinfo": {"crypto/internal/fips140/check"}, // New internal linknames in Go 1.24 @@ -2492,12 +2491,13 @@ var blockedLinknames = map[string][]string{ "runtime.addmoduledata": {}, // assembly symbol, disallow all packages } -// check if a linkname reference to symbol s from pkg is allowed -func (l *Loader) checkLinkname(pkg, name string, s Sym) { +// check if a linkname reference to symbol s from refpkg is allowed +func (l *Loader) checkLinkname(refpkg *oReader, name string, s Sym) { if l.flags&FlagCheckLinkname == 0 { return } + pkg := refpkg.unit.Lib.Pkg error := func() { log.Fatalf("%s: invalid reference to %s", pkg, name) } @@ -2531,6 +2531,13 @@ func (l *Loader) checkLinkname(pkg, name string, s Sym) { return } osym := r.Sym(li) + if osym.IsLinknameStd() { + // It is pushed with linknamestd. Allow only pulls from the + // standard library. + if refpkg.Std() { + return + } + } if osym.IsLinkname() || osym.ABIWrapper() { // Allow if the def has a linkname (push). // ABI wrapper usually wraps an assembly symbol, a linknamed symbol, |
