Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/compile/internal/gc/obj.go

Documentation: cmd/compile/internal/gc

     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/base"
     9  	"cmd/compile/internal/ir"
    10  	"cmd/compile/internal/objw"
    11  	"cmd/compile/internal/reflectdata"
    12  	"cmd/compile/internal/staticdata"
    13  	"cmd/compile/internal/typecheck"
    14  	"cmd/compile/internal/types"
    15  	"cmd/internal/archive"
    16  	"cmd/internal/bio"
    17  	"cmd/internal/obj"
    18  	"cmd/internal/objabi"
    19  	"encoding/json"
    20  	"fmt"
    21  )
    22  
    23  // These modes say which kind of object file to generate.
    24  // The default use of the toolchain is to set both bits,
    25  // generating a combined compiler+linker object, one that
    26  // serves to describe the package to both the compiler and the linker.
    27  // In fact the compiler and linker read nearly disjoint sections of
    28  // that file, though, so in a distributed build setting it can be more
    29  // efficient to split the output into two files, supplying the compiler
    30  // object only to future compilations and the linker object only to
    31  // future links.
    32  //
    33  // By default a combined object is written, but if -linkobj is specified
    34  // on the command line then the default -o output is a compiler object
    35  // and the -linkobj output is a linker object.
    36  const (
    37  	modeCompilerObj = 1 << iota
    38  	modeLinkerObj
    39  )
    40  
    41  func dumpobj() {
    42  	if base.Flag.LinkObj == "" {
    43  		dumpobj1(base.Flag.LowerO, modeCompilerObj|modeLinkerObj)
    44  		return
    45  	}
    46  	dumpobj1(base.Flag.LowerO, modeCompilerObj)
    47  	dumpobj1(base.Flag.LinkObj, modeLinkerObj)
    48  }
    49  
    50  func dumpobj1(outfile string, mode int) {
    51  	bout, err := bio.Create(outfile)
    52  	if err != nil {
    53  		base.FlushErrors()
    54  		fmt.Printf("can't create %s: %v\n", outfile, err)
    55  		base.ErrorExit()
    56  	}
    57  	defer bout.Close()
    58  	bout.WriteString("!<arch>\n")
    59  
    60  	if mode&modeCompilerObj != 0 {
    61  		start := startArchiveEntry(bout)
    62  		dumpCompilerObj(bout)
    63  		finishArchiveEntry(bout, start, "__.PKGDEF")
    64  	}
    65  	if mode&modeLinkerObj != 0 {
    66  		start := startArchiveEntry(bout)
    67  		dumpLinkerObj(bout)
    68  		finishArchiveEntry(bout, start, "_go_.o")
    69  	}
    70  }
    71  
    72  func printObjHeader(bout *bio.Writer) {
    73  	bout.WriteString(objabi.HeaderString())
    74  	if base.Flag.BuildID != "" {
    75  		fmt.Fprintf(bout, "build id %q\n", base.Flag.BuildID)
    76  	}
    77  	if types.LocalPkg.Name == "main" {
    78  		fmt.Fprintf(bout, "main\n")
    79  	}
    80  	fmt.Fprintf(bout, "\n") // header ends with blank line
    81  }
    82  
    83  func startArchiveEntry(bout *bio.Writer) int64 {
    84  	var arhdr [archive.HeaderSize]byte
    85  	bout.Write(arhdr[:])
    86  	return bout.Offset()
    87  }
    88  
    89  func finishArchiveEntry(bout *bio.Writer, start int64, name string) {
    90  	bout.Flush()
    91  	size := bout.Offset() - start
    92  	if size&1 != 0 {
    93  		bout.WriteByte(0)
    94  	}
    95  	bout.MustSeek(start-archive.HeaderSize, 0)
    96  
    97  	var arhdr [archive.HeaderSize]byte
    98  	archive.FormatHeader(arhdr[:], name, size)
    99  	bout.Write(arhdr[:])
   100  	bout.Flush()
   101  	bout.MustSeek(start+size+(size&1), 0)
   102  }
   103  
   104  func dumpCompilerObj(bout *bio.Writer) {
   105  	printObjHeader(bout)
   106  	dumpexport(bout)
   107  }
   108  
   109  func dumpdata() {
   110  	numExterns := len(typecheck.Target.Externs)
   111  	numDecls := len(typecheck.Target.Decls)
   112  
   113  	dumpglobls(typecheck.Target.Externs)
   114  	reflectdata.CollectPTabs()
   115  	numExports := len(typecheck.Target.Exports)
   116  	addsignats(typecheck.Target.Externs)
   117  	reflectdata.WriteRuntimeTypes()
   118  	reflectdata.WriteTabs()
   119  	numPTabs, numITabs := reflectdata.CountTabs()
   120  	reflectdata.WriteImportStrings()
   121  	reflectdata.WriteBasicTypes()
   122  	dumpembeds()
   123  
   124  	// Calls to WriteRuntimeTypes can generate functions,
   125  	// like method wrappers and hash and equality routines.
   126  	// Compile any generated functions, process any new resulting types, repeat.
   127  	// This can't loop forever, because there is no way to generate an infinite
   128  	// number of types in a finite amount of code.
   129  	// In the typical case, we loop 0 or 1 times.
   130  	// It was not until issue 24761 that we found any code that required a loop at all.
   131  	for {
   132  		for i := numDecls; i < len(typecheck.Target.Decls); i++ {
   133  			if n, ok := typecheck.Target.Decls[i].(*ir.Func); ok {
   134  				enqueueFunc(n)
   135  			}
   136  		}
   137  		numDecls = len(typecheck.Target.Decls)
   138  		compileFunctions()
   139  		reflectdata.WriteRuntimeTypes()
   140  		if numDecls == len(typecheck.Target.Decls) {
   141  			break
   142  		}
   143  	}
   144  
   145  	// Dump extra globals.
   146  	dumpglobls(typecheck.Target.Externs[numExterns:])
   147  
   148  	if reflectdata.ZeroSize > 0 {
   149  		zero := base.PkgLinksym("go.map", "zero", obj.ABI0)
   150  		objw.Global(zero, int32(reflectdata.ZeroSize), obj.DUPOK|obj.RODATA)
   151  		zero.Set(obj.AttrStatic, true)
   152  	}
   153  
   154  	staticdata.WriteFuncSyms()
   155  	addGCLocals()
   156  
   157  	if numExports != len(typecheck.Target.Exports) {
   158  		base.Fatalf("Target.Exports changed after compile functions loop")
   159  	}
   160  	newNumPTabs, newNumITabs := reflectdata.CountTabs()
   161  	if newNumPTabs != numPTabs {
   162  		base.Fatalf("ptabs changed after compile functions loop")
   163  	}
   164  	if newNumITabs != numITabs {
   165  		base.Fatalf("itabs changed after compile functions loop")
   166  	}
   167  }
   168  
   169  func dumpLinkerObj(bout *bio.Writer) {
   170  	printObjHeader(bout)
   171  
   172  	if len(typecheck.Target.CgoPragmas) != 0 {
   173  		// write empty export section; must be before cgo section
   174  		fmt.Fprintf(bout, "\n$$\n\n$$\n\n")
   175  		fmt.Fprintf(bout, "\n$$  // cgo\n")
   176  		if err := json.NewEncoder(bout).Encode(typecheck.Target.CgoPragmas); err != nil {
   177  			base.Fatalf("serializing pragcgobuf: %v", err)
   178  		}
   179  		fmt.Fprintf(bout, "\n$$\n\n")
   180  	}
   181  
   182  	fmt.Fprintf(bout, "\n!\n")
   183  
   184  	obj.WriteObjFile(base.Ctxt, bout)
   185  }
   186  
   187  func dumpGlobal(n *ir.Name) {
   188  	if n.Type() == nil {
   189  		base.Fatalf("external %v nil type\n", n)
   190  	}
   191  	if n.Class == ir.PFUNC {
   192  		return
   193  	}
   194  	if n.Sym().Pkg != types.LocalPkg {
   195  		return
   196  	}
   197  	types.CalcSize(n.Type())
   198  	ggloblnod(n)
   199  	base.Ctxt.DwarfGlobal(base.Ctxt.Pkgpath, types.TypeSymName(n.Type()), n.Linksym())
   200  }
   201  
   202  func dumpGlobalConst(n ir.Node) {
   203  	// only export typed constants
   204  	t := n.Type()
   205  	if t == nil {
   206  		return
   207  	}
   208  	if n.Sym().Pkg != types.LocalPkg {
   209  		return
   210  	}
   211  	// only export integer constants for now
   212  	if !t.IsInteger() {
   213  		return
   214  	}
   215  	v := n.Val()
   216  	if t.IsUntyped() {
   217  		// Export untyped integers as int (if they fit).
   218  		t = types.Types[types.TINT]
   219  		if ir.ConstOverflow(v, t) {
   220  			return
   221  		}
   222  	}
   223  	base.Ctxt.DwarfIntConst(base.Ctxt.Pkgpath, n.Sym().Name, types.TypeSymName(t), ir.IntVal(t, v))
   224  }
   225  
   226  func dumpglobls(externs []ir.Node) {
   227  	// add globals
   228  	for _, n := range externs {
   229  		switch n.Op() {
   230  		case ir.ONAME:
   231  			dumpGlobal(n.(*ir.Name))
   232  		case ir.OLITERAL:
   233  			dumpGlobalConst(n)
   234  		}
   235  	}
   236  }
   237  
   238  // addGCLocals adds gcargs, gclocals, gcregs, and stack object symbols to Ctxt.Data.
   239  //
   240  // This is done during the sequential phase after compilation, since
   241  // global symbols can't be declared during parallel compilation.
   242  func addGCLocals() {
   243  	for _, s := range base.Ctxt.Text {
   244  		fn := s.Func()
   245  		if fn == nil {
   246  			continue
   247  		}
   248  		for _, gcsym := range []*obj.LSym{fn.GCArgs, fn.GCLocals} {
   249  			if gcsym != nil && !gcsym.OnList() {
   250  				objw.Global(gcsym, int32(len(gcsym.P)), obj.RODATA|obj.DUPOK)
   251  			}
   252  		}
   253  		if x := fn.StackObjects; x != nil {
   254  			attr := int16(obj.RODATA)
   255  			objw.Global(x, int32(len(x.P)), attr)
   256  			x.Set(obj.AttrStatic, true)
   257  		}
   258  		if x := fn.OpenCodedDeferInfo; x != nil {
   259  			objw.Global(x, int32(len(x.P)), obj.RODATA|obj.DUPOK)
   260  		}
   261  		if x := fn.ArgInfo; x != nil {
   262  			objw.Global(x, int32(len(x.P)), obj.RODATA|obj.DUPOK)
   263  			x.Set(obj.AttrStatic, true)
   264  			x.Set(obj.AttrContentAddressable, true)
   265  		}
   266  	}
   267  }
   268  
   269  func ggloblnod(nam *ir.Name) {
   270  	s := nam.Linksym()
   271  	s.Gotype = reflectdata.TypeLinksym(nam.Type())
   272  	flags := 0
   273  	if nam.Readonly() {
   274  		flags = obj.RODATA
   275  	}
   276  	if nam.Type() != nil && !nam.Type().HasPointers() {
   277  		flags |= obj.NOPTR
   278  	}
   279  	base.Ctxt.Globl(s, nam.Type().Width, flags)
   280  	if nam.LibfuzzerExtraCounter() {
   281  		s.Type = objabi.SLIBFUZZER_EXTRA_COUNTER
   282  	}
   283  	if nam.Sym().Linkname != "" {
   284  		// Make sure linkname'd symbol is non-package. When a symbol is
   285  		// both imported and linkname'd, s.Pkg may not set to "_" in
   286  		// types.Sym.Linksym because LSym already exists. Set it here.
   287  		s.Pkg = "_"
   288  	}
   289  }
   290  
   291  func dumpembeds() {
   292  	for _, v := range typecheck.Target.Embeds {
   293  		staticdata.WriteEmbed(v)
   294  	}
   295  }
   296  
   297  func addsignats(dcls []ir.Node) {
   298  	// copy types from dcl list to signatset
   299  	for _, n := range dcls {
   300  		if n.Op() == ir.OTYPE {
   301  			reflectdata.NeedRuntimeType(n.Type())
   302  		}
   303  	}
   304  }
   305  

View as plain text