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