Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/compile/internal/staticdata/data.go

Documentation: cmd/compile/internal/staticdata

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package staticdata
     6  
     7  import (
     8  	"crypto/sha256"
     9  	"fmt"
    10  	"go/constant"
    11  	"internal/buildcfg"
    12  	"io"
    13  	"io/ioutil"
    14  	"os"
    15  	"sort"
    16  	"strconv"
    17  	"sync"
    18  
    19  	"cmd/compile/internal/base"
    20  	"cmd/compile/internal/ir"
    21  	"cmd/compile/internal/objw"
    22  	"cmd/compile/internal/typecheck"
    23  	"cmd/compile/internal/types"
    24  	"cmd/internal/obj"
    25  	"cmd/internal/objabi"
    26  	"cmd/internal/src"
    27  )
    28  
    29  // InitAddrOffset writes the static name symbol lsym to n, it does not modify n.
    30  // It's the caller responsibility to make sure lsym is from ONAME/PEXTERN node.
    31  func InitAddrOffset(n *ir.Name, noff int64, lsym *obj.LSym, off int64) {
    32  	if n.Op() != ir.ONAME {
    33  		base.Fatalf("InitAddr n op %v", n.Op())
    34  	}
    35  	if n.Sym() == nil {
    36  		base.Fatalf("InitAddr nil n sym")
    37  	}
    38  	s := n.Linksym()
    39  	s.WriteAddr(base.Ctxt, noff, types.PtrSize, lsym, off)
    40  }
    41  
    42  // InitAddr is InitAddrOffset, with offset fixed to 0.
    43  func InitAddr(n *ir.Name, noff int64, lsym *obj.LSym) {
    44  	InitAddrOffset(n, noff, lsym, 0)
    45  }
    46  
    47  // InitSlice writes a static slice symbol {lsym, lencap, lencap} to n+noff, it does not modify n.
    48  // It's the caller responsibility to make sure lsym is from ONAME node.
    49  func InitSlice(n *ir.Name, noff int64, lsym *obj.LSym, lencap int64) {
    50  	s := n.Linksym()
    51  	s.WriteAddr(base.Ctxt, noff, types.PtrSize, lsym, 0)
    52  	s.WriteInt(base.Ctxt, noff+types.SliceLenOffset, types.PtrSize, lencap)
    53  	s.WriteInt(base.Ctxt, noff+types.SliceCapOffset, types.PtrSize, lencap)
    54  }
    55  
    56  func InitSliceBytes(nam *ir.Name, off int64, s string) {
    57  	if nam.Op() != ir.ONAME {
    58  		base.Fatalf("InitSliceBytes %v", nam)
    59  	}
    60  	InitSlice(nam, off, slicedata(nam.Pos(), s).Linksym(), int64(len(s)))
    61  }
    62  
    63  const (
    64  	stringSymPrefix  = "go.string."
    65  	stringSymPattern = ".gostring.%d.%x"
    66  )
    67  
    68  // StringSym returns a symbol containing the string s.
    69  // The symbol contains the string data, not a string header.
    70  func StringSym(pos src.XPos, s string) (data *obj.LSym) {
    71  	var symname string
    72  	if len(s) > 100 {
    73  		// Huge strings are hashed to avoid long names in object files.
    74  		// Indulge in some paranoia by writing the length of s, too,
    75  		// as protection against length extension attacks.
    76  		// Same pattern is known to fileStringSym below.
    77  		h := sha256.New()
    78  		io.WriteString(h, s)
    79  		symname = fmt.Sprintf(stringSymPattern, len(s), h.Sum(nil))
    80  	} else {
    81  		// Small strings get named directly by their contents.
    82  		symname = strconv.Quote(s)
    83  	}
    84  
    85  	symdata := base.Ctxt.Lookup(stringSymPrefix + symname)
    86  	if !symdata.OnList() {
    87  		off := dstringdata(symdata, 0, s, pos, "string")
    88  		objw.Global(symdata, int32(off), obj.DUPOK|obj.RODATA|obj.LOCAL)
    89  		symdata.Set(obj.AttrContentAddressable, true)
    90  	}
    91  
    92  	return symdata
    93  }
    94  
    95  // fileStringSym returns a symbol for the contents and the size of file.
    96  // If readonly is true, the symbol shares storage with any literal string
    97  // or other file with the same content and is placed in a read-only section.
    98  // If readonly is false, the symbol is a read-write copy separate from any other,
    99  // for use as the backing store of a []byte.
   100  // The content hash of file is copied into hash. (If hash is nil, nothing is copied.)
   101  // The returned symbol contains the data itself, not a string header.
   102  func fileStringSym(pos src.XPos, file string, readonly bool, hash []byte) (*obj.LSym, int64, error) {
   103  	f, err := os.Open(file)
   104  	if err != nil {
   105  		return nil, 0, err
   106  	}
   107  	defer f.Close()
   108  	info, err := f.Stat()
   109  	if err != nil {
   110  		return nil, 0, err
   111  	}
   112  	if !info.Mode().IsRegular() {
   113  		return nil, 0, fmt.Errorf("not a regular file")
   114  	}
   115  	size := info.Size()
   116  	if size <= 1*1024 {
   117  		data, err := ioutil.ReadAll(f)
   118  		if err != nil {
   119  			return nil, 0, err
   120  		}
   121  		if int64(len(data)) != size {
   122  			return nil, 0, fmt.Errorf("file changed between reads")
   123  		}
   124  		var sym *obj.LSym
   125  		if readonly {
   126  			sym = StringSym(pos, string(data))
   127  		} else {
   128  			sym = slicedata(pos, string(data)).Linksym()
   129  		}
   130  		if len(hash) > 0 {
   131  			sum := sha256.Sum256(data)
   132  			copy(hash, sum[:])
   133  		}
   134  		return sym, size, nil
   135  	}
   136  	if size > 2e9 {
   137  		// ggloblsym takes an int32,
   138  		// and probably the rest of the toolchain
   139  		// can't handle such big symbols either.
   140  		// See golang.org/issue/9862.
   141  		return nil, 0, fmt.Errorf("file too large")
   142  	}
   143  
   144  	// File is too big to read and keep in memory.
   145  	// Compute hash if needed for read-only content hashing or if the caller wants it.
   146  	var sum []byte
   147  	if readonly || len(hash) > 0 {
   148  		h := sha256.New()
   149  		n, err := io.Copy(h, f)
   150  		if err != nil {
   151  			return nil, 0, err
   152  		}
   153  		if n != size {
   154  			return nil, 0, fmt.Errorf("file changed between reads")
   155  		}
   156  		sum = h.Sum(nil)
   157  		copy(hash, sum)
   158  	}
   159  
   160  	var symdata *obj.LSym
   161  	if readonly {
   162  		symname := fmt.Sprintf(stringSymPattern, size, sum)
   163  		symdata = base.Ctxt.Lookup(stringSymPrefix + symname)
   164  		if !symdata.OnList() {
   165  			info := symdata.NewFileInfo()
   166  			info.Name = file
   167  			info.Size = size
   168  			objw.Global(symdata, int32(size), obj.DUPOK|obj.RODATA|obj.LOCAL)
   169  			// Note: AttrContentAddressable cannot be set here,
   170  			// because the content-addressable-handling code
   171  			// does not know about file symbols.
   172  		}
   173  	} else {
   174  		// Emit a zero-length data symbol
   175  		// and then fix up length and content to use file.
   176  		symdata = slicedata(pos, "").Linksym()
   177  		symdata.Size = size
   178  		symdata.Type = objabi.SNOPTRDATA
   179  		info := symdata.NewFileInfo()
   180  		info.Name = file
   181  		info.Size = size
   182  	}
   183  
   184  	return symdata, size, nil
   185  }
   186  
   187  var slicedataGen int
   188  
   189  func slicedata(pos src.XPos, s string) *ir.Name {
   190  	slicedataGen++
   191  	symname := fmt.Sprintf(".gobytes.%d", slicedataGen)
   192  	sym := types.LocalPkg.Lookup(symname)
   193  	symnode := typecheck.NewName(sym)
   194  	sym.Def = symnode
   195  
   196  	lsym := symnode.Linksym()
   197  	off := dstringdata(lsym, 0, s, pos, "slice")
   198  	objw.Global(lsym, int32(off), obj.NOPTR|obj.LOCAL)
   199  
   200  	return symnode
   201  }
   202  
   203  func dstringdata(s *obj.LSym, off int, t string, pos src.XPos, what string) int {
   204  	// Objects that are too large will cause the data section to overflow right away,
   205  	// causing a cryptic error message by the linker. Check for oversize objects here
   206  	// and provide a useful error message instead.
   207  	if int64(len(t)) > 2e9 {
   208  		base.ErrorfAt(pos, "%v with length %v is too big", what, len(t))
   209  		return 0
   210  	}
   211  
   212  	s.WriteString(base.Ctxt, int64(off), len(t), t)
   213  	return off + len(t)
   214  }
   215  
   216  var (
   217  	funcsymsmu sync.Mutex // protects funcsyms and associated package lookups (see func funcsym)
   218  	funcsyms   []*ir.Name // functions that need function value symbols
   219  )
   220  
   221  // FuncLinksym returns n·f, the function value symbol for n.
   222  func FuncLinksym(n *ir.Name) *obj.LSym {
   223  	if n.Op() != ir.ONAME || n.Class != ir.PFUNC {
   224  		base.Fatalf("expected func name: %v", n)
   225  	}
   226  	s := n.Sym()
   227  
   228  	// funcsymsmu here serves to protect not just mutations of funcsyms (below),
   229  	// but also the package lookup of the func sym name,
   230  	// since this function gets called concurrently from the backend.
   231  	// There are no other concurrent package lookups in the backend,
   232  	// except for the types package, which is protected separately.
   233  	// Reusing funcsymsmu to also cover this package lookup
   234  	// avoids a general, broader, expensive package lookup mutex.
   235  	// Note NeedFuncSym also does package look-up of func sym names,
   236  	// but that it is only called serially, from the front end.
   237  	funcsymsmu.Lock()
   238  	sf, existed := s.Pkg.LookupOK(ir.FuncSymName(s))
   239  	// Don't export s·f when compiling for dynamic linking.
   240  	// When dynamically linking, the necessary function
   241  	// symbols will be created explicitly with NeedFuncSym.
   242  	// See the NeedFuncSym comment for details.
   243  	if !base.Ctxt.Flag_dynlink && !existed {
   244  		funcsyms = append(funcsyms, n)
   245  	}
   246  	funcsymsmu.Unlock()
   247  
   248  	return sf.Linksym()
   249  }
   250  
   251  func GlobalLinksym(n *ir.Name) *obj.LSym {
   252  	if n.Op() != ir.ONAME || n.Class != ir.PEXTERN {
   253  		base.Fatalf("expected global variable: %v", n)
   254  	}
   255  	return n.Linksym()
   256  }
   257  
   258  // NeedFuncSym ensures that fn·f is exported, if needed.
   259  // It is only used with -dynlink.
   260  // When not compiling for dynamic linking,
   261  // the funcsyms are created as needed by
   262  // the packages that use them.
   263  // Normally we emit the fn·f stubs as DUPOK syms,
   264  // but DUPOK doesn't work across shared library boundaries.
   265  // So instead, when dynamic linking, we only create
   266  // the fn·f stubs in fn's package.
   267  func NeedFuncSym(fn *ir.Func) {
   268  	if base.Ctxt.InParallel {
   269  		// The append below probably just needs to lock
   270  		// funcsymsmu, like in FuncSym.
   271  		base.Fatalf("NeedFuncSym must be called in serial")
   272  	}
   273  	if fn.ABI != obj.ABIInternal && buildcfg.Experiment.RegabiWrappers {
   274  		// Function values must always reference ABIInternal
   275  		// entry points, so it doesn't make sense to create a
   276  		// funcsym for other ABIs.
   277  		//
   278  		// (If we're using ABI aliases, it doesn't matter.)
   279  		base.Fatalf("expected ABIInternal: %v has %v", fn.Nname, fn.ABI)
   280  	}
   281  	if ir.IsBlank(fn.Nname) {
   282  		// Blank functions aren't unique, so we can't make a
   283  		// funcsym for them.
   284  		base.Fatalf("NeedFuncSym called for _")
   285  	}
   286  	if !base.Ctxt.Flag_dynlink {
   287  		return
   288  	}
   289  	s := fn.Nname.Sym()
   290  	if base.Flag.CompilingRuntime && (s.Name == "getg" || s.Name == "getclosureptr" || s.Name == "getcallerpc" || s.Name == "getcallersp") ||
   291  		(base.Ctxt.Pkgpath == "internal/abi" && (s.Name == "FuncPCABI0" || s.Name == "FuncPCABIInternal")) {
   292  		// runtime.getg(), getclosureptr(), getcallerpc(), getcallersp(),
   293  		// and internal/abi.FuncPCABIxxx() are not real functions and so
   294  		// do not get funcsyms.
   295  		return
   296  	}
   297  	funcsyms = append(funcsyms, fn.Nname)
   298  }
   299  
   300  func WriteFuncSyms() {
   301  	sort.Slice(funcsyms, func(i, j int) bool {
   302  		return funcsyms[i].Linksym().Name < funcsyms[j].Linksym().Name
   303  	})
   304  	for _, nam := range funcsyms {
   305  		s := nam.Sym()
   306  		sf := s.Pkg.Lookup(ir.FuncSymName(s)).Linksym()
   307  		// Function values must always reference ABIInternal
   308  		// entry points.
   309  		target := s.Linksym()
   310  		if target.ABI() != obj.ABIInternal {
   311  			base.Fatalf("expected ABIInternal: %v has %v", target, target.ABI())
   312  		}
   313  		objw.SymPtr(sf, 0, target, 0)
   314  		objw.Global(sf, int32(types.PtrSize), obj.DUPOK|obj.RODATA)
   315  	}
   316  }
   317  
   318  // InitConst writes the static literal c to n.
   319  // Neither n nor c is modified.
   320  func InitConst(n *ir.Name, noff int64, c ir.Node, wid int) {
   321  	if n.Op() != ir.ONAME {
   322  		base.Fatalf("InitConst n op %v", n.Op())
   323  	}
   324  	if n.Sym() == nil {
   325  		base.Fatalf("InitConst nil n sym")
   326  	}
   327  	if c.Op() == ir.ONIL {
   328  		return
   329  	}
   330  	if c.Op() != ir.OLITERAL {
   331  		base.Fatalf("InitConst c op %v", c.Op())
   332  	}
   333  	s := n.Linksym()
   334  	switch u := c.Val(); u.Kind() {
   335  	case constant.Bool:
   336  		i := int64(obj.Bool2int(constant.BoolVal(u)))
   337  		s.WriteInt(base.Ctxt, noff, wid, i)
   338  
   339  	case constant.Int:
   340  		s.WriteInt(base.Ctxt, noff, wid, ir.IntVal(c.Type(), u))
   341  
   342  	case constant.Float:
   343  		f, _ := constant.Float64Val(u)
   344  		switch c.Type().Kind() {
   345  		case types.TFLOAT32:
   346  			s.WriteFloat32(base.Ctxt, noff, float32(f))
   347  		case types.TFLOAT64:
   348  			s.WriteFloat64(base.Ctxt, noff, f)
   349  		}
   350  
   351  	case constant.Complex:
   352  		re, _ := constant.Float64Val(constant.Real(u))
   353  		im, _ := constant.Float64Val(constant.Imag(u))
   354  		switch c.Type().Kind() {
   355  		case types.TCOMPLEX64:
   356  			s.WriteFloat32(base.Ctxt, noff, float32(re))
   357  			s.WriteFloat32(base.Ctxt, noff+4, float32(im))
   358  		case types.TCOMPLEX128:
   359  			s.WriteFloat64(base.Ctxt, noff, re)
   360  			s.WriteFloat64(base.Ctxt, noff+8, im)
   361  		}
   362  
   363  	case constant.String:
   364  		i := constant.StringVal(u)
   365  		symdata := StringSym(n.Pos(), i)
   366  		s.WriteAddr(base.Ctxt, noff, types.PtrSize, symdata, 0)
   367  		s.WriteInt(base.Ctxt, noff+int64(types.PtrSize), types.PtrSize, int64(len(i)))
   368  
   369  	default:
   370  		base.Fatalf("InitConst unhandled OLITERAL %v", c)
   371  	}
   372  }
   373  

View as plain text