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 staticinit.CanOptimize(fn) {
    91  			s := staticinit.Schedule{
    92  				Plans: make(map[ir.Node]*staticinit.Plan),
    93  				Temps: make(map[ir.Node]*ir.Name),
    94  			}
    95  			for _, n := range fn.Body {
    96  				s.StaticInit(n)
    97  			}
    98  			fn.Body = s.Out
    99  			ir.WithFunc(fn, func() {
   100  				typecheck.Stmts(fn.Body)
   101  			})
   102  
   103  			if len(fn.Body) == 0 {
   104  				fn.Body = []ir.Node{ir.NewBlockStmt(src.NoXPos, nil)}
   105  			}
   106  		}
   107  
   108  		// Skip init functions with empty bodies.
   109  		if len(fn.Body) == 1 {
   110  			if stmt := fn.Body[0]; stmt.Op() == ir.OBLOCK && len(stmt.(*ir.BlockStmt).List) == 0 {
   111  				continue
   112  			}
   113  		}
   114  		fns = append(fns, fn.Nname.Linksym())
   115  	}
   116  
   117  	if len(deps) == 0 && len(fns) == 0 && types.LocalPkg.Path != "main" && types.LocalPkg.Path != "runtime" {
   118  		return // nothing to initialize
   119  	}
   120  
   121  	// Make an .inittask structure.
   122  	sym := typecheck.Lookup(".inittask")
   123  	task := ir.NewNameAt(base.Pos, sym, types.Types[types.TUINT8]) // fake type
   124  	task.Class = ir.PEXTERN
   125  	sym.Def = task
   126  	lsym := task.Linksym()
   127  	ot := 0
   128  	ot = objw.Uint32(lsym, ot, 0) // state: not initialized yet
   129  	ot = objw.Uint32(lsym, ot, uint32(len(fns)))
   130  	for _, f := range fns {
   131  		ot = objw.SymPtr(lsym, ot, f, 0)
   132  	}
   133  
   134  	// Add relocations which tell the linker all of the packages
   135  	// that this package depends on (and thus, all of the packages
   136  	// that need to be initialized before this one).
   137  	for _, d := range deps {
   138  		lsym.AddRel(base.Ctxt, obj.Reloc{Type: objabi.R_INITORDER, Sym: d})
   139  	}
   140  	// An initTask has pointers, but none into the Go heap.
   141  	// It's not quite read only, the state field must be modifiable.
   142  	objw.Global(lsym, int32(ot), obj.NOPTR)
   143  }
   144  

View as plain text