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 }