aboutsummaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd')
-rw-r--r--src/cmd/compile/internal/noder/linker.go1
-rw-r--r--src/cmd/compile/internal/noder/noder.go9
-rw-r--r--src/cmd/compile/internal/noder/reader.go7
-rw-r--r--src/cmd/compile/internal/noder/writer.go33
-rw-r--r--src/cmd/compile/internal/ssagen/abi.go3
-rw-r--r--src/cmd/internal/goobj/objfile.go2
-rw-r--r--src/cmd/internal/obj/link.go5
-rw-r--r--src/cmd/internal/obj/objfile.go3
-rw-r--r--src/cmd/link/internal/loader/loader.go25
9 files changed, 65 insertions, 23 deletions
diff --git a/src/cmd/compile/internal/noder/linker.go b/src/cmd/compile/internal/noder/linker.go
index 51b03a1897..df1e248398 100644
--- a/src/cmd/compile/internal/noder/linker.go
+++ b/src/cmd/compile/internal/noder/linker.go
@@ -338,6 +338,7 @@ func (l *linker) linkname(w *pkgbits.Encoder, name *ir.Name) {
linkname := name.Sym().Linkname
if !l.lsymIdx(w, linkname, name.Linksym()) {
w.String(linkname)
+ w.Bool(name.Linksym().IsLinknameStd())
}
}
diff --git a/src/cmd/compile/internal/noder/noder.go b/src/cmd/compile/internal/noder/noder.go
index 973d917784..4e48126e82 100644
--- a/src/cmd/compile/internal/noder/noder.go
+++ b/src/cmd/compile/internal/noder/noder.go
@@ -103,9 +103,10 @@ type noder struct {
err chan syntax.Error
}
-// linkname records a //go:linkname directive.
+// linkname records a //go:linkname or //go:linknamestd directive.
type linkname struct {
pos syntax.Pos
+ std bool
local string
remote string
}
@@ -273,10 +274,10 @@ func (p *noder) pragma(pos syntax.Pos, blankLine bool, text string, old syntax.P
}
}
- case strings.HasPrefix(text, "go:linkname "):
+ case strings.HasPrefix(text, "go:linkname "), strings.HasPrefix(text, "go:linknamestd "):
f := strings.Fields(text)
if !(2 <= len(f) && len(f) <= 3) {
- p.error(syntax.Error{Pos: pos, Msg: "usage: //go:linkname localname [linkname]"})
+ p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf("usage: //%s localname [linkname]", f[0])})
break
}
// The second argument is optional. If omitted, we use
@@ -294,7 +295,7 @@ func (p *noder) pragma(pos syntax.Pos, blankLine bool, text string, old syntax.P
} else {
panic("missing pkgpath")
}
- p.linknames = append(p.linknames, linkname{pos, f[1], target})
+ p.linknames = append(p.linknames, linkname{pos, f[0] == "go:linknamestd", f[1], target})
case text == "go:embed", strings.HasPrefix(text, "go:embed "):
args, err := parseGoEmbed(text[len("go:embed"):])
diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go
index 00710775d6..ebb5043a05 100644
--- a/src/cmd/compile/internal/noder/reader.go
+++ b/src/cmd/compile/internal/noder/reader.go
@@ -1277,6 +1277,7 @@ func (r *reader) linkname(name *ir.Name) {
lsym.Set(obj.AttrIndexed, true)
} else {
linkname := r.String()
+ std := r.Bool()
sym := name.Sym()
sym.Linkname = linkname
if sym.Pkg == types.LocalPkg && linkname != "" {
@@ -1286,7 +1287,11 @@ func (r *reader) linkname(name *ir.Name) {
// corresponding packages). So we can tell in which package
// the linkname is used (pulled), and the linker can
// make a decision for allowing or disallowing it.
- sym.Linksym().Set(obj.AttrLinkname, true)
+ if std {
+ sym.Linksym().Set(obj.AttrLinknameStd, true)
+ } else {
+ sym.Linksym().Set(obj.AttrLinkname, true)
+ }
}
}
}
diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go
index 9e0f4fc9c8..027d7e0636 100644
--- a/src/cmd/compile/internal/noder/writer.go
+++ b/src/cmd/compile/internal/noder/writer.go
@@ -86,8 +86,11 @@ type pkgWriter struct {
typDecls map[*types2.TypeName]typeDeclGen
// linknames maps package-scope objects to their linker symbol name,
- // if specified by a //go:linkname directive.
- linknames map[types2.Object]string
+ // if specified by a //go:linkname or //go:linknamestd directive.
+ linknames map[types2.Object]struct {
+ remote string
+ std bool
+ }
// cgoPragmas accumulates any //go:cgo_* pragmas that need to be
// passed through to cmd/link.
@@ -114,7 +117,10 @@ func newPkgWriter(m posMap, pkg *types2.Package, info *types2.Info, otherInfo ma
funDecls: make(map[*types2.Func]*syntax.FuncDecl),
typDecls: make(map[*types2.TypeName]typeDeclGen),
- linknames: make(map[types2.Object]string),
+ linknames: make(map[types2.Object]struct {
+ remote string
+ std bool
+ }),
}
}
@@ -1175,7 +1181,9 @@ func (w *writer) varExt(obj *types2.Var) {
func (w *writer) linkname(obj types2.Object) {
w.Sync(pkgbits.SyncLinkname)
w.Int64(-1)
- w.String(w.p.linknames[obj])
+ info := w.p.linknames[obj]
+ w.String(info.remote)
+ w.Bool(info.std)
}
func (w *writer) pragmaFlag(p ir.PragmaFlag) {
@@ -2799,26 +2807,33 @@ func (pw *pkgWriter) collectDecls(noders []*noder) {
pw.cgoPragmas = append(pw.cgoPragmas, p.pragcgobuf...)
for _, l := range p.linknames {
+ directive := "go:linkname"
+ if l.std {
+ directive = "go:linknamestd"
+ }
if !file.importedUnsafe {
- pw.errorf(l.pos, "//go:linkname only allowed in Go files that import \"unsafe\"")
+ pw.errorf(l.pos, "//%s only allowed in Go files that import \"unsafe\"", directive)
continue
}
if strings.Contains(l.remote, "[") && strings.Contains(l.remote, "]") {
- pw.errorf(l.pos, "//go:linkname reference of an instantiation is not allowed")
+ pw.errorf(l.pos, "//%s reference of an instantiation is not allowed", directive)
continue
}
switch obj := pw.curpkg.Scope().Lookup(l.local).(type) {
case *types2.Func, *types2.Var:
if _, ok := pw.linknames[obj]; !ok {
- pw.linknames[obj] = l.remote
+ pw.linknames[obj] = struct {
+ remote string
+ std bool
+ }{l.remote, l.std}
} else {
- pw.errorf(l.pos, "duplicate //go:linkname for %s", l.local)
+ pw.errorf(l.pos, "duplicate //%s for %s", directive, l.local)
}
default:
if types.AllowsGoVersion(1, 18) {
- pw.errorf(l.pos, "//go:linkname must refer to declared function or variable")
+ pw.errorf(l.pos, "//%s must refer to declared function or variable", directive)
}
}
}
diff --git a/src/cmd/compile/internal/ssagen/abi.go b/src/cmd/compile/internal/ssagen/abi.go
index 0e8dbd9445..107e48c8c9 100644
--- a/src/cmd/compile/internal/ssagen/abi.go
+++ b/src/cmd/compile/internal/ssagen/abi.go
@@ -168,6 +168,9 @@ func (s *SymABIs) GenABIWrappers() {
if sym.Linksym().IsLinkname() {
sym.LinksymABI(fn.ABI).Set(obj.AttrLinkname, true)
}
+ if sym.Linksym().IsLinknameStd() {
+ sym.LinksymABI(fn.ABI).Set(obj.AttrLinknameStd, true)
+ }
}
// If cgo-exported, add the definition ABI to the cgo
diff --git a/src/cmd/internal/goobj/objfile.go b/src/cmd/internal/goobj/objfile.go
index cca3c840e0..679f4357e2 100644
--- a/src/cmd/internal/goobj/objfile.go
+++ b/src/cmd/internal/goobj/objfile.go
@@ -306,6 +306,7 @@ const (
SymFlagDict
SymFlagPkgInit
SymFlagLinkname
+ SymFlagLinknameStd
SymFlagABIWrapper
SymFlagWasmExport
)
@@ -340,6 +341,7 @@ func (s *Sym) IsItab() bool { return s.Flag2()&SymFlagItab != 0 }
func (s *Sym) IsDict() bool { return s.Flag2()&SymFlagDict != 0 }
func (s *Sym) IsPkgInit() bool { return s.Flag2()&SymFlagPkgInit != 0 }
func (s *Sym) IsLinkname() bool { return s.Flag2()&SymFlagLinkname != 0 }
+func (s *Sym) IsLinknameStd() bool { return s.Flag2()&SymFlagLinknameStd != 0 }
func (s *Sym) ABIWrapper() bool { return s.Flag2()&SymFlagABIWrapper != 0 }
func (s *Sym) WasmExport() bool { return s.Flag2()&SymFlagWasmExport != 0 }
diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go
index 088a7c57aa..69c9e7583b 100644
--- a/src/cmd/internal/obj/link.go
+++ b/src/cmd/internal/obj/link.go
@@ -977,6 +977,9 @@ const (
// Linkname indicates this is a go:linkname'd symbol.
AttrLinkname
+ // LinknameStd indicates this is a go:linknamestd'd symbol.
+ AttrLinknameStd
+
// attrABIBase is the value at which the ABI is encoded in
// Attribute. This must be last; all bits after this are
// assumed to be an ABI value.
@@ -1007,6 +1010,7 @@ func (a *Attribute) ABIWrapper() bool { return a.load()&AttrABIWrapper !
func (a *Attribute) IsPcdata() bool { return a.load()&AttrPcdata != 0 }
func (a *Attribute) IsPkgInit() bool { return a.load()&AttrPkgInit != 0 }
func (a *Attribute) IsLinkname() bool { return a.load()&AttrLinkname != 0 }
+func (a *Attribute) IsLinknameStd() bool { return a.load()&AttrLinknameStd != 0 }
func (a *Attribute) Set(flag Attribute, value bool) {
for {
@@ -1057,6 +1061,7 @@ var textAttrStrings = [...]struct {
{bit: AttrABIWrapper, s: "ABIWRAPPER"},
{bit: AttrPkgInit, s: "PKGINIT"},
{bit: AttrLinkname, s: "LINKNAME"},
+ {bit: AttrLinknameStd, s: "LINKNAMESTD"},
}
// String formats a for printing in as part of a TEXT prog.
diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go
index ea1483de01..de5f172b11 100644
--- a/src/cmd/internal/obj/objfile.go
+++ b/src/cmd/internal/obj/objfile.go
@@ -360,6 +360,9 @@ func (w *writer) Sym(s *LSym) {
// The runtime linknames main.main.
flag2 |= goobj.SymFlagLinkname
}
+ if s.IsLinknameStd() {
+ flag2 |= goobj.SymFlagLinknameStd
+ }
if s.ABIWrapper() {
flag2 |= goobj.SymFlagABIWrapper
}
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,