github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/cmd/compile/internal/gc/obj.go (about)

     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 gc
     6  
     7  import (
     8  	"cmd/compile/internal/types"
     9  	"cmd/internal/bio"
    10  	"cmd/internal/obj"
    11  	"cmd/internal/objabi"
    12  	"cmd/internal/src"
    13  	"crypto/sha256"
    14  	"encoding/json"
    15  	"fmt"
    16  	"io"
    17  	"strconv"
    18  )
    19  
    20  // architecture-independent object file output
    21  const ArhdrSize = 60
    22  
    23  func formathdr(arhdr []byte, name string, size int64) {
    24  	copy(arhdr[:], fmt.Sprintf("%-16s%-12d%-6d%-6d%-8o%-10d`\n", name, 0, 0, 0, 0644, size))
    25  }
    26  
    27  // These modes say which kind of object file to generate.
    28  // The default use of the toolchain is to set both bits,
    29  // generating a combined compiler+linker object, one that
    30  // serves to describe the package to both the compiler and the linker.
    31  // In fact the compiler and linker read nearly disjoint sections of
    32  // that file, though, so in a distributed build setting it can be more
    33  // efficient to split the output into two files, supplying the compiler
    34  // object only to future compilations and the linker object only to
    35  // future links.
    36  //
    37  // By default a combined object is written, but if -linkobj is specified
    38  // on the command line then the default -o output is a compiler object
    39  // and the -linkobj output is a linker object.
    40  const (
    41  	modeCompilerObj = 1 << iota
    42  	modeLinkerObj
    43  )
    44  
    45  func dumpobj() {
    46  	if linkobj == "" {
    47  		dumpobj1(outfile, modeCompilerObj|modeLinkerObj)
    48  		return
    49  	}
    50  	dumpobj1(outfile, modeCompilerObj)
    51  	dumpobj1(linkobj, modeLinkerObj)
    52  }
    53  
    54  func dumpobj1(outfile string, mode int) {
    55  	bout, err := bio.Create(outfile)
    56  	if err != nil {
    57  		flusherrors()
    58  		fmt.Printf("can't create %s: %v\n", outfile, err)
    59  		errorexit()
    60  	}
    61  	defer bout.Close()
    62  	bout.WriteString("!<arch>\n")
    63  
    64  	if mode&modeCompilerObj != 0 {
    65  		start := startArchiveEntry(bout)
    66  		dumpCompilerObj(bout)
    67  		finishArchiveEntry(bout, start, "__.PKGDEF")
    68  	}
    69  	if mode&modeLinkerObj != 0 {
    70  		start := startArchiveEntry(bout)
    71  		dumpLinkerObj(bout)
    72  		finishArchiveEntry(bout, start, "_go_.o")
    73  	}
    74  }
    75  
    76  func printObjHeader(bout *bio.Writer) {
    77  	fmt.Fprintf(bout, "go object %s %s %s %s\n", objabi.GOOS, objabi.GOARCH, objabi.Version, objabi.Expstring())
    78  	if buildid != "" {
    79  		fmt.Fprintf(bout, "build id %q\n", buildid)
    80  	}
    81  	if localpkg.Name == "main" {
    82  		fmt.Fprintf(bout, "main\n")
    83  	}
    84  	fmt.Fprintf(bout, "\n") // header ends with blank line
    85  }
    86  
    87  func startArchiveEntry(bout *bio.Writer) int64 {
    88  	var arhdr [ArhdrSize]byte
    89  	bout.Write(arhdr[:])
    90  	return bout.Offset()
    91  }
    92  
    93  func finishArchiveEntry(bout *bio.Writer, start int64, name string) {
    94  	bout.Flush()
    95  	size := bout.Offset() - start
    96  	if size&1 != 0 {
    97  		bout.WriteByte(0)
    98  	}
    99  	bout.Seek(start-ArhdrSize, 0)
   100  
   101  	var arhdr [ArhdrSize]byte
   102  	formathdr(arhdr[:], name, size)
   103  	bout.Write(arhdr[:])
   104  	bout.Flush()
   105  	bout.Seek(start+size+(size&1), 0)
   106  }
   107  
   108  func dumpCompilerObj(bout *bio.Writer) {
   109  	printObjHeader(bout)
   110  	dumpexport(bout)
   111  }
   112  
   113  func dumpLinkerObj(bout *bio.Writer) {
   114  	printObjHeader(bout)
   115  
   116  	if len(pragcgobuf) != 0 {
   117  		// write empty export section; must be before cgo section
   118  		fmt.Fprintf(bout, "\n$$\n\n$$\n\n")
   119  		fmt.Fprintf(bout, "\n$$  // cgo\n")
   120  		if err := json.NewEncoder(bout).Encode(pragcgobuf); err != nil {
   121  			Fatalf("serializing pragcgobuf: %v", err)
   122  		}
   123  		fmt.Fprintf(bout, "\n$$\n\n")
   124  	}
   125  
   126  	fmt.Fprintf(bout, "\n!\n")
   127  
   128  	externs := len(externdcl)
   129  
   130  	dumpglobls()
   131  	addptabs()
   132  	addsignats(externdcl)
   133  	dumpsignats()
   134  	dumptabs()
   135  	dumpimportstrings()
   136  	dumpbasictypes()
   137  
   138  	// Calls to dumpsignats can generate functions,
   139  	// like method wrappers and hash and equality routines.
   140  	// Compile any generated functions, process any new resulting types, repeat.
   141  	// This can't loop forever, because there is no way to generate an infinite
   142  	// number of types in a finite amount of code.
   143  	// In the typical case, we loop 0 or 1 times.
   144  	// It was not until issue 24761 that we found any code that required a loop at all.
   145  	for len(compilequeue) > 0 {
   146  		compileFunctions()
   147  		dumpsignats()
   148  	}
   149  
   150  	// Dump extra globals.
   151  	tmp := externdcl
   152  
   153  	if externdcl != nil {
   154  		externdcl = externdcl[externs:]
   155  	}
   156  	dumpglobls()
   157  	externdcl = tmp
   158  
   159  	if zerosize > 0 {
   160  		zero := mappkg.Lookup("zero")
   161  		ggloblsym(zero.Linksym(), int32(zerosize), obj.DUPOK|obj.RODATA)
   162  	}
   163  
   164  	addGCLocals()
   165  
   166  	obj.WriteObjFile(Ctxt, bout.Writer)
   167  }
   168  
   169  func addptabs() {
   170  	if !Ctxt.Flag_dynlink || localpkg.Name != "main" {
   171  		return
   172  	}
   173  	for _, exportn := range exportlist {
   174  		s := exportn.Sym
   175  		n := asNode(s.Def)
   176  		if n == nil {
   177  			continue
   178  		}
   179  		if n.Op != ONAME {
   180  			continue
   181  		}
   182  		if !types.IsExported(s.Name) {
   183  			continue
   184  		}
   185  		if s.Pkg.Name != "main" {
   186  			continue
   187  		}
   188  		if n.Type.Etype == TFUNC && n.Class() == PFUNC {
   189  			// function
   190  			ptabs = append(ptabs, ptabEntry{s: s, t: asNode(s.Def).Type})
   191  		} else {
   192  			// variable
   193  			ptabs = append(ptabs, ptabEntry{s: s, t: types.NewPtr(asNode(s.Def).Type)})
   194  		}
   195  	}
   196  }
   197  
   198  func dumpGlobal(n *Node) {
   199  	if n.Type == nil {
   200  		Fatalf("external %v nil type\n", n)
   201  	}
   202  	if n.Class() == PFUNC {
   203  		return
   204  	}
   205  	if n.Sym.Pkg != localpkg {
   206  		return
   207  	}
   208  	dowidth(n.Type)
   209  	ggloblnod(n)
   210  }
   211  
   212  func dumpGlobalConst(n *Node) {
   213  	// only export typed constants
   214  	t := n.Type
   215  	if t == nil {
   216  		return
   217  	}
   218  	if n.Sym.Pkg != localpkg {
   219  		return
   220  	}
   221  	// only export integer constants for now
   222  	switch t.Etype {
   223  	case TINT8:
   224  	case TINT16:
   225  	case TINT32:
   226  	case TINT64:
   227  	case TINT:
   228  	case TUINT8:
   229  	case TUINT16:
   230  	case TUINT32:
   231  	case TUINT64:
   232  	case TUINT:
   233  	case TUINTPTR:
   234  		// ok
   235  	case TIDEAL:
   236  		if !Isconst(n, CTINT) {
   237  			return
   238  		}
   239  		x := n.Val().U.(*Mpint)
   240  		if x.Cmp(minintval[TINT]) < 0 || x.Cmp(maxintval[TINT]) > 0 {
   241  			return
   242  		}
   243  		// Ideal integers we export as int (if they fit).
   244  		t = types.Types[TINT]
   245  	default:
   246  		return
   247  	}
   248  	Ctxt.DwarfIntConst(myimportpath, n.Sym.Name, typesymname(t), n.Int64())
   249  }
   250  
   251  func dumpglobls() {
   252  	// add globals
   253  	for _, n := range externdcl {
   254  		switch n.Op {
   255  		case ONAME:
   256  			dumpGlobal(n)
   257  		case OLITERAL:
   258  			dumpGlobalConst(n)
   259  		}
   260  	}
   261  
   262  	obj.SortSlice(funcsyms, func(i, j int) bool {
   263  		return funcsyms[i].LinksymName() < funcsyms[j].LinksymName()
   264  	})
   265  	for _, s := range funcsyms {
   266  		sf := s.Pkg.Lookup(funcsymname(s)).Linksym()
   267  		dsymptr(sf, 0, s.Linksym(), 0)
   268  		ggloblsym(sf, int32(Widthptr), obj.DUPOK|obj.RODATA)
   269  	}
   270  
   271  	// Do not reprocess funcsyms on next dumpglobls call.
   272  	funcsyms = nil
   273  }
   274  
   275  // addGCLocals adds gcargs, gclocals, gcregs, and stack object symbols to Ctxt.Data.
   276  //
   277  // This is done during the sequential phase after compilation, since
   278  // global symbols can't be declared during parallel compilation.
   279  func addGCLocals() {
   280  	for _, s := range Ctxt.Text {
   281  		if s.Func == nil {
   282  			continue
   283  		}
   284  		for _, gcsym := range []*obj.LSym{s.Func.GCArgs, s.Func.GCLocals, s.Func.GCRegs} {
   285  			if gcsym != nil && !gcsym.OnList() {
   286  				ggloblsym(gcsym, int32(len(gcsym.P)), obj.RODATA|obj.DUPOK)
   287  			}
   288  		}
   289  		if x := s.Func.StackObjects; x != nil {
   290  			ggloblsym(x, int32(len(x.P)), obj.RODATA|obj.LOCAL)
   291  		}
   292  	}
   293  }
   294  
   295  func duintxx(s *obj.LSym, off int, v uint64, wid int) int {
   296  	if off&(wid-1) != 0 {
   297  		Fatalf("duintxxLSym: misaligned: v=%d wid=%d off=%d", v, wid, off)
   298  	}
   299  	s.WriteInt(Ctxt, int64(off), wid, int64(v))
   300  	return off + wid
   301  }
   302  
   303  func duint8(s *obj.LSym, off int, v uint8) int {
   304  	return duintxx(s, off, uint64(v), 1)
   305  }
   306  
   307  func duint16(s *obj.LSym, off int, v uint16) int {
   308  	return duintxx(s, off, uint64(v), 2)
   309  }
   310  
   311  func duint32(s *obj.LSym, off int, v uint32) int {
   312  	return duintxx(s, off, uint64(v), 4)
   313  }
   314  
   315  func duintptr(s *obj.LSym, off int, v uint64) int {
   316  	return duintxx(s, off, v, Widthptr)
   317  }
   318  
   319  func dbvec(s *obj.LSym, off int, bv bvec) int {
   320  	// Runtime reads the bitmaps as byte arrays. Oblige.
   321  	for j := 0; int32(j) < bv.n; j += 8 {
   322  		word := bv.b[j/32]
   323  		off = duint8(s, off, uint8(word>>(uint(j)%32)))
   324  	}
   325  	return off
   326  }
   327  
   328  func stringsym(pos src.XPos, s string) (data *obj.LSym) {
   329  	var symname string
   330  	if len(s) > 100 {
   331  		// Huge strings are hashed to avoid long names in object files.
   332  		// Indulge in some paranoia by writing the length of s, too,
   333  		// as protection against length extension attacks.
   334  		h := sha256.New()
   335  		io.WriteString(h, s)
   336  		symname = fmt.Sprintf(".gostring.%d.%x", len(s), h.Sum(nil))
   337  	} else {
   338  		// Small strings get named directly by their contents.
   339  		symname = strconv.Quote(s)
   340  	}
   341  
   342  	const prefix = "go.string."
   343  	symdataname := prefix + symname
   344  
   345  	symdata := Ctxt.Lookup(symdataname)
   346  
   347  	if !symdata.SeenGlobl() {
   348  		// string data
   349  		off := dsname(symdata, 0, s, pos, "string")
   350  		ggloblsym(symdata, int32(off), obj.DUPOK|obj.RODATA|obj.LOCAL)
   351  	}
   352  
   353  	return symdata
   354  }
   355  
   356  var slicebytes_gen int
   357  
   358  func slicebytes(nam *Node, s string, len int) {
   359  	slicebytes_gen++
   360  	symname := fmt.Sprintf(".gobytes.%d", slicebytes_gen)
   361  	sym := localpkg.Lookup(symname)
   362  	sym.Def = asTypesNode(newname(sym))
   363  
   364  	lsym := sym.Linksym()
   365  	off := dsname(lsym, 0, s, nam.Pos, "slice")
   366  	ggloblsym(lsym, int32(off), obj.NOPTR|obj.LOCAL)
   367  
   368  	if nam.Op != ONAME {
   369  		Fatalf("slicebytes %v", nam)
   370  	}
   371  	nsym := nam.Sym.Linksym()
   372  	off = int(nam.Xoffset)
   373  	off = dsymptr(nsym, off, lsym, 0)
   374  	off = duintptr(nsym, off, uint64(len))
   375  	duintptr(nsym, off, uint64(len))
   376  }
   377  
   378  func dsname(s *obj.LSym, off int, t string, pos src.XPos, what string) int {
   379  	// Objects that are too large will cause the data section to overflow right away,
   380  	// causing a cryptic error message by the linker. Check for oversize objects here
   381  	// and provide a useful error message instead.
   382  	if int64(len(t)) > 2e9 {
   383  		yyerrorl(pos, "%v with length %v is too big", what, len(t))
   384  		return 0
   385  	}
   386  
   387  	s.WriteString(Ctxt, int64(off), len(t), t)
   388  	return off + len(t)
   389  }
   390  
   391  func dsymptr(s *obj.LSym, off int, x *obj.LSym, xoff int) int {
   392  	off = int(Rnd(int64(off), int64(Widthptr)))
   393  	s.WriteAddr(Ctxt, int64(off), Widthptr, x, int64(xoff))
   394  	off += Widthptr
   395  	return off
   396  }
   397  
   398  func dsymptrOff(s *obj.LSym, off int, x *obj.LSym) int {
   399  	s.WriteOff(Ctxt, int64(off), x, 0)
   400  	off += 4
   401  	return off
   402  }
   403  
   404  func dsymptrWeakOff(s *obj.LSym, off int, x *obj.LSym) int {
   405  	s.WriteWeakOff(Ctxt, int64(off), x, 0)
   406  	off += 4
   407  	return off
   408  }
   409  
   410  func gdata(nam *Node, nr *Node, wid int) {
   411  	if nam.Op != ONAME {
   412  		Fatalf("gdata nam op %v", nam.Op)
   413  	}
   414  	if nam.Sym == nil {
   415  		Fatalf("gdata nil nam sym")
   416  	}
   417  	s := nam.Sym.Linksym()
   418  
   419  	switch nr.Op {
   420  	case OLITERAL:
   421  		switch u := nr.Val().U.(type) {
   422  		case bool:
   423  			i := int64(obj.Bool2int(u))
   424  			s.WriteInt(Ctxt, nam.Xoffset, wid, i)
   425  
   426  		case *Mpint:
   427  			s.WriteInt(Ctxt, nam.Xoffset, wid, u.Int64())
   428  
   429  		case *Mpflt:
   430  			f := u.Float64()
   431  			switch nam.Type.Etype {
   432  			case TFLOAT32:
   433  				s.WriteFloat32(Ctxt, nam.Xoffset, float32(f))
   434  			case TFLOAT64:
   435  				s.WriteFloat64(Ctxt, nam.Xoffset, f)
   436  			}
   437  
   438  		case *Mpcplx:
   439  			r := u.Real.Float64()
   440  			i := u.Imag.Float64()
   441  			switch nam.Type.Etype {
   442  			case TCOMPLEX64:
   443  				s.WriteFloat32(Ctxt, nam.Xoffset, float32(r))
   444  				s.WriteFloat32(Ctxt, nam.Xoffset+4, float32(i))
   445  			case TCOMPLEX128:
   446  				s.WriteFloat64(Ctxt, nam.Xoffset, r)
   447  				s.WriteFloat64(Ctxt, nam.Xoffset+8, i)
   448  			}
   449  
   450  		case string:
   451  			symdata := stringsym(nam.Pos, u)
   452  			s.WriteAddr(Ctxt, nam.Xoffset, Widthptr, symdata, 0)
   453  			s.WriteInt(Ctxt, nam.Xoffset+int64(Widthptr), Widthptr, int64(len(u)))
   454  
   455  		default:
   456  			Fatalf("gdata unhandled OLITERAL %v", nr)
   457  		}
   458  
   459  	case OADDR:
   460  		if nr.Left.Op != ONAME {
   461  			Fatalf("gdata ADDR left op %v", nr.Left.Op)
   462  		}
   463  		to := nr.Left
   464  		s.WriteAddr(Ctxt, nam.Xoffset, wid, to.Sym.Linksym(), to.Xoffset)
   465  
   466  	case ONAME:
   467  		if nr.Class() != PFUNC {
   468  			Fatalf("gdata NAME not PFUNC %d", nr.Class())
   469  		}
   470  		s.WriteAddr(Ctxt, nam.Xoffset, wid, funcsym(nr.Sym).Linksym(), nr.Xoffset)
   471  
   472  	default:
   473  		Fatalf("gdata unhandled op %v %v\n", nr, nr.Op)
   474  	}
   475  }