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