Source file src/cmd/compile/internal/pkginit/init.go

     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 pkginit
     6  
     7  import (
     8  	"cmd/compile/internal/base"
     9  	"cmd/compile/internal/ir"
    10  	"cmd/compile/internal/noder"
    11  	"cmd/compile/internal/objw"
    12  	"cmd/compile/internal/staticinit"
    13  	"cmd/compile/internal/typecheck"
    14  	"cmd/compile/internal/types"
    15  	"cmd/internal/obj"
    16  	"cmd/internal/objabi"
    17  	"cmd/internal/src"
    18  )
    19  
    20  // MakeTask makes an initialization record for the package, if necessary.
    21  // See runtime/proc.go:initTask for its layout.
    22  // The 3 tasks for initialization are:
    23  //  1. Initialize all of the packages the current package depends on.
    24  //  2. Initialize all the variables that have initializers.
    25  //  3. Run any init functions.
    26  func MakeTask() {
    27  	var deps []*obj.LSym // initTask records for packages the current package depends on
    28  	var fns []*obj.LSym  // functions to call for package initialization
    29  
    30  	// Find imported packages with init tasks.
    31  	for _, pkg := range typecheck.Target.Imports {
    32  		n, ok := pkg.Lookup(".inittask").Def.(*ir.Name)
    33  		if !ok {
    34  			continue
    35  		}
    36  		if n.Op() != ir.ONAME || n.Class != ir.PEXTERN {
    37  			base.Fatalf("bad inittask: %v", n)
    38  		}
    39  		deps = append(deps, n.Linksym())
    40  	}
    41  	if base.Flag.ASan {
    42  		// Make an initialization function to call runtime.asanregisterglobals to register an
    43  		// array of instrumented global variables when -asan is enabled. An instrumented global
    44  		// variable is described by a structure.
    45  		// See the _asan_global structure declared in src/runtime/asan/asan.go.
    46  		//
    47  		// func init {
    48  		// 		var globals []_asan_global {...}
    49  		// 		asanregisterglobals(&globals[0], len(globals))
    50  		// }
    51  		for _, n := range typecheck.Target.Externs {
    52  			if canInstrumentGlobal(n) {
    53  				name := n.Sym().Name
    54  				InstrumentGlobalsMap[name] = n
    55  				InstrumentGlobalsSlice = append(InstrumentGlobalsSlice, n)
    56  			}
    57  		}
    58  		ni := len(InstrumentGlobalsMap)
    59  		if ni != 0 {
    60  			// Make an init._ function.
    61  			pos := base.AutogeneratedPos
    62  			base.Pos = pos
    63  
    64  			sym := noder.Renameinit()
    65  			fnInit := ir.NewFunc(pos, pos, sym, types.NewSignature(nil, nil, nil))
    66  			typecheck.DeclFunc(fnInit)
    67  
    68  			// Get an array of instrumented global variables.
    69  			globals := instrumentGlobals(fnInit)
    70  
    71  			// Call runtime.asanregisterglobals function to poison redzones.
    72  			// runtime.asanregisterglobals(unsafe.Pointer(&globals[0]), ni)
    73  			asancall := ir.NewCallExpr(base.Pos, ir.OCALL, typecheck.LookupRuntime("asanregisterglobals"), nil)
    74  			asancall.Args.Append(typecheck.ConvNop(typecheck.NodAddr(
    75  				ir.NewIndexExpr(base.Pos, globals, ir.NewInt(base.Pos, 0))), types.Types[types.TUNSAFEPTR]))
    76  			asancall.Args.Append(typecheck.DefaultLit(ir.NewInt(base.Pos, int64(ni)), types.Types[types.TUINTPTR]))
    77  
    78  			fnInit.Body.Append(asancall)
    79  			typecheck.FinishFuncBody()
    80  			ir.CurFunc = fnInit
    81  			typecheck.Stmts(fnInit.Body)
    82  			ir.CurFunc = nil
    83  
    84  			typecheck.Target.Inits = append(typecheck.Target.Inits, fnInit)
    85  		}
    86  	}
    87  
    88  	// Record user init functions.
    89  	for _, fn := range typecheck.Target.Inits {
    90  		if fn.Sym().Name == "init" {
    91  			// Synthetic init function for initialization of package-scope
    92  			// variables. We can use staticinit to optimize away static
    93  			// assignments.
    94  			s := staticinit.Schedule{
    95  				Plans: make(map[ir.Node]*staticinit.Plan),
    96  				Temps: make(map[ir.Node]*ir.Name),
    97  			}
    98  			for _, n := range fn.Body {
    99  				s.StaticInit(n)
   100  			}
   101  			fn.Body = s.Out
   102  			ir.WithFunc(fn, func() {
   103  				typecheck.Stmts(fn.Body)
   104  			})
   105  
   106  			if len(fn.Body) == 0 {
   107  				fn.Body = []ir.Node{ir.NewBlockStmt(src.NoXPos, nil)}
   108  			}
   109  		}
   110  
   111  		// Skip init functions with empty bodies.
   112  		if len(fn.Body) == 1 {
   113  			if stmt := fn.Body[0]; stmt.Op() == ir.OBLOCK && len(stmt.(*ir.BlockStmt).List) == 0 {
   114  				continue
   115  			}
   116  		}
   117  		fns = append(fns, fn.Nname.Linksym())
   118  	}
   119  
   120  	if len(deps) == 0 && len(fns) == 0 && types.LocalPkg.Path != "main" && types.LocalPkg.Path != "runtime" {
   121  		return // nothing to initialize
   122  	}
   123  
   124  	// Make an .inittask structure.
   125  	sym := typecheck.Lookup(".inittask")
   126  	task := ir.NewNameAt(base.Pos, sym, types.Types[types.TUINT8]) // fake type
   127  	task.Class = ir.PEXTERN
   128  	sym.Def = task
   129  	lsym := task.Linksym()
   130  	ot := 0
   131  	ot = objw.Uint32(lsym, ot, 0) // state: not initialized yet
   132  	ot = objw.Uint32(lsym, ot, uint32(len(fns)))
   133  	for _, f := range fns {
   134  		ot = objw.SymPtr(lsym, ot, f, 0)
   135  	}
   136  
   137  	// Add relocations which tell the linker all of the packages
   138  	// that this package depends on (and thus, all of the packages
   139  	// that need to be initialized before this one).
   140  	for _, d := range deps {
   141  		lsym.AddRel(base.Ctxt, obj.Reloc{Type: objabi.R_INITORDER, Sym: d})
   142  	}
   143  	// An initTask has pointers, but none into the Go heap.
   144  	// It's not quite read only, the state field must be modifiable.
   145  	objw.Global(lsym, int32(ot), obj.NOPTR)
   146  }
   147  

View as plain text