aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/link/internal/loader/loader.go
diff options
context:
space:
mode:
authorCherry Mui <cherryyz@google.com>2025-11-25 13:54:18 -0500
committerCherry Mui <cherryyz@google.com>2026-04-01 11:00:13 -0700
commit46755cb4dea406093296ead4250ff5f7091c04a2 (patch)
tree4558617545a2c0b2dc924d2f95c15655ccb74ee3 /src/cmd/link/internal/loader/loader.go
parent8ea160279ff6700282f254d6b74fb02f8a316abe (diff)
downloadgo-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/loader/loader.go')
-rw-r--r--src/cmd/link/internal/loader/loader.go25
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,