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 i := 0; i < len(pc.Pcdata); i++ { 60 data += len(pc.Pcdata[i].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 i := 0; i < len(pc.Pcdata); i++ { 128 w.wr.Write(pc.Pcdata[i].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 if s.Static() { 179 w.writeInt(1) 180 } else { 181 w.writeInt(0) 182 } 183 w.nRefs++ 184 s.RefIdx = w.nRefs 185 m[s.Name] = w.nRefs 186 } 187 188 func (w *objWriter) writeRefs(s *LSym) { 189 w.writeRef(s, false) 190 w.writeRef(s.Gotype, false) 191 for i := range s.R { 192 w.writeRef(s.R[i].Sym, false) 193 } 194 195 if s.Type == objabi.STEXT { 196 for _, a := range s.Func.Autom { 197 w.writeRef(a.Asym, false) 198 w.writeRef(a.Gotype, false) 199 } 200 pc := &s.Func.Pcln 201 for _, d := range pc.Funcdata { 202 w.writeRef(d, false) 203 } 204 for _, f := range pc.File { 205 fsym := w.ctxt.Lookup(f) 206 w.writeRef(fsym, true) 207 } 208 for _, call := range pc.InlTree.nodes { 209 w.writeRef(call.Func, false) 210 f, _ := linkgetlineFromPos(w.ctxt, call.Pos) 211 fsym := w.ctxt.Lookup(f) 212 w.writeRef(fsym, true) 213 } 214 } 215 } 216 217 func (w *objWriter) writeSymDebug(s *LSym) { 218 ctxt := w.ctxt 219 fmt.Fprintf(ctxt.Bso, "%s ", s.Name) 220 if s.Type != 0 { 221 fmt.Fprintf(ctxt.Bso, "%v ", s.Type) 222 } 223 if s.Static() { 224 fmt.Fprint(ctxt.Bso, "static ") 225 } 226 if s.DuplicateOK() { 227 fmt.Fprintf(ctxt.Bso, "dupok ") 228 } 229 if s.CFunc() { 230 fmt.Fprintf(ctxt.Bso, "cfunc ") 231 } 232 if s.NoSplit() { 233 fmt.Fprintf(ctxt.Bso, "nosplit ") 234 } 235 fmt.Fprintf(ctxt.Bso, "size=%d", s.Size) 236 if s.Type == objabi.STEXT { 237 fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x", uint64(s.Func.Args), uint64(s.Func.Locals)) 238 if s.Leaf() { 239 fmt.Fprintf(ctxt.Bso, " leaf") 240 } 241 } 242 fmt.Fprintf(ctxt.Bso, "\n") 243 if s.Type == objabi.STEXT { 244 for p := s.Func.Text; p != nil; p = p.Link { 245 fmt.Fprintf(ctxt.Bso, "\t%#04x %v\n", uint(int(p.Pc)), p) 246 } 247 } 248 for i := 0; i < len(s.P); i += 16 { 249 fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i)) 250 j := i 251 for j = i; j < i+16 && j < len(s.P); j++ { 252 fmt.Fprintf(ctxt.Bso, " %02x", s.P[j]) 253 } 254 for ; j < i+16; j++ { 255 fmt.Fprintf(ctxt.Bso, " ") 256 } 257 fmt.Fprintf(ctxt.Bso, " ") 258 for j = i; j < i+16 && j < len(s.P); j++ { 259 c := int(s.P[j]) 260 if ' ' <= c && c <= 0x7e { 261 fmt.Fprintf(ctxt.Bso, "%c", c) 262 } else { 263 fmt.Fprintf(ctxt.Bso, ".") 264 } 265 } 266 267 fmt.Fprintf(ctxt.Bso, "\n") 268 } 269 270 sort.Sort(relocByOff(s.R)) // generate stable output 271 for _, r := range s.R { 272 name := "" 273 if r.Sym != nil { 274 name = r.Sym.Name 275 } else if r.Type == objabi.R_TLS_LE { 276 name = "TLS" 277 } 278 if ctxt.Arch.InFamily(sys.ARM, sys.PPC64) { 279 fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%x\n", int(r.Off), r.Siz, r.Type, name, uint64(r.Add)) 280 } else { 281 fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, name, r.Add) 282 } 283 } 284 } 285 286 func (w *objWriter) writeSym(s *LSym) { 287 ctxt := w.ctxt 288 if ctxt.Debugasm { 289 w.writeSymDebug(s) 290 } 291 292 w.wr.WriteByte(symPrefix) 293 w.wr.WriteByte(byte(s.Type)) 294 w.writeRefIndex(s) 295 flags := int64(0) 296 if s.DuplicateOK() { 297 flags |= 1 298 } 299 if s.Local() { 300 flags |= 1 << 1 301 } 302 if s.MakeTypelink() { 303 flags |= 1 << 2 304 } 305 w.writeInt(flags) 306 w.writeInt(s.Size) 307 w.writeRefIndex(s.Gotype) 308 w.writeInt(int64(len(s.P))) 309 310 w.writeInt(int64(len(s.R))) 311 var r *Reloc 312 for i := 0; i < len(s.R); i++ { 313 r = &s.R[i] 314 w.writeInt(int64(r.Off)) 315 w.writeInt(int64(r.Siz)) 316 w.writeInt(int64(r.Type)) 317 w.writeInt(r.Add) 318 w.writeRefIndex(r.Sym) 319 } 320 321 if s.Type != objabi.STEXT { 322 return 323 } 324 325 w.writeInt(int64(s.Func.Args)) 326 w.writeInt(int64(s.Func.Locals)) 327 if s.NoSplit() { 328 w.writeInt(1) 329 } else { 330 w.writeInt(0) 331 } 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 i := 0; i < len(pc.Pcdata); i++ { 369 w.writeInt(int64(len(pc.Pcdata[i].P))) 370 } 371 w.writeInt(int64(len(pc.Funcdataoff))) 372 for i := 0; i < len(pc.Funcdataoff); i++ { 373 w.writeRefIndex(pc.Funcdata[i]) 374 } 375 for i := 0; i < len(pc.Funcdataoff); i++ { 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 } 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) AddCURelativeAddress(s dwarf.Sym, data interface{}, value int64) { 460 ls := s.(*LSym) 461 rsym := data.(*LSym) 462 ls.WriteCURelativeAddr(c.Link, ls.Size, rsym, value) 463 } 464 func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) { 465 ls := s.(*LSym) 466 rsym := t.(*LSym) 467 ls.WriteAddr(c.Link, ls.Size, size, rsym, ofs) 468 r := &ls.R[len(ls.R)-1] 469 r.Type = objabi.R_DWARFSECREF 470 } 471 func (c dwCtxt) AddFileRef(s dwarf.Sym, f interface{}) { 472 ls := s.(*LSym) 473 rsym := f.(*LSym) 474 ls.WriteAddr(c.Link, ls.Size, 4, rsym, 0) 475 r := &ls.R[len(ls.R)-1] 476 r.Type = objabi.R_DWARFFILEREF 477 } 478 479 func (c dwCtxt) CurrentOffset(s dwarf.Sym) int64 { 480 ls := s.(*LSym) 481 return ls.Size 482 } 483 484 // Here "from" is a symbol corresponding to an inlined or concrete 485 // function, "to" is the symbol for the corresponding abstract 486 // function, and "dclIdx" is the index of the symbol of interest with 487 // respect to the Dcl slice of the original pre-optimization version 488 // of the inlined function. 489 func (c dwCtxt) RecordDclReference(from dwarf.Sym, to dwarf.Sym, dclIdx int, inlIndex int) { 490 ls := from.(*LSym) 491 tls := to.(*LSym) 492 ridx := len(ls.R) - 1 493 c.Link.DwFixups.ReferenceChildDIE(ls, ridx, tls, dclIdx, inlIndex) 494 } 495 496 func (c dwCtxt) RecordChildDieOffsets(s dwarf.Sym, vars []*dwarf.Var, offsets []int32) { 497 ls := s.(*LSym) 498 c.Link.DwFixups.RegisterChildDIEOffsets(ls, vars, offsets) 499 } 500 501 func (c dwCtxt) Logf(format string, args ...interface{}) { 502 c.Link.Logf(format, args...) 503 } 504 505 func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfLocSym, dwarfRangesSym, dwarfAbsFnSym *LSym) { 506 if s.Type != objabi.STEXT { 507 ctxt.Diag("dwarfSym of non-TEXT %v", s) 508 } 509 if s.Func.dwarfInfoSym == nil { 510 s.Func.dwarfInfoSym = ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name) 511 if ctxt.Flag_locationlists { 512 s.Func.dwarfLocSym = ctxt.LookupDerived(s, dwarf.LocPrefix+s.Name) 513 } 514 s.Func.dwarfRangesSym = ctxt.LookupDerived(s, dwarf.RangePrefix+s.Name) 515 if s.WasInlined() { 516 s.Func.dwarfAbsFnSym = ctxt.DwFixups.AbsFuncDwarfSym(s) 517 } 518 519 } 520 return s.Func.dwarfInfoSym, s.Func.dwarfLocSym, s.Func.dwarfRangesSym, s.Func.dwarfAbsFnSym 521 } 522 523 func (s *LSym) Len() int64 { 524 return s.Size 525 } 526 527 // fileSymbol returns a symbol corresponding to the source file of the 528 // first instruction (prog) of the specified function. This will 529 // presumably be the file in which the function is defined. 530 func (ctxt *Link) fileSymbol(fn *LSym) *LSym { 531 p := fn.Func.Text 532 if p != nil { 533 f, _ := linkgetlineFromPos(ctxt, p.Pos) 534 fsym := ctxt.Lookup(f) 535 return fsym 536 } 537 return nil 538 } 539 540 // populateDWARF fills in the DWARF Debugging Information Entries for 541 // TEXT symbol 's'. The various DWARF symbols must already have been 542 // initialized in InitTextSym. 543 func (ctxt *Link) populateDWARF(curfn interface{}, s *LSym, myimportpath string) { 544 info, loc, ranges, absfunc := ctxt.dwarfSym(s) 545 if info.Size != 0 { 546 ctxt.Diag("makeFuncDebugEntry double process %v", s) 547 } 548 var scopes []dwarf.Scope 549 var inlcalls dwarf.InlCalls 550 if ctxt.DebugInfo != nil { 551 scopes, inlcalls = ctxt.DebugInfo(s, curfn) 552 } 553 var err error 554 dwctxt := dwCtxt{ctxt} 555 filesym := ctxt.fileSymbol(s) 556 fnstate := &dwarf.FnState{ 557 Name: s.Name, 558 Importpath: myimportpath, 559 Info: info, 560 Filesym: filesym, 561 Loc: loc, 562 Ranges: ranges, 563 Absfn: absfunc, 564 StartPC: s, 565 Size: s.Size, 566 External: !s.Static(), 567 Scopes: scopes, 568 InlCalls: inlcalls, 569 } 570 if absfunc != nil { 571 err = dwarf.PutAbstractFunc(dwctxt, fnstate) 572 if err != nil { 573 ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err) 574 } 575 err = dwarf.PutConcreteFunc(dwctxt, fnstate) 576 } else { 577 err = dwarf.PutDefaultFunc(dwctxt, fnstate) 578 } 579 if err != nil { 580 ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err) 581 } 582 } 583 584 // DwarfIntConst creates a link symbol for an integer constant with the 585 // given name, type and value. 586 func (ctxt *Link) DwarfIntConst(myimportpath, name, typename string, val int64) { 587 if myimportpath == "" { 588 return 589 } 590 s := ctxt.LookupInit(dwarf.ConstInfoPrefix+myimportpath, func(s *LSym) { 591 s.Type = objabi.SDWARFINFO 592 ctxt.Data = append(ctxt.Data, s) 593 }) 594 dwarf.PutIntConst(dwCtxt{ctxt}, s, ctxt.Lookup(dwarf.InfoPrefix+typename), myimportpath+"."+name, val) 595 } 596 597 func (ctxt *Link) DwarfAbstractFunc(curfn interface{}, s *LSym, myimportpath string) { 598 absfn := ctxt.DwFixups.AbsFuncDwarfSym(s) 599 if absfn.Size != 0 { 600 ctxt.Diag("internal error: DwarfAbstractFunc double process %v", s) 601 } 602 if s.Func == nil { 603 s.Func = new(FuncInfo) 604 } 605 scopes, _ := ctxt.DebugInfo(s, curfn) 606 dwctxt := dwCtxt{ctxt} 607 filesym := ctxt.fileSymbol(s) 608 fnstate := dwarf.FnState{ 609 Name: s.Name, 610 Importpath: myimportpath, 611 Info: absfn, 612 Filesym: filesym, 613 Absfn: absfn, 614 External: !s.Static(), 615 Scopes: scopes, 616 } 617 if err := dwarf.PutAbstractFunc(dwctxt, &fnstate); err != nil { 618 ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err) 619 } 620 } 621 622 // This table is designed to aid in the creation of references betweeen 623 // DWARF subprogram DIEs. 624 // 625 // In most cases when one DWARF DIE has to refer to another DWARF DIE, 626 // the target of the reference has an LSym, which makes it easy to use 627 // the existing relocation mechanism. For DWARF inlined routine DIEs, 628 // however, the subprogram DIE has to refer to a child 629 // parameter/variable DIE of the abstract subprogram. This child DIE 630 // doesn't have an LSym, and also of interest is the fact that when 631 // DWARF generation is happening for inlined function F within caller 632 // G, it's possible that DWARF generation hasn't happened yet for F, 633 // so there is no way to know the offset of a child DIE within F's 634 // abstract function. Making matters more complex, each inlined 635 // instance of F may refer to a subset of the original F's variables 636 // (depending on what happens with optimization, some vars may be 637 // eliminated). 638 // 639 // The fixup table below helps overcome this hurdle. At the point 640 // where a parameter/variable reference is made (via a call to 641 // "ReferenceChildDIE"), a fixup record is generate that records 642 // the relocation that is targeting that child variable. At a later 643 // point when the abstract function DIE is emitted, there will be 644 // a call to "RegisterChildDIEOffsets", at which point the offsets 645 // needed to apply fixups are captured. Finally, once the parallel 646 // portion of the compilation is done, fixups can actually be applied 647 // during the "Finalize" method (this can't be done during the 648 // parallel portion of the compile due to the possibility of data 649 // races). 650 // 651 // This table is also used to record the "precursor" function node for 652 // each function that is the target of an inline -- child DIE references 653 // have to be made with respect to the original pre-optimization 654 // version of the function (to allow for the fact that each inlined 655 // body may be optimized differently). 656 type DwarfFixupTable struct { 657 ctxt *Link 658 mu sync.Mutex 659 symtab map[*LSym]int // maps abstract fn LSYM to index in svec 660 svec []symFixups 661 precursor map[*LSym]fnState // maps fn Lsym to precursor Node, absfn sym 662 } 663 664 type symFixups struct { 665 fixups []relFixup 666 doffsets []declOffset 667 inlIndex int32 668 defseen bool 669 } 670 671 type declOffset struct { 672 // Index of variable within DCL list of pre-optimization function 673 dclIdx int32 674 // Offset of var's child DIE with respect to containing subprogram DIE 675 offset int32 676 } 677 678 type relFixup struct { 679 refsym *LSym 680 relidx int32 681 dclidx int32 682 } 683 684 type fnState struct { 685 // precursor function (really *gc.Node) 686 precursor interface{} 687 // abstract function symbol 688 absfn *LSym 689 } 690 691 func NewDwarfFixupTable(ctxt *Link) *DwarfFixupTable { 692 return &DwarfFixupTable{ 693 ctxt: ctxt, 694 symtab: make(map[*LSym]int), 695 precursor: make(map[*LSym]fnState), 696 } 697 } 698 699 func (ft *DwarfFixupTable) GetPrecursorFunc(s *LSym) interface{} { 700 if fnstate, found := ft.precursor[s]; found { 701 return fnstate.precursor 702 } 703 return nil 704 } 705 706 func (ft *DwarfFixupTable) SetPrecursorFunc(s *LSym, fn interface{}) { 707 if _, found := ft.precursor[s]; found { 708 ft.ctxt.Diag("internal error: DwarfFixupTable.SetPrecursorFunc double call on %v", s) 709 } 710 711 // initialize abstract function symbol now. This is done here so 712 // as to avoid data races later on during the parallel portion of 713 // the back end. 714 absfn := ft.ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name+dwarf.AbstractFuncSuffix) 715 absfn.Set(AttrDuplicateOK, true) 716 absfn.Type = objabi.SDWARFINFO 717 ft.ctxt.Data = append(ft.ctxt.Data, absfn) 718 719 ft.precursor[s] = fnState{precursor: fn, absfn: absfn} 720 } 721 722 // Make a note of a child DIE reference: relocation 'ridx' within symbol 's' 723 // is targeting child 'c' of DIE with symbol 'tgt'. 724 func (ft *DwarfFixupTable) ReferenceChildDIE(s *LSym, ridx int, tgt *LSym, dclidx int, inlIndex int) { 725 // Protect against concurrent access if multiple backend workers 726 ft.mu.Lock() 727 defer ft.mu.Unlock() 728 729 // Create entry for symbol if not already present. 730 idx, found := ft.symtab[tgt] 731 if !found { 732 ft.svec = append(ft.svec, symFixups{inlIndex: int32(inlIndex)}) 733 idx = len(ft.svec) - 1 734 ft.symtab[tgt] = idx 735 } 736 737 // Do we have child DIE offsets available? If so, then apply them, 738 // otherwise create a fixup record. 739 sf := &ft.svec[idx] 740 if len(sf.doffsets) > 0 { 741 found := false 742 for _, do := range sf.doffsets { 743 if do.dclIdx == int32(dclidx) { 744 off := do.offset 745 s.R[ridx].Add += int64(off) 746 found = true 747 break 748 } 749 } 750 if !found { 751 ft.ctxt.Diag("internal error: DwarfFixupTable.ReferenceChildDIE unable to locate child DIE offset for dclIdx=%d src=%v tgt=%v", dclidx, s, tgt) 752 } 753 } else { 754 sf.fixups = append(sf.fixups, relFixup{s, int32(ridx), int32(dclidx)}) 755 } 756 } 757 758 // Called once DWARF generation is complete for a given abstract function, 759 // whose children might have been referenced via a call above. Stores 760 // the offsets for any child DIEs (vars, params) so that they can be 761 // consumed later in on DwarfFixupTable.Finalize, which applies any 762 // outstanding fixups. 763 func (ft *DwarfFixupTable) RegisterChildDIEOffsets(s *LSym, vars []*dwarf.Var, coffsets []int32) { 764 // Length of these two slices should agree 765 if len(vars) != len(coffsets) { 766 ft.ctxt.Diag("internal error: RegisterChildDIEOffsets vars/offsets length mismatch") 767 return 768 } 769 770 // Generate the slice of declOffset's based in vars/coffsets 771 doffsets := make([]declOffset, len(coffsets)) 772 for i := 0; i < len(coffsets); i++ { 773 doffsets[i].dclIdx = vars[i].ChildIndex 774 doffsets[i].offset = coffsets[i] 775 } 776 777 ft.mu.Lock() 778 defer ft.mu.Unlock() 779 780 // Store offsets for this symbol. 781 idx, found := ft.symtab[s] 782 if !found { 783 sf := symFixups{inlIndex: -1, defseen: true, doffsets: doffsets} 784 ft.svec = append(ft.svec, sf) 785 ft.symtab[s] = len(ft.svec) - 1 786 } else { 787 sf := &ft.svec[idx] 788 sf.doffsets = doffsets 789 sf.defseen = true 790 } 791 } 792 793 func (ft *DwarfFixupTable) processFixups(slot int, s *LSym) { 794 sf := &ft.svec[slot] 795 for _, f := range sf.fixups { 796 dfound := false 797 for i := 0; i < len(sf.doffsets); i++ { 798 if sf.doffsets[i].dclIdx == f.dclidx { 799 f.refsym.R[f.relidx].Add += int64(sf.doffsets[i].offset) 800 dfound = true 801 break 802 } 803 } 804 if !dfound { 805 ft.ctxt.Diag("internal error: DwarfFixupTable has orphaned fixup on %v targeting %v relidx=%d dclidx=%d", f.refsym, s, f.relidx, f.dclidx) 806 } 807 } 808 } 809 810 // return the LSym corresponding to the 'abstract subprogram' DWARF 811 // info entry for a function. 812 func (ft *DwarfFixupTable) AbsFuncDwarfSym(fnsym *LSym) *LSym { 813 // Protect against concurrent access if multiple backend workers 814 ft.mu.Lock() 815 defer ft.mu.Unlock() 816 817 if fnstate, found := ft.precursor[fnsym]; found { 818 return fnstate.absfn 819 } 820 ft.ctxt.Diag("internal error: AbsFuncDwarfSym requested for %v, not seen during inlining", fnsym) 821 return nil 822 } 823 824 // Called after all functions have been compiled; the main job of this 825 // function is to identify cases where there are outstanding fixups. 826 // This scenario crops up when we have references to variables of an 827 // inlined routine, but that routine is defined in some other package. 828 // This helper walks through and locate these fixups, then invokes a 829 // helper to create an abstract subprogram DIE for each one. 830 func (ft *DwarfFixupTable) Finalize(myimportpath string, trace bool) { 831 if trace { 832 ft.ctxt.Logf("DwarfFixupTable.Finalize invoked for %s\n", myimportpath) 833 } 834 835 // Collect up the keys from the precursor map, then sort the 836 // resulting list (don't want to rely on map ordering here). 837 fns := make([]*LSym, len(ft.precursor)) 838 idx := 0 839 for fn, _ := range ft.precursor { 840 fns[idx] = fn 841 idx++ 842 } 843 sort.Sort(bySymName(fns)) 844 845 // Should not be called during parallel portion of compilation. 846 if ft.ctxt.InParallel { 847 ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize call during parallel backend") 848 } 849 850 // Generate any missing abstract functions. 851 for i := 0; i < len(fns); i++ { 852 s := fns[i] 853 absfn := ft.AbsFuncDwarfSym(s) 854 slot, found := ft.symtab[absfn] 855 if !found || !ft.svec[slot].defseen { 856 ft.ctxt.GenAbstractFunc(s) 857 } 858 } 859 860 // Apply fixups. 861 for i := 0; i < len(fns); i++ { 862 s := fns[i] 863 absfn := ft.AbsFuncDwarfSym(s) 864 slot, found := ft.symtab[absfn] 865 if !found { 866 ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize orphan abstract function for %v", s) 867 } else { 868 ft.processFixups(slot, s) 869 } 870 } 871 } 872 873 type bySymName []*LSym 874 875 func (s bySymName) Len() int { return len(s) } 876 func (s bySymName) Less(i, j int) bool { return s[i].Name < s[j].Name } 877 func (s bySymName) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 878