github.com/bir3/gocompiler@v0.9.2202/src/cmd/compile/internal/pkginit/init.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 pkginit 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/staticinit" 13 "github.com/bir3/gocompiler/src/cmd/compile/internal/typecheck" 14 "github.com/bir3/gocompiler/src/cmd/compile/internal/types" 15 "github.com/bir3/gocompiler/src/cmd/internal/obj" 16 "github.com/bir3/gocompiler/src/cmd/internal/objabi" 17 "github.com/bir3/gocompiler/src/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 r := obj.Addrel(lsym) 142 r.Type = objabi.R_INITORDER 143 r.Sym = d 144 } 145 // An initTask has pointers, but none into the Go heap. 146 // It's not quite read only, the state field must be modifiable. 147 objw.Global(lsym, int32(ot), obj.NOPTR) 148 }