github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/internal/obj/objfile2.go (about) 1 // Copyright 2019 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 // Writing Go object files. 6 7 package obj 8 9 import ( 10 "bytes" 11 "github.com/gagliardetto/golang-go/cmd/internal/bio" 12 "github.com/gagliardetto/golang-go/cmd/internal/goobj2" 13 "github.com/gagliardetto/golang-go/cmd/internal/objabi" 14 "fmt" 15 "path/filepath" 16 "strings" 17 ) 18 19 // Entry point of writing new object file. 20 func WriteObjFile2(ctxt *Link, b *bio.Writer, pkgpath string) { 21 if ctxt.Debugasm > 0 { 22 ctxt.traverseSyms(traverseDefs, ctxt.writeSymDebug) 23 } 24 25 genFuncInfoSyms(ctxt) 26 27 w := writer{ 28 Writer: goobj2.NewWriter(b), 29 ctxt: ctxt, 30 pkgpath: objabi.PathToPrefix(pkgpath), 31 } 32 33 start := b.Offset() 34 w.init() 35 36 // Header 37 // We just reserve the space. We'll fill in the offsets later. 38 flags := uint32(0) 39 if ctxt.Flag_shared { 40 flags |= goobj2.ObjFlagShared 41 } 42 h := goobj2.Header{Magic: goobj2.Magic, Flags: flags} 43 h.Write(w.Writer) 44 45 // String table 46 w.StringTable() 47 48 // Autolib 49 h.Offsets[goobj2.BlkAutolib] = w.Offset() 50 for _, pkg := range ctxt.Imports { 51 w.StringRef(pkg) 52 } 53 54 // Package references 55 h.Offsets[goobj2.BlkPkgIdx] = w.Offset() 56 for _, pkg := range w.pkglist { 57 w.StringRef(pkg) 58 } 59 60 // DWARF file table 61 h.Offsets[goobj2.BlkDwarfFile] = w.Offset() 62 for _, f := range ctxt.PosTable.DebugLinesFileTable() { 63 w.StringRef(f) 64 } 65 66 // Symbol definitions 67 h.Offsets[goobj2.BlkSymdef] = w.Offset() 68 for _, s := range ctxt.defs { 69 w.Sym(s) 70 } 71 72 // Non-pkg symbol definitions 73 h.Offsets[goobj2.BlkNonpkgdef] = w.Offset() 74 for _, s := range ctxt.nonpkgdefs { 75 w.Sym(s) 76 } 77 78 // Non-pkg symbol references 79 h.Offsets[goobj2.BlkNonpkgref] = w.Offset() 80 for _, s := range ctxt.nonpkgrefs { 81 w.Sym(s) 82 } 83 84 // Reloc indexes 85 h.Offsets[goobj2.BlkRelocIdx] = w.Offset() 86 nreloc := uint32(0) 87 lists := [][]*LSym{ctxt.defs, ctxt.nonpkgdefs} 88 for _, list := range lists { 89 for _, s := range list { 90 w.Uint32(nreloc) 91 nreloc += uint32(len(s.R)) 92 } 93 } 94 w.Uint32(nreloc) 95 96 // Symbol Info indexes 97 h.Offsets[goobj2.BlkAuxIdx] = w.Offset() 98 naux := uint32(0) 99 for _, list := range lists { 100 for _, s := range list { 101 w.Uint32(naux) 102 naux += uint32(nAuxSym(s)) 103 } 104 } 105 w.Uint32(naux) 106 107 // Data indexes 108 h.Offsets[goobj2.BlkDataIdx] = w.Offset() 109 dataOff := uint32(0) 110 for _, list := range lists { 111 for _, s := range list { 112 w.Uint32(dataOff) 113 dataOff += uint32(len(s.P)) 114 } 115 } 116 w.Uint32(dataOff) 117 118 // Relocs 119 h.Offsets[goobj2.BlkReloc] = w.Offset() 120 for _, list := range lists { 121 for _, s := range list { 122 for i := range s.R { 123 w.Reloc(&s.R[i]) 124 } 125 } 126 } 127 128 // Aux symbol info 129 h.Offsets[goobj2.BlkAux] = w.Offset() 130 for _, list := range lists { 131 for _, s := range list { 132 w.Aux(s) 133 } 134 } 135 136 // Data 137 h.Offsets[goobj2.BlkData] = w.Offset() 138 for _, list := range lists { 139 for _, s := range list { 140 w.Bytes(s.P) 141 } 142 } 143 144 // Pcdata 145 h.Offsets[goobj2.BlkPcdata] = w.Offset() 146 for _, s := range ctxt.Text { // iteration order must match genFuncInfoSyms 147 if s.Func != nil { 148 pc := &s.Func.Pcln 149 w.Bytes(pc.Pcsp.P) 150 w.Bytes(pc.Pcfile.P) 151 w.Bytes(pc.Pcline.P) 152 w.Bytes(pc.Pcinline.P) 153 for i := range pc.Pcdata { 154 w.Bytes(pc.Pcdata[i].P) 155 } 156 } 157 } 158 159 // Fix up block offsets in the header 160 end := start + int64(w.Offset()) 161 b.MustSeek(start, 0) 162 h.Write(w.Writer) 163 b.MustSeek(end, 0) 164 } 165 166 type writer struct { 167 *goobj2.Writer 168 ctxt *Link 169 pkgpath string // the package import path (escaped), "" if unknown 170 pkglist []string // list of packages referenced, indexed by ctxt.pkgIdx 171 } 172 173 // prepare package index list 174 func (w *writer) init() { 175 w.pkglist = make([]string, len(w.ctxt.pkgIdx)+1) 176 w.pkglist[0] = "" // dummy invalid package for index 0 177 for pkg, i := range w.ctxt.pkgIdx { 178 w.pkglist[i] = pkg 179 } 180 } 181 182 func (w *writer) StringTable() { 183 w.AddString("") 184 for _, pkg := range w.ctxt.Imports { 185 w.AddString(pkg) 186 } 187 for _, pkg := range w.pkglist { 188 w.AddString(pkg) 189 } 190 w.ctxt.traverseSyms(traverseAll, func(s *LSym) { 191 if w.pkgpath != "" { 192 s.Name = strings.Replace(s.Name, "\"\".", w.pkgpath+".", -1) 193 } 194 w.AddString(s.Name) 195 }) 196 w.ctxt.traverseSyms(traverseDefs, func(s *LSym) { 197 if s.Type != objabi.STEXT { 198 return 199 } 200 pc := &s.Func.Pcln 201 for _, f := range pc.File { 202 w.AddString(filepath.ToSlash(f)) 203 } 204 for _, call := range pc.InlTree.nodes { 205 f, _ := linkgetlineFromPos(w.ctxt, call.Pos) 206 w.AddString(filepath.ToSlash(f)) 207 } 208 }) 209 for _, f := range w.ctxt.PosTable.DebugLinesFileTable() { 210 w.AddString(f) 211 } 212 } 213 214 func (w *writer) Sym(s *LSym) { 215 abi := uint16(s.ABI()) 216 if s.Static() { 217 abi = goobj2.SymABIstatic 218 } 219 flag := uint8(0) 220 if s.DuplicateOK() { 221 flag |= goobj2.SymFlagDupok 222 } 223 if s.Local() { 224 flag |= goobj2.SymFlagLocal 225 } 226 if s.MakeTypelink() { 227 flag |= goobj2.SymFlagTypelink 228 } 229 if s.Leaf() { 230 flag |= goobj2.SymFlagLeaf 231 } 232 if s.CFunc() { 233 flag |= goobj2.SymFlagCFunc 234 } 235 if s.ReflectMethod() { 236 flag |= goobj2.SymFlagReflectMethod 237 } 238 if s.TopFrame() { 239 flag |= goobj2.SymFlagTopFrame 240 } 241 if strings.HasPrefix(s.Name, "type.") && s.Name[5] != '.' && s.Type == objabi.SRODATA { 242 flag |= goobj2.SymFlagGoType 243 } 244 name := s.Name 245 if strings.HasPrefix(name, "gofile..") { 246 name = filepath.ToSlash(name) 247 } 248 o := goobj2.Sym{ 249 Name: name, 250 ABI: abi, 251 Type: uint8(s.Type), 252 Flag: flag, 253 Siz: uint32(s.Size), 254 } 255 o.Write(w.Writer) 256 } 257 258 func makeSymRef(s *LSym) goobj2.SymRef { 259 if s == nil { 260 return goobj2.SymRef{} 261 } 262 if s.PkgIdx == 0 || !s.Indexed() { 263 fmt.Printf("unindexed symbol reference: %v\n", s) 264 panic("unindexed symbol reference") 265 } 266 return goobj2.SymRef{PkgIdx: uint32(s.PkgIdx), SymIdx: uint32(s.SymIdx)} 267 } 268 269 func (w *writer) Reloc(r *Reloc) { 270 o := goobj2.Reloc{ 271 Off: r.Off, 272 Siz: r.Siz, 273 Type: uint8(r.Type), 274 Add: r.Add, 275 Sym: makeSymRef(r.Sym), 276 } 277 o.Write(w.Writer) 278 } 279 280 func (w *writer) Aux(s *LSym) { 281 if s.Gotype != nil { 282 o := goobj2.Aux{ 283 Type: goobj2.AuxGotype, 284 Sym: makeSymRef(s.Gotype), 285 } 286 o.Write(w.Writer) 287 } 288 if s.Func != nil { 289 o := goobj2.Aux{ 290 Type: goobj2.AuxFuncInfo, 291 Sym: makeSymRef(s.Func.FuncInfoSym), 292 } 293 o.Write(w.Writer) 294 295 for _, d := range s.Func.Pcln.Funcdata { 296 o := goobj2.Aux{ 297 Type: goobj2.AuxFuncdata, 298 Sym: makeSymRef(d), 299 } 300 o.Write(w.Writer) 301 } 302 303 if s.Func.dwarfInfoSym != nil { 304 o := goobj2.Aux{ 305 Type: goobj2.AuxDwarfInfo, 306 Sym: makeSymRef(s.Func.dwarfInfoSym), 307 } 308 o.Write(w.Writer) 309 } 310 if s.Func.dwarfLocSym != nil { 311 o := goobj2.Aux{ 312 Type: goobj2.AuxDwarfLoc, 313 Sym: makeSymRef(s.Func.dwarfLocSym), 314 } 315 o.Write(w.Writer) 316 } 317 if s.Func.dwarfRangesSym != nil { 318 o := goobj2.Aux{ 319 Type: goobj2.AuxDwarfRanges, 320 Sym: makeSymRef(s.Func.dwarfRangesSym), 321 } 322 o.Write(w.Writer) 323 } 324 if s.Func.dwarfDebugLinesSym != nil { 325 o := goobj2.Aux{ 326 Type: goobj2.AuxDwarfLines, 327 Sym: makeSymRef(s.Func.dwarfDebugLinesSym), 328 } 329 o.Write(w.Writer) 330 } 331 } 332 } 333 334 // return the number of aux symbols s have. 335 func nAuxSym(s *LSym) int { 336 n := 0 337 if s.Gotype != nil { 338 n++ 339 } 340 if s.Func != nil { 341 // FuncInfo is an aux symbol, each Funcdata is an aux symbol 342 n += 1 + len(s.Func.Pcln.Funcdata) 343 if s.Func.dwarfInfoSym != nil { 344 n++ 345 } 346 if s.Func.dwarfLocSym != nil { 347 n++ 348 } 349 if s.Func.dwarfRangesSym != nil { 350 n++ 351 } 352 if s.Func.dwarfDebugLinesSym != nil { 353 n++ 354 } 355 } 356 return n 357 } 358 359 // generate symbols for FuncInfo. 360 func genFuncInfoSyms(ctxt *Link) { 361 infosyms := make([]*LSym, 0, len(ctxt.Text)) 362 var pcdataoff uint32 363 var b bytes.Buffer 364 symidx := int32(len(ctxt.defs)) 365 for _, s := range ctxt.Text { 366 if s.Func == nil { 367 continue 368 } 369 nosplit := uint8(0) 370 if s.NoSplit() { 371 nosplit = 1 372 } 373 o := goobj2.FuncInfo{ 374 NoSplit: nosplit, 375 Args: uint32(s.Func.Args), 376 Locals: uint32(s.Func.Locals), 377 } 378 pc := &s.Func.Pcln 379 o.Pcsp = pcdataoff 380 pcdataoff += uint32(len(pc.Pcsp.P)) 381 o.Pcfile = pcdataoff 382 pcdataoff += uint32(len(pc.Pcfile.P)) 383 o.Pcline = pcdataoff 384 pcdataoff += uint32(len(pc.Pcline.P)) 385 o.Pcinline = pcdataoff 386 pcdataoff += uint32(len(pc.Pcinline.P)) 387 o.Pcdata = make([]uint32, len(pc.Pcdata)) 388 for i, pcd := range pc.Pcdata { 389 o.Pcdata[i] = pcdataoff 390 pcdataoff += uint32(len(pcd.P)) 391 } 392 o.PcdataEnd = pcdataoff 393 o.Funcdataoff = make([]uint32, len(pc.Funcdataoff)) 394 for i, x := range pc.Funcdataoff { 395 o.Funcdataoff[i] = uint32(x) 396 } 397 o.File = make([]goobj2.SymRef, len(pc.File)) 398 for i, f := range pc.File { 399 fsym := ctxt.Lookup(f) 400 o.File[i] = makeSymRef(fsym) 401 } 402 o.InlTree = make([]goobj2.InlTreeNode, len(pc.InlTree.nodes)) 403 for i, inl := range pc.InlTree.nodes { 404 f, l := linkgetlineFromPos(ctxt, inl.Pos) 405 fsym := ctxt.Lookup(f) 406 o.InlTree[i] = goobj2.InlTreeNode{ 407 Parent: int32(inl.Parent), 408 File: makeSymRef(fsym), 409 Line: l, 410 Func: makeSymRef(inl.Func), 411 ParentPC: inl.ParentPC, 412 } 413 } 414 415 o.Write(&b) 416 isym := &LSym{ 417 Type: objabi.SDATA, // for now, I don't think it matters 418 PkgIdx: goobj2.PkgIdxSelf, 419 SymIdx: symidx, 420 P: append([]byte(nil), b.Bytes()...), 421 } 422 isym.Set(AttrIndexed, true) 423 symidx++ 424 infosyms = append(infosyms, isym) 425 s.Func.FuncInfoSym = isym 426 b.Reset() 427 } 428 ctxt.defs = append(ctxt.defs, infosyms...) 429 }