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