var nowritebarrierrecCheck *nowritebarrierrecChecker
-// funcsym returns s·f.
-func funcsym(s *types.Sym) *types.Sym {
- // funcsymsmu here serves to protect not just mutations of funcsyms (below),
- // but also the package lookup of the func sym name,
- // since this function gets called concurrently from the backend.
- // There are no other concurrent package lookups in the backend,
- // except for the types package, which is protected separately.
- // Reusing funcsymsmu to also cover this package lookup
- // avoids a general, broader, expensive package lookup mutex.
- // Note makefuncsym also does package look-up of func sym names,
- // but that it is only called serially, from the front end.
- funcsymsmu.Lock()
- sf, existed := s.Pkg.LookupOK(ir.FuncSymName(s))
- // Don't export s·f when compiling for dynamic linking.
- // When dynamically linking, the necessary function
- // symbols will be created explicitly with makefuncsym.
- // See the makefuncsym comment for details.
- if !base.Ctxt.Flag_dynlink && !existed {
- funcsyms = append(funcsyms, s)
- }
- funcsymsmu.Unlock()
- return sf
-}
-
-// makefuncsym ensures that s·f is exported.
-// It is only used with -dynlink.
-// When not compiling for dynamic linking,
-// the funcsyms are created as needed by
-// the packages that use them.
-// Normally we emit the s·f stubs as DUPOK syms,
-// but DUPOK doesn't work across shared library boundaries.
-// So instead, when dynamic linking, we only create
-// the s·f stubs in s's package.
-func makefuncsym(s *types.Sym) {
- if !base.Ctxt.Flag_dynlink {
- base.Fatalf("makefuncsym dynlink")
- }
- if s.IsBlank() {
- return
- }
- if base.Flag.CompilingRuntime && (s.Name == "getg" || s.Name == "getclosureptr" || s.Name == "getcallerpc" || s.Name == "getcallersp") {
- // runtime.getg(), getclosureptr(), getcallerpc(), and
- // getcallersp() are not real functions and so do not
- // get funcsyms.
- return
- }
- if _, existed := s.Pkg.LookupOK(ir.FuncSymName(s)); !existed {
- funcsyms = append(funcsyms, s)
- }
-}
-
type nowritebarrierrecChecker struct {
// extraCalls contains extra function calls that may not be
// visible during later analysis. It maps from the ODCLFUNC of
import (
"cmd/compile/internal/objw"
"cmd/compile/internal/ssa"
- "cmd/compile/internal/types"
"cmd/internal/obj"
- "sync"
)
var pragcgobuf [][]string
var zerosize int64
-var (
- funcsymsmu sync.Mutex // protects funcsyms and associated package lookups (see func funcsym)
- funcsyms []*types.Sym
-)
-
// interface to back end
type Arch struct {
"cmd/compile/internal/logopt"
"cmd/compile/internal/noder"
"cmd/compile/internal/ssa"
+ "cmd/compile/internal/staticdata"
"cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/dwarf"
typecheck.Target = new(ir.Package)
- typecheck.NeedFuncSym = makefuncsym
+ typecheck.NeedFuncSym = staticdata.NeedFuncSym
typecheck.NeedITab = func(t, iface *types.Type) { itabname(t, iface) }
typecheck.NeedRuntimeType = addsignat // TODO(rsc): typenamesym for lock?
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/objw"
+ "cmd/compile/internal/staticdata"
"cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/archive"
"cmd/internal/bio"
"cmd/internal/obj"
"cmd/internal/objabi"
- "cmd/internal/src"
- "crypto/sha256"
"encoding/json"
"fmt"
"go/constant"
- "io"
- "io/ioutil"
- "os"
- "sort"
- "strconv"
)
// These modes say which kind of object file to generate.
numDecls := len(typecheck.Target.Decls)
dumpglobls(typecheck.Target.Externs)
- dumpfuncsyms()
+ staticdata.WriteFuncSyms()
addptabs()
numExports := len(typecheck.Target.Exports)
addsignats(typecheck.Target.Externs)
}
}
-func dumpfuncsyms() {
- sort.Slice(funcsyms, func(i, j int) bool {
- return funcsyms[i].LinksymName() < funcsyms[j].LinksymName()
- })
- for _, s := range funcsyms {
- sf := s.Pkg.Lookup(ir.FuncSymName(s)).Linksym()
- objw.SymPtr(sf, 0, s.Linksym(), 0)
- objw.Global(sf, int32(types.PtrSize), obj.DUPOK|obj.RODATA)
- }
-}
-
// addGCLocals adds gcargs, gclocals, gcregs, and stack object symbols to Ctxt.Data.
//
// This is done during the sequential phase after compilation, since
}
}
-const (
- stringSymPrefix = "go.string."
- stringSymPattern = ".gostring.%d.%x"
-)
-
-// stringsym returns a symbol containing the string s.
-// The symbol contains the string data, not a string header.
-func stringsym(pos src.XPos, s string) (data *obj.LSym) {
- var symname string
- if len(s) > 100 {
- // Huge strings are hashed to avoid long names in object files.
- // Indulge in some paranoia by writing the length of s, too,
- // as protection against length extension attacks.
- // Same pattern is known to fileStringSym below.
- h := sha256.New()
- io.WriteString(h, s)
- symname = fmt.Sprintf(stringSymPattern, len(s), h.Sum(nil))
- } else {
- // Small strings get named directly by their contents.
- symname = strconv.Quote(s)
- }
-
- symdata := base.Ctxt.Lookup(stringSymPrefix + symname)
- if !symdata.OnList() {
- off := dstringdata(symdata, 0, s, pos, "string")
- objw.Global(symdata, int32(off), obj.DUPOK|obj.RODATA|obj.LOCAL)
- symdata.Set(obj.AttrContentAddressable, true)
- }
-
- return symdata
-}
-
-// fileStringSym returns a symbol for the contents and the size of file.
-// If readonly is true, the symbol shares storage with any literal string
-// or other file with the same content and is placed in a read-only section.
-// If readonly is false, the symbol is a read-write copy separate from any other,
-// for use as the backing store of a []byte.
-// The content hash of file is copied into hash. (If hash is nil, nothing is copied.)
-// The returned symbol contains the data itself, not a string header.
-func fileStringSym(pos src.XPos, file string, readonly bool, hash []byte) (*obj.LSym, int64, error) {
- f, err := os.Open(file)
- if err != nil {
- return nil, 0, err
- }
- defer f.Close()
- info, err := f.Stat()
- if err != nil {
- return nil, 0, err
- }
- if !info.Mode().IsRegular() {
- return nil, 0, fmt.Errorf("not a regular file")
- }
- size := info.Size()
- if size <= 1*1024 {
- data, err := ioutil.ReadAll(f)
- if err != nil {
- return nil, 0, err
- }
- if int64(len(data)) != size {
- return nil, 0, fmt.Errorf("file changed between reads")
- }
- var sym *obj.LSym
- if readonly {
- sym = stringsym(pos, string(data))
- } else {
- sym = slicedata(pos, string(data)).Sym().Linksym()
- }
- if len(hash) > 0 {
- sum := sha256.Sum256(data)
- copy(hash, sum[:])
- }
- return sym, size, nil
- }
- if size > 2e9 {
- // ggloblsym takes an int32,
- // and probably the rest of the toolchain
- // can't handle such big symbols either.
- // See golang.org/issue/9862.
- return nil, 0, fmt.Errorf("file too large")
- }
-
- // File is too big to read and keep in memory.
- // Compute hash if needed for read-only content hashing or if the caller wants it.
- var sum []byte
- if readonly || len(hash) > 0 {
- h := sha256.New()
- n, err := io.Copy(h, f)
- if err != nil {
- return nil, 0, err
- }
- if n != size {
- return nil, 0, fmt.Errorf("file changed between reads")
- }
- sum = h.Sum(nil)
- copy(hash, sum)
- }
-
- var symdata *obj.LSym
- if readonly {
- symname := fmt.Sprintf(stringSymPattern, size, sum)
- symdata = base.Ctxt.Lookup(stringSymPrefix + symname)
- if !symdata.OnList() {
- info := symdata.NewFileInfo()
- info.Name = file
- info.Size = size
- objw.Global(symdata, int32(size), obj.DUPOK|obj.RODATA|obj.LOCAL)
- // Note: AttrContentAddressable cannot be set here,
- // because the content-addressable-handling code
- // does not know about file symbols.
- }
- } else {
- // Emit a zero-length data symbol
- // and then fix up length and content to use file.
- symdata = slicedata(pos, "").Sym().Linksym()
- symdata.Size = size
- symdata.Type = objabi.SNOPTRDATA
- info := symdata.NewFileInfo()
- info.Name = file
- info.Size = size
- }
-
- return symdata, size, nil
-}
-
-var slicedataGen int
-
-func slicedata(pos src.XPos, s string) *ir.Name {
- slicedataGen++
- symname := fmt.Sprintf(".gobytes.%d", slicedataGen)
- sym := types.LocalPkg.Lookup(symname)
- symnode := typecheck.NewName(sym)
- sym.Def = symnode
-
- lsym := sym.Linksym()
- off := dstringdata(lsym, 0, s, pos, "slice")
- objw.Global(lsym, int32(off), obj.NOPTR|obj.LOCAL)
-
- return symnode
-}
-
-func slicebytes(nam *ir.Name, off int64, s string) {
- if nam.Op() != ir.ONAME {
- base.Fatalf("slicebytes %v", nam)
- }
- slicesym(nam, off, slicedata(nam.Pos(), s), int64(len(s)))
-}
-
-func dstringdata(s *obj.LSym, off int, t string, pos src.XPos, what string) int {
- // Objects that are too large will cause the data section to overflow right away,
- // causing a cryptic error message by the linker. Check for oversize objects here
- // and provide a useful error message instead.
- if int64(len(t)) > 2e9 {
- base.ErrorfAt(pos, "%v with length %v is too big", what, len(t))
- return 0
- }
-
- s.WriteString(base.Ctxt, int64(off), len(t), t)
- return off + len(t)
-}
-
-// slicesym writes a static slice symbol {&arr, lencap, lencap} to n+noff.
-// slicesym does not modify n.
-func slicesym(n *ir.Name, noff int64, arr *ir.Name, lencap int64) {
- s := n.Sym().Linksym()
- if arr.Op() != ir.ONAME {
- base.Fatalf("slicesym non-name arr %v", arr)
- }
- s.WriteAddr(base.Ctxt, noff, types.PtrSize, arr.Sym().Linksym(), 0)
- s.WriteInt(base.Ctxt, noff+types.SliceLenOffset, types.PtrSize, lencap)
- s.WriteInt(base.Ctxt, noff+types.SliceCapOffset, types.PtrSize, lencap)
-}
-
-// addrsym writes the static address of a to n. a must be an ONAME.
-// Neither n nor a is modified.
-func addrsym(n *ir.Name, noff int64, a *ir.Name, aoff int64) {
- if n.Op() != ir.ONAME {
- base.Fatalf("addrsym n op %v", n.Op())
- }
- if n.Sym() == nil {
- base.Fatalf("addrsym nil n sym")
- }
- if a.Op() != ir.ONAME {
- base.Fatalf("addrsym a op %v", a.Op())
- }
- s := n.Sym().Linksym()
- s.WriteAddr(base.Ctxt, noff, types.PtrSize, a.Sym().Linksym(), aoff)
-}
-
-// pfuncsym writes the static address of f to n. f must be a global function.
-// Neither n nor f is modified.
-func pfuncsym(n *ir.Name, noff int64, f *ir.Name) {
- if n.Op() != ir.ONAME {
- base.Fatalf("pfuncsym n op %v", n.Op())
- }
- if n.Sym() == nil {
- base.Fatalf("pfuncsym nil n sym")
- }
- if f.Class_ != ir.PFUNC {
- base.Fatalf("pfuncsym class not PFUNC %d", f.Class_)
- }
- s := n.Sym().Linksym()
- s.WriteAddr(base.Ctxt, noff, types.PtrSize, funcsym(f.Sym()).Linksym(), 0)
-}
-
// litsym writes the static literal c to n.
// Neither n nor c is modified.
func litsym(n *ir.Name, noff int64, c ir.Node, wid int) {
case constant.String:
i := constant.StringVal(u)
- symdata := stringsym(n.Pos(), i)
+ symdata := staticdata.StringSym(n.Pos(), i)
s.WriteAddr(base.Ctxt, noff, types.PtrSize, symdata, 0)
s.WriteInt(base.Ctxt, noff+int64(types.PtrSize), types.PtrSize, int64(len(i)))
s.Pkg = "_"
}
}
+
+func dumpembeds() {
+ for _, v := range typecheck.Target.Embeds {
+ staticdata.WriteEmbed(v)
+ }
+}
import (
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
+ "cmd/compile/internal/staticdata"
"cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/obj"
func (s *InitSchedule) staticcopy(l *ir.Name, loff int64, rn *ir.Name, typ *types.Type) bool {
if rn.Class_ == ir.PFUNC {
// TODO if roff != 0 { panic }
- pfuncsym(l, loff, rn)
+ staticdata.InitFunc(l, loff, rn)
return true
}
if rn.Class_ != ir.PEXTERN || rn.Sym().Pkg != types.LocalPkg {
r := r.(*ir.AddrExpr)
if a := r.X; a.Op() == ir.ONAME {
a := a.(*ir.Name)
- addrsym(l, loff, a, 0)
+ staticdata.InitAddr(l, loff, a, 0)
return true
}
switch r.X.Op() {
case ir.OARRAYLIT, ir.OSLICELIT, ir.OSTRUCTLIT, ir.OMAPLIT:
// copy pointer
- addrsym(l, loff, s.inittemps[r], 0)
+ staticdata.InitAddr(l, loff, s.inittemps[r], 0)
return true
}
case ir.OSLICELIT:
r := r.(*ir.CompLitExpr)
// copy slice
- slicesym(l, loff, s.inittemps[r], r.Len)
+ staticdata.InitSlice(l, loff, s.inittemps[r], r.Len)
return true
case ir.OARRAYLIT, ir.OSTRUCTLIT:
case ir.OADDR:
r := r.(*ir.AddrExpr)
if name, offset, ok := stataddr(r.X); ok {
- addrsym(l, loff, name, offset)
+ staticdata.InitAddr(l, loff, name, offset)
return true
}
fallthrough
a := staticname(r.X.Type())
s.inittemps[r] = a
- addrsym(l, loff, a, 0)
+ staticdata.InitAddr(l, loff, a, 0)
// Init underlying literal.
if !s.staticassign(a, 0, r.X, a.Type()) {
r := r.(*ir.ConvExpr)
if l.Class_ == ir.PEXTERN && r.X.Op() == ir.OLITERAL {
sval := ir.StringVal(r.X)
- slicebytes(l, loff, sval)
+ staticdata.InitSliceBytes(l, loff, sval)
return true
}
ta.SetNoalg(true)
a := staticname(ta)
s.inittemps[r] = a
- slicesym(l, loff, a, r.Len)
+ staticdata.InitSlice(l, loff, a, r.Len)
// Fall through to init underlying array.
l = a
loff = 0
// Closures with no captured variables are globals,
// so the assignment can be done at link time.
// TODO if roff != 0 { panic }
- pfuncsym(l, loff, r.Func.Nname)
+ staticdata.InitFunc(l, loff, r.Func.Nname)
return true
}
closuredebugruntimecheck(r)
// Create a copy of l to modify while we emit data.
// Emit itab, advance offset.
- addrsym(l, loff, itab.X.(*ir.Name), 0)
+ staticdata.InitAddr(l, loff, itab.X.(*ir.Name), 0)
// Emit data.
if types.IsDirectIface(val.Type()) {
if !s.staticassign(a, 0, val, val.Type()) {
s.append(ir.NewAssignStmt(base.Pos, a, val))
}
- addrsym(l, loff+int64(types.PtrSize), a, 0)
+ staticdata.InitAddr(l, loff+int64(types.PtrSize), a, 0)
}
return true
if !ok || name.Class_ != ir.PEXTERN {
base.Fatalf("slicelit: %v", var_)
}
- slicesym(name, offset, vstat, t.NumElem())
+ staticdata.InitSlice(name, offset, vstat, t.NumElem())
return
}
return
case ir.OMETHEXPR:
r := r.(*ir.MethodExpr)
- pfuncsym(name, offset, r.FuncName())
+ staticdata.InitFunc(name, offset, r.FuncName())
return
case ir.ONAME:
r := r.(*ir.Name)
base.Fatalf("genAsStatic %+v", as)
}
if r.Class_ == ir.PFUNC {
- pfuncsym(name, offset, r)
+ staticdata.InitFunc(name, offset, r)
return
}
}
"cmd/compile/internal/liveness"
"cmd/compile/internal/objw"
"cmd/compile/internal/ssa"
+ "cmd/compile/internal/staticdata"
"cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/obj"
return s.entryNewValue1A(ssa.OpAddr, n.Type(), aux, s.sb)
case ir.OMETHEXPR:
n := n.(*ir.MethodExpr)
- sym := funcsym(n.FuncName().Sym()).Linksym()
+ sym := staticdata.FuncSym(n.FuncName().Sym()).Linksym()
return s.entryNewValue1A(ssa.OpAddr, types.NewPtr(n.Type()), sym, s.sb)
case ir.ONAME:
n := n.(*ir.Name)
if n.Class_ == ir.PFUNC {
// "value" of a function is the address of the function's closure
- sym := funcsym(n.Sym()).Linksym()
+ sym := staticdata.FuncSym(n.Sym()).Linksym()
return s.entryNewValue1A(ssa.OpAddr, types.NewPtr(n.Type()), sym, s.sb)
}
if s.canSSA(n) {
if e.strings == nil {
e.strings = make(map[string]*obj.LSym)
}
- data := stringsym(e.curfn.Pos(), s)
+ data := staticdata.StringSym(e.curfn.Pos(), s)
e.strings[s] = data
return data
}
"cmd/compile/internal/base"
"cmd/compile/internal/escape"
"cmd/compile/internal/ir"
+ "cmd/compile/internal/staticdata"
"cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/obj"
// Emit string symbol now to avoid emitting
// any concurrently during the backend.
if v := n.Val(); v.Kind() == constant.String {
- _ = stringsym(n.Pos(), constant.StringVal(v))
+ _ = staticdata.StringSym(n.Pos(), constant.StringVal(v))
}
}
--- /dev/null
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package staticdata
+
+import (
+ "crypto/sha256"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "sort"
+ "strconv"
+ "sync"
+
+ "cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
+ "cmd/compile/internal/objw"
+ "cmd/compile/internal/typecheck"
+ "cmd/compile/internal/types"
+ "cmd/internal/obj"
+ "cmd/internal/objabi"
+ "cmd/internal/src"
+)
+
+// InitAddr writes the static address of a to n. a must be an ONAME.
+// Neither n nor a is modified.
+func InitAddr(n *ir.Name, noff int64, a *ir.Name, aoff int64) {
+ if n.Op() != ir.ONAME {
+ base.Fatalf("addrsym n op %v", n.Op())
+ }
+ if n.Sym() == nil {
+ base.Fatalf("addrsym nil n sym")
+ }
+ if a.Op() != ir.ONAME {
+ base.Fatalf("addrsym a op %v", a.Op())
+ }
+ s := n.Sym().Linksym()
+ s.WriteAddr(base.Ctxt, noff, types.PtrSize, a.Sym().Linksym(), aoff)
+}
+
+// InitFunc writes the static address of f to n. f must be a global function.
+// Neither n nor f is modified.
+func InitFunc(n *ir.Name, noff int64, f *ir.Name) {
+ if n.Op() != ir.ONAME {
+ base.Fatalf("pfuncsym n op %v", n.Op())
+ }
+ if n.Sym() == nil {
+ base.Fatalf("pfuncsym nil n sym")
+ }
+ if f.Class_ != ir.PFUNC {
+ base.Fatalf("pfuncsym class not PFUNC %d", f.Class_)
+ }
+ s := n.Sym().Linksym()
+ s.WriteAddr(base.Ctxt, noff, types.PtrSize, FuncSym(f.Sym()).Linksym(), 0)
+}
+
+// InitSlice writes a static slice symbol {&arr, lencap, lencap} to n+noff.
+// InitSlice does not modify n.
+func InitSlice(n *ir.Name, noff int64, arr *ir.Name, lencap int64) {
+ s := n.Sym().Linksym()
+ if arr.Op() != ir.ONAME {
+ base.Fatalf("slicesym non-name arr %v", arr)
+ }
+ s.WriteAddr(base.Ctxt, noff, types.PtrSize, arr.Sym().Linksym(), 0)
+ s.WriteInt(base.Ctxt, noff+types.SliceLenOffset, types.PtrSize, lencap)
+ s.WriteInt(base.Ctxt, noff+types.SliceCapOffset, types.PtrSize, lencap)
+}
+
+func InitSliceBytes(nam *ir.Name, off int64, s string) {
+ if nam.Op() != ir.ONAME {
+ base.Fatalf("slicebytes %v", nam)
+ }
+ InitSlice(nam, off, slicedata(nam.Pos(), s), int64(len(s)))
+}
+
+const (
+ stringSymPrefix = "go.string."
+ stringSymPattern = ".gostring.%d.%x"
+)
+
+// StringSym returns a symbol containing the string s.
+// The symbol contains the string data, not a string header.
+func StringSym(pos src.XPos, s string) (data *obj.LSym) {
+ var symname string
+ if len(s) > 100 {
+ // Huge strings are hashed to avoid long names in object files.
+ // Indulge in some paranoia by writing the length of s, too,
+ // as protection against length extension attacks.
+ // Same pattern is known to fileStringSym below.
+ h := sha256.New()
+ io.WriteString(h, s)
+ symname = fmt.Sprintf(stringSymPattern, len(s), h.Sum(nil))
+ } else {
+ // Small strings get named directly by their contents.
+ symname = strconv.Quote(s)
+ }
+
+ symdata := base.Ctxt.Lookup(stringSymPrefix + symname)
+ if !symdata.OnList() {
+ off := dstringdata(symdata, 0, s, pos, "string")
+ objw.Global(symdata, int32(off), obj.DUPOK|obj.RODATA|obj.LOCAL)
+ symdata.Set(obj.AttrContentAddressable, true)
+ }
+
+ return symdata
+}
+
+// fileStringSym returns a symbol for the contents and the size of file.
+// If readonly is true, the symbol shares storage with any literal string
+// or other file with the same content and is placed in a read-only section.
+// If readonly is false, the symbol is a read-write copy separate from any other,
+// for use as the backing store of a []byte.
+// The content hash of file is copied into hash. (If hash is nil, nothing is copied.)
+// The returned symbol contains the data itself, not a string header.
+func fileStringSym(pos src.XPos, file string, readonly bool, hash []byte) (*obj.LSym, int64, error) {
+ f, err := os.Open(file)
+ if err != nil {
+ return nil, 0, err
+ }
+ defer f.Close()
+ info, err := f.Stat()
+ if err != nil {
+ return nil, 0, err
+ }
+ if !info.Mode().IsRegular() {
+ return nil, 0, fmt.Errorf("not a regular file")
+ }
+ size := info.Size()
+ if size <= 1*1024 {
+ data, err := ioutil.ReadAll(f)
+ if err != nil {
+ return nil, 0, err
+ }
+ if int64(len(data)) != size {
+ return nil, 0, fmt.Errorf("file changed between reads")
+ }
+ var sym *obj.LSym
+ if readonly {
+ sym = StringSym(pos, string(data))
+ } else {
+ sym = slicedata(pos, string(data)).Sym().Linksym()
+ }
+ if len(hash) > 0 {
+ sum := sha256.Sum256(data)
+ copy(hash, sum[:])
+ }
+ return sym, size, nil
+ }
+ if size > 2e9 {
+ // ggloblsym takes an int32,
+ // and probably the rest of the toolchain
+ // can't handle such big symbols either.
+ // See golang.org/issue/9862.
+ return nil, 0, fmt.Errorf("file too large")
+ }
+
+ // File is too big to read and keep in memory.
+ // Compute hash if needed for read-only content hashing or if the caller wants it.
+ var sum []byte
+ if readonly || len(hash) > 0 {
+ h := sha256.New()
+ n, err := io.Copy(h, f)
+ if err != nil {
+ return nil, 0, err
+ }
+ if n != size {
+ return nil, 0, fmt.Errorf("file changed between reads")
+ }
+ sum = h.Sum(nil)
+ copy(hash, sum)
+ }
+
+ var symdata *obj.LSym
+ if readonly {
+ symname := fmt.Sprintf(stringSymPattern, size, sum)
+ symdata = base.Ctxt.Lookup(stringSymPrefix + symname)
+ if !symdata.OnList() {
+ info := symdata.NewFileInfo()
+ info.Name = file
+ info.Size = size
+ objw.Global(symdata, int32(size), obj.DUPOK|obj.RODATA|obj.LOCAL)
+ // Note: AttrContentAddressable cannot be set here,
+ // because the content-addressable-handling code
+ // does not know about file symbols.
+ }
+ } else {
+ // Emit a zero-length data symbol
+ // and then fix up length and content to use file.
+ symdata = slicedata(pos, "").Sym().Linksym()
+ symdata.Size = size
+ symdata.Type = objabi.SNOPTRDATA
+ info := symdata.NewFileInfo()
+ info.Name = file
+ info.Size = size
+ }
+
+ return symdata, size, nil
+}
+
+var slicedataGen int
+
+func slicedata(pos src.XPos, s string) *ir.Name {
+ slicedataGen++
+ symname := fmt.Sprintf(".gobytes.%d", slicedataGen)
+ sym := types.LocalPkg.Lookup(symname)
+ symnode := typecheck.NewName(sym)
+ sym.Def = symnode
+
+ lsym := sym.Linksym()
+ off := dstringdata(lsym, 0, s, pos, "slice")
+ objw.Global(lsym, int32(off), obj.NOPTR|obj.LOCAL)
+
+ return symnode
+}
+
+func dstringdata(s *obj.LSym, off int, t string, pos src.XPos, what string) int {
+ // Objects that are too large will cause the data section to overflow right away,
+ // causing a cryptic error message by the linker. Check for oversize objects here
+ // and provide a useful error message instead.
+ if int64(len(t)) > 2e9 {
+ base.ErrorfAt(pos, "%v with length %v is too big", what, len(t))
+ return 0
+ }
+
+ s.WriteString(base.Ctxt, int64(off), len(t), t)
+ return off + len(t)
+}
+
+var (
+ funcsymsmu sync.Mutex // protects funcsyms and associated package lookups (see func funcsym)
+ funcsyms []*types.Sym
+)
+
+// FuncSym returns s·f.
+func FuncSym(s *types.Sym) *types.Sym {
+ // funcsymsmu here serves to protect not just mutations of funcsyms (below),
+ // but also the package lookup of the func sym name,
+ // since this function gets called concurrently from the backend.
+ // There are no other concurrent package lookups in the backend,
+ // except for the types package, which is protected separately.
+ // Reusing funcsymsmu to also cover this package lookup
+ // avoids a general, broader, expensive package lookup mutex.
+ // Note makefuncsym also does package look-up of func sym names,
+ // but that it is only called serially, from the front end.
+ funcsymsmu.Lock()
+ sf, existed := s.Pkg.LookupOK(ir.FuncSymName(s))
+ // Don't export s·f when compiling for dynamic linking.
+ // When dynamically linking, the necessary function
+ // symbols will be created explicitly with makefuncsym.
+ // See the makefuncsym comment for details.
+ if !base.Ctxt.Flag_dynlink && !existed {
+ funcsyms = append(funcsyms, s)
+ }
+ funcsymsmu.Unlock()
+ return sf
+}
+
+// NeedFuncSym ensures that s·f is exported.
+// It is only used with -dynlink.
+// When not compiling for dynamic linking,
+// the funcsyms are created as needed by
+// the packages that use them.
+// Normally we emit the s·f stubs as DUPOK syms,
+// but DUPOK doesn't work across shared library boundaries.
+// So instead, when dynamic linking, we only create
+// the s·f stubs in s's package.
+func NeedFuncSym(s *types.Sym) {
+ if !base.Ctxt.Flag_dynlink {
+ base.Fatalf("makefuncsym dynlink")
+ }
+ if s.IsBlank() {
+ return
+ }
+ if base.Flag.CompilingRuntime && (s.Name == "getg" || s.Name == "getclosureptr" || s.Name == "getcallerpc" || s.Name == "getcallersp") {
+ // runtime.getg(), getclosureptr(), getcallerpc(), and
+ // getcallersp() are not real functions and so do not
+ // get funcsyms.
+ return
+ }
+ if _, existed := s.Pkg.LookupOK(ir.FuncSymName(s)); !existed {
+ funcsyms = append(funcsyms, s)
+ }
+}
+
+func WriteFuncSyms() {
+ sort.Slice(funcsyms, func(i, j int) bool {
+ return funcsyms[i].LinksymName() < funcsyms[j].LinksymName()
+ })
+ for _, s := range funcsyms {
+ sf := s.Pkg.Lookup(ir.FuncSymName(s)).Linksym()
+ objw.SymPtr(sf, 0, s.Linksym(), 0)
+ objw.Global(sf, int32(types.PtrSize), obj.DUPOK|obj.RODATA)
+ }
+}
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package gc
+package staticdata
import (
+ "path"
+ "sort"
+ "strings"
+
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/objw"
- "cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/obj"
-
- "path"
- "sort"
- "strings"
)
const (
return xdir < ydir || xdir == ydir && xelem < yelem
}
-func dumpembeds() {
- for _, v := range typecheck.Target.Embeds {
- initEmbed(v)
- }
-}
-
-// initEmbed emits the init data for a //go:embed variable,
+// WriteEmbed emits the init data for a //go:embed variable,
// which is either a string, a []byte, or an embed.FS.
-func initEmbed(v *ir.Name) {
+func WriteEmbed(v *ir.Name) {
files := embedFileList(v)
switch kind := embedKind(v.Type()); kind {
case embedUnknown:
const hashSize = 16
hash := make([]byte, hashSize)
for _, file := range files {
- off = objw.SymPtr(slicedata, off, stringsym(v.Pos(), file), 0) // file string
+ off = objw.SymPtr(slicedata, off, StringSym(v.Pos(), file), 0) // file string
off = objw.Uintptr(slicedata, off, uint64(len(file)))
if strings.HasSuffix(file, "/") {
// entry for directory - no data