diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/cmd/compile/internal/noder/linker.go | 1 | ||||
| -rw-r--r-- | src/cmd/compile/internal/noder/noder.go | 9 | ||||
| -rw-r--r-- | src/cmd/compile/internal/noder/reader.go | 7 | ||||
| -rw-r--r-- | src/cmd/compile/internal/noder/writer.go | 33 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssagen/abi.go | 3 | ||||
| -rw-r--r-- | src/cmd/internal/goobj/objfile.go | 2 | ||||
| -rw-r--r-- | src/cmd/internal/obj/link.go | 5 | ||||
| -rw-r--r-- | src/cmd/internal/obj/objfile.go | 3 | ||||
| -rw-r--r-- | src/cmd/link/internal/loader/loader.go | 25 | ||||
| -rw-r--r-- | src/iter/iter.go | 2 | ||||
| -rw-r--r-- | src/runtime/coro.go | 2 |
11 files changed, 67 insertions, 25 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, diff --git a/src/iter/iter.go b/src/iter/iter.go index f119eae995..57d19d047b 100644 --- a/src/iter/iter.go +++ b/src/iter/iter.go @@ -233,7 +233,7 @@ type coro struct{} //go:linkname newcoro runtime.newcoro func newcoro(func(*coro)) *coro -//go:linkname coroswitch runtime.coroswitch +//go:linknamestd coroswitch runtime.coroswitch func coroswitch(*coro) // Pull converts the “push-style” iterator sequence seq diff --git a/src/runtime/coro.go b/src/runtime/coro.go index 40d4e47fbe..72c58b7964 100644 --- a/src/runtime/coro.go +++ b/src/runtime/coro.go @@ -84,7 +84,7 @@ func coroexit(c *coro) { mcall(coroswitch_m) } -//go:linkname coroswitch +//go:linknamestd coroswitch // coroswitch switches to the goroutine blocked on c // and then blocks the current goroutine on c. |
