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