github.com/zxy12/go_duplicate_1_12@v0.0.0-20200217043740-b1636fc0368b/src/cmd/internal/obj/objfile.go (about) 1 // Copyright 2013 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 of Go object files. 6 7 package obj 8 9 import ( 10 "bufio" 11 "cmd/internal/dwarf" 12 "cmd/internal/objabi" 13 "cmd/internal/sys" 14 "fmt" 15 "log" 16 "path/filepath" 17 "sort" 18 "sync" 19 ) 20 21 // objWriter writes Go object files. 22 type objWriter struct { 23 wr *bufio.Writer 24 ctxt *Link 25 // Temporary buffer for zigzag int writing. 26 varintbuf [10]uint8 27 28 // Number of objects written of each type. 29 nRefs int 30 nData int 31 nReloc int 32 nPcdata int 33 nAutom int 34 nFuncdata int 35 nFile int 36 } 37 38 func (w *objWriter) addLengths(s *LSym) { 39 w.nData += len(s.P) 40 w.nReloc += len(s.R) 41 42 if s.Type != objabi.STEXT { 43 return 44 } 45 46 pc := &s.Func.Pcln 47 48 data := 0 49 data += len(pc.Pcsp.P) 50 data += len(pc.Pcfile.P) 51 data += len(pc.Pcline.P) 52 data += len(pc.Pcinline.P) 53 for _, pcd := range pc.Pcdata { 54 data += len(pcd.P) 55 } 56 57 w.nData += data 58 w.nPcdata += len(pc.Pcdata) 59 60 w.nAutom += len(s.Func.Autom) 61 w.nFuncdata += len(pc.Funcdataoff) 62 w.nFile += len(pc.File) 63 } 64 65 func (w *objWriter) writeLengths() { 66 w.writeInt(int64(w.nData)) 67 w.writeInt(int64(w.nReloc)) 68 w.writeInt(int64(w.nPcdata)) 69 w.writeInt(int64(w.nAutom)) 70 w.writeInt(int64(w.nFuncdata)) 71 w.writeInt(int64(w.nFile)) 72 } 73 74 func newObjWriter(ctxt *Link, b *bufio.Writer) *objWriter { 75 return &objWriter{ 76 ctxt: ctxt, 77 wr: b, 78 } 79 } 80 81 func WriteObjFile(ctxt *Link, b *bufio.Writer) { 82 w := newObjWriter(ctxt, b) 83 84 // Magic header 85 w.wr.WriteString("\x00go112ld") 86 87 // Version 88 w.wr.WriteByte(1) 89 90 // Autolib 91 for _, pkg := range ctxt.Imports { 92 w.writeString(pkg) 93 } 94 w.writeString("") 95 96 // Symbol references 97 for _, s := range ctxt.Text { 98 w.writeRefs(s) 99 w.addLengths(s) 100 } 101 102 if ctxt.Headtype == objabi.Haix { 103 // Data must be sorted to keep a constant order in TOC symbols. 104 // As they are created during Progedit, two symbols can be switched between 105 // two different compilations. Therefore, BuildID will be different. 106 // TODO: find a better place and optimize to only sort TOC symbols 107 SortSlice(ctxt.Data, func(i, j int) bool { 108 return ctxt.Data[i].Name < ctxt.Data[j].Name 109 }) 110 } 111 112 for _, s := range ctxt.Data { 113 w.writeRefs(s) 114 w.addLengths(s) 115 } 116 for _, s := range ctxt.ABIAliases { 117 w.writeRefs(s) 118 w.addLengths(s) 119 } 120 // End symbol references 121 w.wr.WriteByte(0xff) 122 123 // Lengths 124 w.writeLengths() 125 126 // Data block 127 for _, s := range ctxt.Text { 128 w.wr.Write(s.P) 129 pc := &s.Func.Pcln 130 w.wr.Write(pc.Pcsp.P) 131 w.wr.Write(pc.Pcfile.P) 132 w.wr.Write(pc.Pcline.P) 133 w.wr.Write(pc.Pcinline.P) 134 for _, pcd := range pc.Pcdata { 135 w.wr.Write(pcd.P) 136 } 137 } 138 for _, s := range ctxt.Data { 139 if len(s.P) > 0 { 140 switch s.Type { 141 case objabi.SBSS, objabi.SNOPTRBSS, objabi.STLSBSS: 142 ctxt.Diag("cannot provide data for %v sym %v", s.Type, s.Name) 143 } 144 } 145 w.wr.Write(s.P) 146 } 147 148 // Symbols 149 for _, s := range ctxt.Text { 150 w.writeSym(s) 151 } 152 for _, s := range ctxt.Data { 153 w.writeSym(s) 154 } 155 for _, s := range ctxt.ABIAliases { 156 w.writeSym(s) 157 } 158 159 // Magic footer 160 w.wr.WriteString("\xffgo112ld") 161 } 162 163 // Symbols are prefixed so their content doesn't get confused with the magic footer. 164 const symPrefix = 0xfe 165 166 func (w *objWriter) writeRef(s *LSym, isPath bool) { 167 if s == nil || s.RefIdx != 0 { 168 return 169 } 170 w.wr.WriteByte(symPrefix) 171 if isPath { 172 w.writeString(filepath.ToSlash(s.Name)) 173 } else { 174 w.writeString(s.Name) 175 } 176 // Write ABI/static information. 177 abi := int64(s.ABI()) 178 if s.Static() { 179 abi = -1 180 } 181 w.writeInt(abi) 182 w.nRefs++ 183 s.RefIdx = w.nRefs 184 } 185 186 func (w *objWriter) writeRefs(s *LSym) { 187 w.writeRef(s, false) 188 w.writeRef(s.Gotype, false) 189 for _, r := range s.R { 190 w.writeRef(r.Sym, false) 191 } 192 193 if s.Type == objabi.STEXT { 194 for _, a := range s.Func.Autom { 195 w.writeRef(a.Asym, false) 196 w.writeRef(a.Gotype, false) 197 } 198 pc := &s.Func.Pcln 199 for _, d := range pc.Funcdata { 200 w.writeRef(d, false) 201 } 202 for _, f := range pc.File { 203 fsym := w.ctxt.Lookup(f) 204 w.writeRef(fsym, true) 205 } 206 for _, call := range pc.InlTree.nodes { 207 w.writeRef(call.Func, false) 208 f, _ := linkgetlineFromPos(w.ctxt, call.Pos) 209 fsym := w.ctxt.Lookup(f) 210 w.writeRef(fsym, true) 211 } 212 } 213 } 214 215 func (w *objWriter) writeSymDebug(s *LSym) { 216 ctxt := w.ctxt 217 fmt.Fprintf(ctxt.Bso, "%s ", s.Name) 218 if s.Type != 0 { 219 fmt.Fprintf(ctxt.Bso, "%v ", s.Type) 220 } 221 if s.Static() { 222 fmt.Fprint(ctxt.Bso, "static ") 223 } 224 if s.DuplicateOK() { 225 fmt.Fprintf(ctxt.Bso, "dupok ") 226 } 227 if s.CFunc() { 228 fmt.Fprintf(ctxt.Bso, "cfunc ") 229 } 230 if s.NoSplit() { 231 fmt.Fprintf(ctxt.Bso, "nosplit ") 232 } 233 fmt.Fprintf(ctxt.Bso, "size=%d", s.Size) 234 if s.Type == objabi.STEXT { 235 fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x", uint64(s.Func.Args), uint64(s.Func.Locals)) 236 if s.Leaf() { 237 fmt.Fprintf(ctxt.Bso, " leaf") 238 } 239 } 240 fmt.Fprintf(ctxt.Bso, "\n") 241 if s.Type == objabi.STEXT { 242 for p := s.Func.Text; p != nil; p = p.Link { 243 var s string 244 if ctxt.Debugasm > 1 { 245 s = p.String() 246 } else { 247 s = p.InnermostString() 248 } 249 fmt.Fprintf(ctxt.Bso, "\t%#04x %s\n", uint(int(p.Pc)), s) 250 } 251 } 252 for i := 0; i < len(s.P); i += 16 { 253 fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i)) 254 j := i 255 for j = i; j < i+16 && j < len(s.P); j++ { 256 fmt.Fprintf(ctxt.Bso, " %02x", s.P[j]) 257 } 258 for ; j < i+16; j++ { 259 fmt.Fprintf(ctxt.Bso, " ") 260 } 261 fmt.Fprintf(ctxt.Bso, " ") 262 for j = i; j < i+16 && j < len(s.P); j++ { 263 c := int(s.P[j]) 264 if ' ' <= c && c <= 0x7e { 265 fmt.Fprintf(ctxt.Bso, "%c", c) 266 } else { 267 fmt.Fprintf(ctxt.Bso, ".") 268 } 269 } 270 271 fmt.Fprintf(ctxt.Bso, "\n") 272 } 273 274 sort.Sort(relocByOff(s.R)) // generate stable output 275 for _, r := range s.R { 276 name := "" 277 if r.Sym != nil { 278 name = r.Sym.Name 279 } else if r.Type == objabi.R_TLS_LE { 280 name = "TLS" 281 } 282 if ctxt.Arch.InFamily(sys.ARM, sys.PPC64) { 283 fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%x\n", int(r.Off), r.Siz, r.Type, name, uint64(r.Add)) 284 } else { 285 fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, name, r.Add) 286 } 287 } 288 } 289 290 func (w *objWriter) writeSym(s *LSym) { 291 ctxt := w.ctxt 292 if ctxt.Debugasm > 0 { 293 w.writeSymDebug(s) 294 } 295 296 w.wr.WriteByte(symPrefix) 297 w.wr.WriteByte(byte(s.Type)) 298 w.writeRefIndex(s) 299 flags := int64(0) 300 if s.DuplicateOK() { 301 flags |= 1 302 } 303 if s.Local() { 304 flags |= 1 << 1 305 } 306 if s.MakeTypelink() { 307 flags |= 1 << 2 308 } 309 w.writeInt(flags) 310 w.writeInt(s.Size) 311 w.writeRefIndex(s.Gotype) 312 w.writeInt(int64(len(s.P))) 313 314 w.writeInt(int64(len(s.R))) 315 var r *Reloc 316 for i := range s.R { 317 r = &s.R[i] 318 w.writeInt(int64(r.Off)) 319 w.writeInt(int64(r.Siz)) 320 w.writeInt(int64(r.Type)) 321 w.writeInt(r.Add) 322 w.writeRefIndex(r.Sym) 323 } 324 325 if s.Type != objabi.STEXT { 326 return 327 } 328 329 w.writeInt(int64(s.Func.Args)) 330 w.writeInt(int64(s.Func.Locals)) 331 w.writeBool(s.NoSplit()) 332 flags = int64(0) 333 if s.Leaf() { 334 flags |= 1 335 } 336 if s.CFunc() { 337 flags |= 1 << 1 338 } 339 if s.ReflectMethod() { 340 flags |= 1 << 2 341 } 342 if ctxt.Flag_shared { 343 flags |= 1 << 3 344 } 345 w.writeInt(flags) 346 w.writeInt(int64(len(s.Func.Autom))) 347 for _, a := range s.Func.Autom { 348 w.writeRefIndex(a.Asym) 349 w.writeInt(int64(a.Aoffset)) 350 if a.Name == NAME_AUTO { 351 w.writeInt(objabi.A_AUTO) 352 } else if a.Name == NAME_PARAM { 353 w.writeInt(objabi.A_PARAM) 354 } else if a.Name == NAME_DELETED_AUTO { 355 w.writeInt(objabi.A_DELETED_AUTO) 356 } else { 357 log.Fatalf("%s: invalid local variable type %d", s.Name, a.Name) 358 } 359 w.writeRefIndex(a.Gotype) 360 } 361 362 pc := &s.Func.Pcln 363 w.writeInt(int64(len(pc.Pcsp.P))) 364 w.writeInt(int64(len(pc.Pcfile.P))) 365 w.writeInt(int64(len(pc.Pcline.P))) 366 w.writeInt(int64(len(pc.Pcinline.P))) 367 w.writeInt(int64(len(pc.Pcdata))) 368 for _, pcd := range pc.Pcdata { 369 w.writeInt(int64(len(pcd.P))) 370 } 371 w.writeInt(int64(len(pc.Funcdataoff))) 372 for i := range pc.Funcdataoff { 373 w.writeRefIndex(pc.Funcdata[i]) 374 } 375 for i := range pc.Funcdataoff { 376 w.writeInt(pc.Funcdataoff[i]) 377 } 378 w.writeInt(int64(len(pc.File))) 379 for _, f := range pc.File { 380 fsym := ctxt.Lookup(f) 381 w.writeRefIndex(fsym) 382 } 383 w.writeInt(int64(len(pc.InlTree.nodes))) 384 for _, call := range pc.InlTree.nodes { 385 w.writeInt(int64(call.Parent)) 386 f, l := linkgetlineFromPos(w.ctxt, call.Pos) 387 fsym := ctxt.Lookup(f) 388 w.writeRefIndex(fsym) 389 w.writeInt(int64(l)) 390 w.writeRefIndex(call.Func) 391 w.writeInt(int64(call.ParentPC)) 392 } 393 } 394 395 func (w *objWriter) writeBool(b bool) { 396 if b { 397 w.writeInt(1) 398 } else { 399 w.writeInt(0) 400 } 401 } 402 403 func (w *objWriter) writeInt(sval int64) { 404 var v uint64 405 uv := (uint64(sval) << 1) ^ uint64(sval>>63) 406 p := w.varintbuf[:] 407 for v = uv; v >= 0x80; v >>= 7 { 408 p[0] = uint8(v | 0x80) 409 p = p[1:] 410 } 411 p[0] = uint8(v) 412 p = p[1:] 413 w.wr.Write(w.varintbuf[:len(w.varintbuf)-len(p)]) 414 } 415 416 func (w *objWriter) writeString(s string) { 417 w.writeInt(int64(len(s))) 418 w.wr.WriteString(s) 419 } 420 421 func (w *objWriter) writeRefIndex(s *LSym) { 422 if s == nil { 423 w.writeInt(0) 424 return 425 } 426 if s.RefIdx == 0 { 427 log.Fatalln("writing an unreferenced symbol", s.Name) 428 } 429 w.writeInt(int64(s.RefIdx)) 430 } 431 432 // relocByOff sorts relocations by their offsets. 433 type relocByOff []Reloc 434 435 func (x relocByOff) Len() int { return len(x) } 436 func (x relocByOff) Less(i, j int) bool { return x[i].Off < x[j].Off } 437 func (x relocByOff) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 438 439 // implement dwarf.Context 440 type dwCtxt struct{ *Link } 441 442 func (c dwCtxt) PtrSize() int { 443 return c.Arch.PtrSize 444 } 445 func (c dwCtxt) AddInt(s dwarf.Sym, size int, i int64) { 446 ls := s.(*LSym) 447 ls.WriteInt(c.Link, ls.Size, size, i) 448 } 449 func (c dwCtxt) AddBytes(s dwarf.Sym, b []byte) { 450 ls := s.(*LSym) 451 ls.WriteBytes(c.Link, ls.Size, b) 452 } 453 func (c dwCtxt) AddString(s dwarf.Sym, v string) { 454 ls := s.(*LSym) 455 ls.WriteString(c.Link, ls.Size, len(v), v) 456 ls.WriteInt(c.Link, ls.Size, 1, 0) 457 } 458 func (c dwCtxt) AddAddress(s dwarf.Sym, data interface{}, value int64) { 459 ls := s.(*LSym) 460 size := c.PtrSize() 461 if data != nil { 462 rsym := data.(*LSym) 463 ls.WriteAddr(c.Link, ls.Size, size, rsym, value) 464 } else { 465 ls.WriteInt(c.Link, ls.Size, size, value) 466 } 467 } 468 func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) { 469 panic("should be used only in the linker") 470 } 471 func (c dwCtxt) AddDWARFAddrSectionOffset(s dwarf.Sym, t interface{}, ofs int64) { 472 size := 4 473 if isDwarf64(c.Link) { 474 size = 8 475 } 476 477 ls := s.(*LSym) 478 rsym := t.(*LSym) 479 ls.WriteAddr(c.Link, ls.Size, size, rsym, ofs) 480 r := &ls.R[len(ls.R)-1] 481 r.Type = objabi.R_DWARFSECREF 482 } 483 func (c dwCtxt) AddFileRef(s dwarf.Sym, f interface{}) { 484 ls := s.(*LSym) 485 rsym := f.(*LSym) 486 ls.WriteAddr(c.Link, ls.Size, 4, rsym, 0) 487 r := &ls.R[len(ls.R)-1] 488 r.Type = objabi.R_DWARFFILEREF 489 } 490 491 func (c dwCtxt) CurrentOffset(s dwarf.Sym) int64 { 492 ls := s.(*LSym) 493 return ls.Size 494 } 495 496 // Here "from" is a symbol corresponding to an inlined or concrete 497 // function, "to" is the symbol for the corresponding abstract 498 // function, and "dclIdx" is the index of the symbol of interest with 499 // respect to the Dcl slice of the original pre-optimization version 500 // of the inlined function. 501 func (c dwCtxt) RecordDclReference(from dwarf.Sym, to dwarf.Sym, dclIdx int, inlIndex int) { 502 ls := from.(*LSym) 503 tls := to.(*LSym) 504 ridx := len(ls.R) - 1 505 c.Link.DwFixups.ReferenceChildDIE(ls, ridx, tls, dclIdx, inlIndex) 506 } 507 508 func (c dwCtxt) RecordChildDieOffsets(s dwarf.Sym, vars []*dwarf.Var, offsets []int32) { 509 ls := s.(*LSym) 510 c.Link.DwFixups.RegisterChildDIEOffsets(ls, vars, offsets) 511 } 512 513 func (c dwCtxt) Logf(format string, args ...interface{}) { 514 c.Link.Logf(format, args...) 515 } 516 517 func isDwarf64(ctxt *Link) bool { 518 return ctxt.Headtype == objabi.Haix 519 } 520 521 func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfLocSym, dwarfRangesSym, dwarfAbsFnSym, dwarfIsStmtSym *LSym) { 522 if s.Type != objabi.STEXT { 523 ctxt.Diag("dwarfSym of non-TEXT %v", s) 524 } 525 if s.Func.dwarfInfoSym == nil { 526 s.Func.dwarfInfoSym = ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name) 527 if ctxt.Flag_locationlists { 528 s.Func.dwarfLocSym = ctxt.LookupDerived(s, dwarf.LocPrefix+s.Name) 529 } 530 s.Func.dwarfRangesSym = ctxt.LookupDerived(s, dwarf.RangePrefix+s.Name) 531 if s.WasInlined() { 532 s.Func.dwarfAbsFnSym = ctxt.DwFixups.AbsFuncDwarfSym(s) 533 } 534 s.Func.dwarfIsStmtSym = ctxt.LookupDerived(s, dwarf.IsStmtPrefix+s.Name) 535 536 } 537 return s.Func.dwarfInfoSym, s.Func.dwarfLocSym, s.Func.dwarfRangesSym, s.Func.dwarfAbsFnSym, s.Func.dwarfIsStmtSym 538 } 539 540 func (s *LSym) Len() int64 { 541 return s.Size 542 } 543 544 // fileSymbol returns a symbol corresponding to the source file of the 545 // first instruction (prog) of the specified function. This will 546 // presumably be the file in which the function is defined. 547 func (ctxt *Link) fileSymbol(fn *LSym) *LSym { 548 p := fn.Func.Text 549 if p != nil { 550 f, _ := linkgetlineFromPos(ctxt, p.Pos) 551 fsym := ctxt.Lookup(f) 552 return fsym 553 } 554 return nil 555 } 556 557 // populateDWARF fills in the DWARF Debugging Information Entries for 558 // TEXT symbol 's'. The various DWARF symbols must already have been 559 // initialized in InitTextSym. 560 func (ctxt *Link) populateDWARF(curfn interface{}, s *LSym, myimportpath string) { 561 info, loc, ranges, absfunc, _ := ctxt.dwarfSym(s) 562 if info.Size != 0 { 563 ctxt.Diag("makeFuncDebugEntry double process %v", s) 564 } 565 var scopes []dwarf.Scope 566 var inlcalls dwarf.InlCalls 567 if ctxt.DebugInfo != nil { 568 stmtData(ctxt, s) 569 scopes, inlcalls = ctxt.DebugInfo(s, curfn) 570 } 571 var err error 572 dwctxt := dwCtxt{ctxt} 573 filesym := ctxt.fileSymbol(s) 574 fnstate := &dwarf.FnState{ 575 Name: s.Name, 576 Importpath: myimportpath, 577 Info: info, 578 Filesym: filesym, 579 Loc: loc, 580 Ranges: ranges, 581 Absfn: absfunc, 582 StartPC: s, 583 Size: s.Size, 584 External: !s.Static(), 585 Scopes: scopes, 586 InlCalls: inlcalls, 587 } 588 if absfunc != nil { 589 err = dwarf.PutAbstractFunc(dwctxt, fnstate) 590 if err != nil { 591 ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err) 592 } 593 err = dwarf.PutConcreteFunc(dwctxt, fnstate) 594 } else { 595 err = dwarf.PutDefaultFunc(dwctxt, fnstate) 596 } 597 if err != nil { 598 ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err) 599 } 600 } 601 602 // DwarfIntConst creates a link symbol for an integer constant with the 603 // given name, type and value. 604 func (ctxt *Link) DwarfIntConst(myimportpath, name, typename string, val int64) { 605 if myimportpath == "" { 606 return 607 } 608 s := ctxt.LookupInit(dwarf.ConstInfoPrefix+myimportpath, func(s *LSym) { 609 s.Type = objabi.SDWARFINFO 610 ctxt.Data = append(ctxt.Data, s) 611 }) 612 dwarf.PutIntConst(dwCtxt{ctxt}, s, ctxt.Lookup(dwarf.InfoPrefix+typename), myimportpath+"."+name, val) 613 } 614 615 func (ctxt *Link) DwarfAbstractFunc(curfn interface{}, s *LSym, myimportpath string) { 616 absfn := ctxt.DwFixups.AbsFuncDwarfSym(s) 617 if absfn.Size != 0 { 618 ctxt.Diag("internal error: DwarfAbstractFunc double process %v", s) 619 } 620 if s.Func == nil { 621 s.Func = new(FuncInfo) 622 } 623 scopes, _ := ctxt.DebugInfo(s, curfn) 624 dwctxt := dwCtxt{ctxt} 625 filesym := ctxt.fileSymbol(s) 626 fnstate := dwarf.FnState{ 627 Name: s.Name, 628 Importpath: myimportpath, 629 Info: absfn, 630 Filesym: filesym, 631 Absfn: absfn, 632 External: !s.Static(), 633 Scopes: scopes, 634 } 635 if err := dwarf.PutAbstractFunc(dwctxt, &fnstate); err != nil { 636 ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err) 637 } 638 } 639 640 // This table is designed to aid in the creation of references betweeen 641 // DWARF subprogram DIEs. 642 // 643 // In most cases when one DWARF DIE has to refer to another DWARF DIE, 644 // the target of the reference has an LSym, which makes it easy to use 645 // the existing relocation mechanism. For DWARF inlined routine DIEs, 646 // however, the subprogram DIE has to refer to a child 647 // parameter/variable DIE of the abstract subprogram. This child DIE 648 // doesn't have an LSym, and also of interest is the fact that when 649 // DWARF generation is happening for inlined function F within caller 650 // G, it's possible that DWARF generation hasn't happened yet for F, 651 // so there is no way to know the offset of a child DIE within F's 652 // abstract function. Making matters more complex, each inlined 653 // instance of F may refer to a subset of the original F's variables 654 // (depending on what happens with optimization, some vars may be 655 // eliminated). 656 // 657 // The fixup table below helps overcome this hurdle. At the point 658 // where a parameter/variable reference is made (via a call to 659 // "ReferenceChildDIE"), a fixup record is generate that records 660 // the relocation that is targeting that child variable. At a later 661 // point when the abstract function DIE is emitted, there will be 662 // a call to "RegisterChildDIEOffsets", at which point the offsets 663 // needed to apply fixups are captured. Finally, once the parallel 664 // portion of the compilation is done, fixups can actually be applied 665 // during the "Finalize" method (this can't be done during the 666 // parallel portion of the compile due to the possibility of data 667 // races). 668 // 669 // This table is also used to record the "precursor" function node for 670 // each function that is the target of an inline -- child DIE references 671 // have to be made with respect to the original pre-optimization 672 // version of the function (to allow for the fact that each inlined 673 // body may be optimized differently). 674 type DwarfFixupTable struct { 675 ctxt *Link 676 mu sync.Mutex 677 symtab map[*LSym]int // maps abstract fn LSYM to index in svec 678 svec []symFixups 679 precursor map[*LSym]fnState // maps fn Lsym to precursor Node, absfn sym 680 } 681 682 type symFixups struct { 683 fixups []relFixup 684 doffsets []declOffset 685 inlIndex int32 686 defseen bool 687 } 688 689 type declOffset struct { 690 // Index of variable within DCL list of pre-optimization function 691 dclIdx int32 692 // Offset of var's child DIE with respect to containing subprogram DIE 693 offset int32 694 } 695 696 type relFixup struct { 697 refsym *LSym 698 relidx int32 699 dclidx int32 700 } 701 702 type fnState struct { 703 // precursor function (really *gc.Node) 704 precursor interface{} 705 // abstract function symbol 706 absfn *LSym 707 } 708 709 func NewDwarfFixupTable(ctxt *Link) *DwarfFixupTable { 710 return &DwarfFixupTable{ 711 ctxt: ctxt, 712 symtab: make(map[*LSym]int), 713 precursor: make(map[*LSym]fnState), 714 } 715 } 716 717 func (ft *DwarfFixupTable) GetPrecursorFunc(s *LSym) interface{} { 718 if fnstate, found := ft.precursor[s]; found { 719 return fnstate.precursor 720 } 721 return nil 722 } 723 724 func (ft *DwarfFixupTable) SetPrecursorFunc(s *LSym, fn interface{}) { 725 if _, found := ft.precursor[s]; found { 726 ft.ctxt.Diag("internal error: DwarfFixupTable.SetPrecursorFunc double call on %v", s) 727 } 728 729 // initialize abstract function symbol now. This is done here so 730 // as to avoid data races later on during the parallel portion of 731 // the back end. 732 absfn := ft.ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name+dwarf.AbstractFuncSuffix) 733 absfn.Set(AttrDuplicateOK, true) 734 absfn.Type = objabi.SDWARFINFO 735 ft.ctxt.Data = append(ft.ctxt.Data, absfn) 736 737 ft.precursor[s] = fnState{precursor: fn, absfn: absfn} 738 } 739 740 // Make a note of a child DIE reference: relocation 'ridx' within symbol 's' 741 // is targeting child 'c' of DIE with symbol 'tgt'. 742 func (ft *DwarfFixupTable) ReferenceChildDIE(s *LSym, ridx int, tgt *LSym, dclidx int, inlIndex int) { 743 // Protect against concurrent access if multiple backend workers 744 ft.mu.Lock() 745 defer ft.mu.Unlock() 746 747 // Create entry for symbol if not already present. 748 idx, found := ft.symtab[tgt] 749 if !found { 750 ft.svec = append(ft.svec, symFixups{inlIndex: int32(inlIndex)}) 751 idx = len(ft.svec) - 1 752 ft.symtab[tgt] = idx 753 } 754 755 // Do we have child DIE offsets available? If so, then apply them, 756 // otherwise create a fixup record. 757 sf := &ft.svec[idx] 758 if len(sf.doffsets) > 0 { 759 found := false 760 for _, do := range sf.doffsets { 761 if do.dclIdx == int32(dclidx) { 762 off := do.offset 763 s.R[ridx].Add += int64(off) 764 found = true 765 break 766 } 767 } 768 if !found { 769 ft.ctxt.Diag("internal error: DwarfFixupTable.ReferenceChildDIE unable to locate child DIE offset for dclIdx=%d src=%v tgt=%v", dclidx, s, tgt) 770 } 771 } else { 772 sf.fixups = append(sf.fixups, relFixup{s, int32(ridx), int32(dclidx)}) 773 } 774 } 775 776 // Called once DWARF generation is complete for a given abstract function, 777 // whose children might have been referenced via a call above. Stores 778 // the offsets for any child DIEs (vars, params) so that they can be 779 // consumed later in on DwarfFixupTable.Finalize, which applies any 780 // outstanding fixups. 781 func (ft *DwarfFixupTable) RegisterChildDIEOffsets(s *LSym, vars []*dwarf.Var, coffsets []int32) { 782 // Length of these two slices should agree 783 if len(vars) != len(coffsets) { 784 ft.ctxt.Diag("internal error: RegisterChildDIEOffsets vars/offsets length mismatch") 785 return 786 } 787 788 // Generate the slice of declOffset's based in vars/coffsets 789 doffsets := make([]declOffset, len(coffsets)) 790 for i := range coffsets { 791 doffsets[i].dclIdx = vars[i].ChildIndex 792 doffsets[i].offset = coffsets[i] 793 } 794 795 ft.mu.Lock() 796 defer ft.mu.Unlock() 797 798 // Store offsets for this symbol. 799 idx, found := ft.symtab[s] 800 if !found { 801 sf := symFixups{inlIndex: -1, defseen: true, doffsets: doffsets} 802 ft.svec = append(ft.svec, sf) 803 ft.symtab[s] = len(ft.svec) - 1 804 } else { 805 sf := &ft.svec[idx] 806 sf.doffsets = doffsets 807 sf.defseen = true 808 } 809 } 810 811 func (ft *DwarfFixupTable) processFixups(slot int, s *LSym) { 812 sf := &ft.svec[slot] 813 for _, f := range sf.fixups { 814 dfound := false 815 for _, doffset := range sf.doffsets { 816 if doffset.dclIdx == f.dclidx { 817 f.refsym.R[f.relidx].Add += int64(doffset.offset) 818 dfound = true 819 break 820 } 821 } 822 if !dfound { 823 ft.ctxt.Diag("internal error: DwarfFixupTable has orphaned fixup on %v targeting %v relidx=%d dclidx=%d", f.refsym, s, f.relidx, f.dclidx) 824 } 825 } 826 } 827 828 // return the LSym corresponding to the 'abstract subprogram' DWARF 829 // info entry for a function. 830 func (ft *DwarfFixupTable) AbsFuncDwarfSym(fnsym *LSym) *LSym { 831 // Protect against concurrent access if multiple backend workers 832 ft.mu.Lock() 833 defer ft.mu.Unlock() 834 835 if fnstate, found := ft.precursor[fnsym]; found { 836 return fnstate.absfn 837 } 838 ft.ctxt.Diag("internal error: AbsFuncDwarfSym requested for %v, not seen during inlining", fnsym) 839 return nil 840 } 841 842 // Called after all functions have been compiled; the main job of this 843 // function is to identify cases where there are outstanding fixups. 844 // This scenario crops up when we have references to variables of an 845 // inlined routine, but that routine is defined in some other package. 846 // This helper walks through and locate these fixups, then invokes a 847 // helper to create an abstract subprogram DIE for each one. 848 func (ft *DwarfFixupTable) Finalize(myimportpath string, trace bool) { 849 if trace { 850 ft.ctxt.Logf("DwarfFixupTable.Finalize invoked for %s\n", myimportpath) 851 } 852 853 // Collect up the keys from the precursor map, then sort the 854 // resulting list (don't want to rely on map ordering here). 855 fns := make([]*LSym, len(ft.precursor)) 856 idx := 0 857 for fn := range ft.precursor { 858 fns[idx] = fn 859 idx++ 860 } 861 sort.Sort(bySymName(fns)) 862 863 // Should not be called during parallel portion of compilation. 864 if ft.ctxt.InParallel { 865 ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize call during parallel backend") 866 } 867 868 // Generate any missing abstract functions. 869 for _, s := range fns { 870 absfn := ft.AbsFuncDwarfSym(s) 871 slot, found := ft.symtab[absfn] 872 if !found || !ft.svec[slot].defseen { 873 ft.ctxt.GenAbstractFunc(s) 874 } 875 } 876 877 // Apply fixups. 878 for _, s := range fns { 879 absfn := ft.AbsFuncDwarfSym(s) 880 slot, found := ft.symtab[absfn] 881 if !found { 882 ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize orphan abstract function for %v", s) 883 } else { 884 ft.processFixups(slot, s) 885 } 886 } 887 } 888 889 type bySymName []*LSym 890 891 func (s bySymName) Len() int { return len(s) } 892 func (s bySymName) Less(i, j int) bool { return s[i].Name < s[j].Name } 893 func (s bySymName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }