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