| | |
| | |
| | |
| |
|
| | package staticdata |
| |
|
| | import ( |
| | "encoding/base64" |
| | "fmt" |
| | "go/constant" |
| | "io" |
| | "os" |
| | "slices" |
| | "strconv" |
| | "strings" |
| | "sync" |
| |
|
| | "cmd/compile/internal/base" |
| | "cmd/compile/internal/ir" |
| | "cmd/compile/internal/objw" |
| | "cmd/compile/internal/types" |
| | "cmd/internal/hash" |
| | "cmd/internal/obj" |
| | "cmd/internal/objabi" |
| | "cmd/internal/src" |
| | ) |
| |
|
| | |
| | |
| | func InitAddrOffset(n *ir.Name, noff int64, lsym *obj.LSym, off int64) { |
| | if n.Op() != ir.ONAME { |
| | base.Fatalf("InitAddr n op %v", n.Op()) |
| | } |
| | if n.Sym() == nil { |
| | base.Fatalf("InitAddr nil n sym") |
| | } |
| | s := n.Linksym() |
| | s.WriteAddr(base.Ctxt, noff, types.PtrSize, lsym, off) |
| | } |
| |
|
| | |
| | func InitAddr(n *ir.Name, noff int64, lsym *obj.LSym) { |
| | InitAddrOffset(n, noff, lsym, 0) |
| | } |
| |
|
| | |
| | |
| | func InitSlice(n *ir.Name, noff int64, lsym *obj.LSym, lencap int64) { |
| | s := n.Linksym() |
| | s.WriteAddr(base.Ctxt, noff, types.PtrSize, lsym, 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("InitSliceBytes %v", nam) |
| | } |
| | InitSlice(nam, off, slicedata(nam.Pos(), s), int64(len(s))) |
| | } |
| |
|
| | const ( |
| | stringSymPrefix = "go:string." |
| | stringSymPattern = ".gostring.%d.%s" |
| | ) |
| |
|
| | |
| | |
| | func shortHashString(hash []byte) string { |
| | return base64.StdEncoding.EncodeToString(hash[:16]) |
| | } |
| |
|
| | |
| | |
| | func StringSym(pos src.XPos, s string) (data *obj.LSym) { |
| | var symname string |
| | if len(s) > 100 { |
| | |
| | |
| | |
| | |
| | h := hash.New32() |
| | io.WriteString(h, s) |
| | symname = fmt.Sprintf(stringSymPattern, len(s), shortHashString(h.Sum(nil))) |
| | } else { |
| | |
| | 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 |
| | } |
| |
|
| | |
| | |
| | |
| | func StringSymNoCommon(s string) (data *obj.LSym) { |
| | var nameSym obj.LSym |
| | nameSym.WriteString(base.Ctxt, 0, len(s), s) |
| | objw.Global(&nameSym, int32(len(s)), obj.RODATA) |
| | return &nameSym |
| | } |
| |
|
| | |
| | |
| | const maxFileSize = int64(2e9) |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func fileStringSym(pos src.XPos, file string, readonly bool, hashBytes []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 := io.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)) |
| | } |
| | if len(hashBytes) > 0 { |
| | sum := hash.Sum32(data) |
| | copy(hashBytes, sum[:]) |
| | } |
| | return sym, size, nil |
| | } |
| | if size > maxFileSize { |
| | |
| | |
| | |
| | |
| | return nil, 0, fmt.Errorf("file too large (%d bytes > %d bytes)", size, maxFileSize) |
| | } |
| |
|
| | |
| | |
| | var sum []byte |
| | if readonly || len(hashBytes) > 0 { |
| | h := hash.New32() |
| | 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(hashBytes, sum) |
| | } |
| |
|
| | var symdata *obj.LSym |
| | if readonly { |
| | symname := fmt.Sprintf(stringSymPattern, size, shortHashString(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) |
| | |
| | |
| | |
| | } |
| | } else { |
| | |
| | |
| | symdata = slicedata(pos, "") |
| | 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) *obj.LSym { |
| | slicedataGen++ |
| | symname := fmt.Sprintf(".gobytes.%d", slicedataGen) |
| | lsym := types.LocalPkg.Lookup(symname).LinksymABI(obj.ABI0) |
| | off := dstringdata(lsym, 0, s, pos, "slice") |
| | objw.Global(lsym, int32(off), obj.NOPTR|obj.LOCAL) |
| |
|
| | return lsym |
| | } |
| |
|
| | func dstringdata(s *obj.LSym, off int, t string, pos src.XPos, what string) int { |
| | |
| | |
| | |
| | if int64(len(t)) > 2e9 { |
| | base.ErrorfAt(pos, 0, "%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 |
| | funcsyms []*ir.Name |
| | ) |
| |
|
| | |
| | func FuncLinksym(n *ir.Name) *obj.LSym { |
| | if n.Op() != ir.ONAME || n.Class != ir.PFUNC { |
| | base.Fatalf("expected func name: %v", n) |
| | } |
| | s := n.Sym() |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | funcsymsmu.Lock() |
| | sf, existed := s.Pkg.LookupOK(ir.FuncSymName(s)) |
| | if !existed { |
| | funcsyms = append(funcsyms, n) |
| | } |
| | funcsymsmu.Unlock() |
| |
|
| | return sf.Linksym() |
| | } |
| |
|
| | func GlobalLinksym(n *ir.Name) *obj.LSym { |
| | if n.Op() != ir.ONAME || n.Class != ir.PEXTERN { |
| | base.Fatalf("expected global variable: %v", n) |
| | } |
| | return n.Linksym() |
| | } |
| |
|
| | func WriteFuncSyms() { |
| | slices.SortFunc(funcsyms, func(a, b *ir.Name) int { |
| | return strings.Compare(a.Linksym().Name, b.Linksym().Name) |
| | }) |
| | for _, nam := range funcsyms { |
| | s := nam.Sym() |
| | sf := s.Pkg.Lookup(ir.FuncSymName(s)).Linksym() |
| |
|
| | |
| | |
| | |
| | if base.Flag.CompilingRuntime && sf.OnList() { |
| | continue |
| | } |
| |
|
| | |
| | |
| | target := s.Linksym() |
| | if target.ABI() != obj.ABIInternal { |
| | base.Fatalf("expected ABIInternal: %v has %v", target, target.ABI()) |
| | } |
| | objw.SymPtr(sf, 0, target, 0) |
| | objw.Global(sf, int32(types.PtrSize), obj.DUPOK|obj.RODATA) |
| | } |
| | } |
| |
|
| | |
| | |
| | func InitConst(n *ir.Name, noff int64, c ir.Node, wid int) { |
| | if n.Op() != ir.ONAME { |
| | base.Fatalf("InitConst n op %v", n.Op()) |
| | } |
| | if n.Sym() == nil { |
| | base.Fatalf("InitConst nil n sym") |
| | } |
| | if c.Op() == ir.ONIL { |
| | return |
| | } |
| | if c.Op() != ir.OLITERAL { |
| | base.Fatalf("InitConst c op %v", c.Op()) |
| | } |
| | s := n.Linksym() |
| | switch u := c.Val(); u.Kind() { |
| | case constant.Bool: |
| | i := int64(obj.Bool2int(constant.BoolVal(u))) |
| | s.WriteInt(base.Ctxt, noff, wid, i) |
| |
|
| | case constant.Int: |
| | s.WriteInt(base.Ctxt, noff, wid, ir.IntVal(c.Type(), u)) |
| |
|
| | case constant.Float: |
| | f, _ := constant.Float64Val(u) |
| | switch c.Type().Kind() { |
| | case types.TFLOAT32: |
| | s.WriteFloat32(base.Ctxt, noff, float32(f)) |
| | case types.TFLOAT64: |
| | s.WriteFloat64(base.Ctxt, noff, f) |
| | } |
| |
|
| | case constant.Complex: |
| | re, _ := constant.Float64Val(constant.Real(u)) |
| | im, _ := constant.Float64Val(constant.Imag(u)) |
| | switch c.Type().Kind() { |
| | case types.TCOMPLEX64: |
| | s.WriteFloat32(base.Ctxt, noff, float32(re)) |
| | s.WriteFloat32(base.Ctxt, noff+4, float32(im)) |
| | case types.TCOMPLEX128: |
| | s.WriteFloat64(base.Ctxt, noff, re) |
| | s.WriteFloat64(base.Ctxt, noff+8, im) |
| | } |
| |
|
| | case constant.String: |
| | i := constant.StringVal(u) |
| | symdata := 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))) |
| |
|
| | default: |
| | base.Fatalf("InitConst unhandled OLITERAL %v", c) |
| | } |
| | } |
| |
|