github.com/bir3/gocompiler@v0.3.205/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 Go object files. 6 7 package obj 8 9 import ( 10 "bytes" 11 "github.com/bir3/gocompiler/src/cmd/internal/bio" 12 "github.com/bir3/gocompiler/src/cmd/internal/goobj" 13 "github.com/bir3/gocompiler/src/cmd/internal/notsha256" 14 "github.com/bir3/gocompiler/src/cmd/internal/objabi" 15 "github.com/bir3/gocompiler/src/cmd/internal/sys" 16 "encoding/binary" 17 "fmt" 18 "io" 19 "log" 20 "os" 21 "path/filepath" 22 "sort" 23 "strings" 24 ) 25 26 const UnlinkablePkg = "<unlinkable>" // invalid package path, used when compiled without -p flag 27 28 // Entry point of writing new object file. 29 func WriteObjFile(ctxt *Link, b *bio.Writer) { 30 31 debugAsmEmit(ctxt) 32 33 genFuncInfoSyms(ctxt) 34 35 w := writer{ 36 Writer: goobj.NewWriter(b), 37 ctxt: ctxt, 38 pkgpath: objabi.PathToPrefix(ctxt.Pkgpath), 39 } 40 41 start := b.Offset() 42 w.init() 43 44 // Header 45 // We just reserve the space. We'll fill in the offsets later. 46 flags := uint32(0) 47 if ctxt.Flag_shared { 48 flags |= goobj.ObjFlagShared 49 } 50 if w.pkgpath == UnlinkablePkg { 51 flags |= goobj.ObjFlagUnlinkable 52 } 53 if w.pkgpath == "" { 54 log.Fatal("empty package path") 55 } 56 if ctxt.IsAsm { 57 flags |= goobj.ObjFlagFromAssembly 58 } 59 h := goobj.Header{ 60 Magic: goobj.Magic, 61 Fingerprint: ctxt.Fingerprint, 62 Flags: flags, 63 } 64 h.Write(w.Writer) 65 66 // String table 67 w.StringTable() 68 69 // Autolib 70 h.Offsets[goobj.BlkAutolib] = w.Offset() 71 for i := range ctxt.Imports { 72 ctxt.Imports[i].Write(w.Writer) 73 } 74 75 // Package references 76 h.Offsets[goobj.BlkPkgIdx] = w.Offset() 77 for _, pkg := range w.pkglist { 78 w.StringRef(pkg) 79 } 80 81 // File table (for DWARF and pcln generation). 82 h.Offsets[goobj.BlkFile] = w.Offset() 83 for _, f := range ctxt.PosTable.FileTable() { 84 w.StringRef(filepath.ToSlash(f)) 85 } 86 87 // Symbol definitions 88 h.Offsets[goobj.BlkSymdef] = w.Offset() 89 for _, s := range ctxt.defs { 90 w.Sym(s) 91 } 92 93 // Short hashed symbol definitions 94 h.Offsets[goobj.BlkHashed64def] = w.Offset() 95 for _, s := range ctxt.hashed64defs { 96 w.Sym(s) 97 } 98 99 // Hashed symbol definitions 100 h.Offsets[goobj.BlkHasheddef] = w.Offset() 101 for _, s := range ctxt.hasheddefs { 102 w.Sym(s) 103 } 104 105 // Non-pkg symbol definitions 106 h.Offsets[goobj.BlkNonpkgdef] = w.Offset() 107 for _, s := range ctxt.nonpkgdefs { 108 w.Sym(s) 109 } 110 111 // Non-pkg symbol references 112 h.Offsets[goobj.BlkNonpkgref] = w.Offset() 113 for _, s := range ctxt.nonpkgrefs { 114 w.Sym(s) 115 } 116 117 // Referenced package symbol flags 118 h.Offsets[goobj.BlkRefFlags] = w.Offset() 119 w.refFlags() 120 121 // Hashes 122 h.Offsets[goobj.BlkHash64] = w.Offset() 123 for _, s := range ctxt.hashed64defs { 124 w.Hash64(s) 125 } 126 h.Offsets[goobj.BlkHash] = w.Offset() 127 for _, s := range ctxt.hasheddefs { 128 w.Hash(s) 129 } 130 // TODO: hashedrefs unused/unsupported for now 131 132 // Reloc indexes 133 h.Offsets[goobj.BlkRelocIdx] = w.Offset() 134 nreloc := uint32(0) 135 lists := [][]*LSym{ctxt.defs, ctxt.hashed64defs, ctxt.hasheddefs, ctxt.nonpkgdefs} 136 for _, list := range lists { 137 for _, s := range list { 138 w.Uint32(nreloc) 139 nreloc += uint32(len(s.R)) 140 } 141 } 142 w.Uint32(nreloc) 143 144 // Symbol Info indexes 145 h.Offsets[goobj.BlkAuxIdx] = w.Offset() 146 naux := uint32(0) 147 for _, list := range lists { 148 for _, s := range list { 149 w.Uint32(naux) 150 naux += uint32(nAuxSym(s)) 151 } 152 } 153 w.Uint32(naux) 154 155 // Data indexes 156 h.Offsets[goobj.BlkDataIdx] = w.Offset() 157 dataOff := int64(0) 158 for _, list := range lists { 159 for _, s := range list { 160 w.Uint32(uint32(dataOff)) 161 dataOff += int64(len(s.P)) 162 if file := s.File(); file != nil { 163 dataOff += int64(file.Size) 164 } 165 } 166 } 167 if int64(uint32(dataOff)) != dataOff { 168 log.Fatalf("data too large") 169 } 170 w.Uint32(uint32(dataOff)) 171 172 // Relocs 173 h.Offsets[goobj.BlkReloc] = w.Offset() 174 for _, list := range lists { 175 for _, s := range list { 176 sort.Sort(relocByOff(s.R)) // some platforms (e.g. PE) requires relocations in address order 177 for i := range s.R { 178 w.Reloc(&s.R[i]) 179 } 180 } 181 } 182 183 // Aux symbol info 184 h.Offsets[goobj.BlkAux] = w.Offset() 185 for _, list := range lists { 186 for _, s := range list { 187 w.Aux(s) 188 } 189 } 190 191 // Data 192 h.Offsets[goobj.BlkData] = w.Offset() 193 for _, list := range lists { 194 for _, s := range list { 195 w.Bytes(s.P) 196 if file := s.File(); file != nil { 197 w.writeFile(ctxt, file) 198 } 199 } 200 } 201 202 // Blocks used only by tools (objdump, nm). 203 204 // Referenced symbol names from other packages 205 h.Offsets[goobj.BlkRefName] = w.Offset() 206 w.refNames() 207 208 h.Offsets[goobj.BlkEnd] = w.Offset() 209 210 // Fix up block offsets in the header 211 end := start + int64(w.Offset()) 212 b.MustSeek(start, 0) 213 h.Write(w.Writer) 214 b.MustSeek(end, 0) 215 } 216 217 type writer struct { 218 *goobj.Writer 219 filebuf []byte 220 ctxt *Link 221 pkgpath string // the package import path (escaped), "" if unknown 222 pkglist []string // list of packages referenced, indexed by ctxt.pkgIdx 223 224 // scratch space for writing (the Write methods escape 225 // as they are interface calls) 226 tmpSym goobj.Sym 227 tmpReloc goobj.Reloc 228 tmpAux goobj.Aux 229 tmpHash64 goobj.Hash64Type 230 tmpHash goobj.HashType 231 tmpRefFlags goobj.RefFlags 232 tmpRefName goobj.RefName 233 } 234 235 // prepare package index list 236 func (w *writer) init() { 237 w.pkglist = make([]string, len(w.ctxt.pkgIdx)+1) 238 w.pkglist[0] = "" // dummy invalid package for index 0 239 for pkg, i := range w.ctxt.pkgIdx { 240 w.pkglist[i] = pkg 241 } 242 } 243 244 func (w *writer) writeFile(ctxt *Link, file *FileInfo) { 245 f, err := os.Open(file.Name) 246 if err != nil { 247 ctxt.Diag("%v", err) 248 return 249 } 250 defer f.Close() 251 if w.filebuf == nil { 252 w.filebuf = make([]byte, 1024) 253 } 254 buf := w.filebuf 255 written := int64(0) 256 for { 257 n, err := f.Read(buf) 258 w.Bytes(buf[:n]) 259 written += int64(n) 260 if err == io.EOF { 261 break 262 } 263 if err != nil { 264 ctxt.Diag("%v", err) 265 return 266 } 267 } 268 if written != file.Size { 269 ctxt.Diag("copy %s: unexpected length %d != %d", file.Name, written, file.Size) 270 } 271 } 272 273 func (w *writer) StringTable() { 274 w.AddString("") 275 for _, p := range w.ctxt.Imports { 276 w.AddString(p.Pkg) 277 } 278 for _, pkg := range w.pkglist { 279 w.AddString(pkg) 280 } 281 w.ctxt.traverseSyms(traverseAll, func(s *LSym) { 282 // Don't put names of builtins into the string table (to save 283 // space). 284 if s.PkgIdx == goobj.PkgIdxBuiltin { 285 return 286 } 287 // TODO: this includes references of indexed symbols from other packages, 288 // for which the linker doesn't need the name. Consider moving them to 289 // a separate block (for tools only). 290 if w.ctxt.Flag_noRefName && s.PkgIdx < goobj.PkgIdxSpecial { 291 // Don't include them if Flag_noRefName 292 return 293 } 294 if w.pkgpath != "" { 295 s.Name = strings.Replace(s.Name, "\"\".", w.pkgpath+".", -1) 296 } 297 w.AddString(s.Name) 298 }) 299 300 // All filenames are in the postable. 301 for _, f := range w.ctxt.PosTable.FileTable() { 302 w.AddString(filepath.ToSlash(f)) 303 } 304 } 305 306 // cutoff is the maximum data section size permitted by the linker 307 // (see issue #9862). 308 const cutoff = int64(2e9) // 2 GB (or so; looks better in errors than 2^31) 309 310 func (w *writer) Sym(s *LSym) { 311 abi := uint16(s.ABI()) 312 if s.Static() { 313 abi = goobj.SymABIstatic 314 } 315 flag := uint8(0) 316 if s.DuplicateOK() { 317 flag |= goobj.SymFlagDupok 318 } 319 if s.Local() { 320 flag |= goobj.SymFlagLocal 321 } 322 if s.MakeTypelink() { 323 flag |= goobj.SymFlagTypelink 324 } 325 if s.Leaf() { 326 flag |= goobj.SymFlagLeaf 327 } 328 if s.NoSplit() { 329 flag |= goobj.SymFlagNoSplit 330 } 331 if s.ReflectMethod() { 332 flag |= goobj.SymFlagReflectMethod 333 } 334 if strings.HasPrefix(s.Name, "type:") && s.Name[5] != '.' && s.Type == objabi.SRODATA { 335 flag |= goobj.SymFlagGoType 336 } 337 flag2 := uint8(0) 338 if s.UsedInIface() { 339 flag2 |= goobj.SymFlagUsedInIface 340 } 341 if strings.HasPrefix(s.Name, "go:itab.") && s.Type == objabi.SRODATA { 342 flag2 |= goobj.SymFlagItab 343 } 344 if strings.HasPrefix(s.Name, w.ctxt.Pkgpath) && strings.HasPrefix(s.Name[len(w.ctxt.Pkgpath):], ".") && strings.HasPrefix(s.Name[len(w.ctxt.Pkgpath)+1:], objabi.GlobalDictPrefix) { 345 flag2 |= goobj.SymFlagDict 346 } 347 name := s.Name 348 if strings.HasPrefix(name, "gofile..") { 349 name = filepath.ToSlash(name) 350 } 351 var align uint32 352 if fn := s.Func(); fn != nil { 353 align = uint32(fn.Align) 354 } 355 if s.ContentAddressable() && s.Size != 0 { 356 // We generally assume data symbols are natually aligned 357 // (e.g. integer constants), except for strings and a few 358 // compiler-emitted funcdata. If we dedup a string symbol and 359 // a non-string symbol with the same content, we should keep 360 // the largest alignment. 361 // TODO: maybe the compiler could set the alignment for all 362 // data symbols more carefully. 363 switch { 364 case strings.HasPrefix(s.Name, "go:string."), 365 strings.HasPrefix(name, "type:.namedata."), 366 strings.HasPrefix(name, "type:.importpath."), 367 strings.HasSuffix(name, ".opendefer"), 368 strings.HasSuffix(name, ".arginfo0"), 369 strings.HasSuffix(name, ".arginfo1"), 370 strings.HasSuffix(name, ".argliveinfo"): 371 // These are just bytes, or varints. 372 align = 1 373 case strings.HasPrefix(name, "gclocals·"): 374 // It has 32-bit fields. 375 align = 4 376 default: 377 switch { 378 case w.ctxt.Arch.PtrSize == 8 && s.Size%8 == 0: 379 align = 8 380 case s.Size%4 == 0: 381 align = 4 382 case s.Size%2 == 0: 383 align = 2 384 default: 385 align = 1 386 } 387 } 388 } 389 if s.Size > cutoff { 390 w.ctxt.Diag("%s: symbol too large (%d bytes > %d bytes)", s.Name, s.Size, cutoff) 391 } 392 o := &w.tmpSym 393 o.SetName(name, w.Writer) 394 o.SetABI(abi) 395 o.SetType(uint8(s.Type)) 396 o.SetFlag(flag) 397 o.SetFlag2(flag2) 398 o.SetSiz(uint32(s.Size)) 399 o.SetAlign(align) 400 o.Write(w.Writer) 401 } 402 403 func (w *writer) Hash64(s *LSym) { 404 if !s.ContentAddressable() || len(s.R) != 0 { 405 panic("Hash of non-content-addressable symbol") 406 } 407 w.tmpHash64 = contentHash64(s) 408 w.Bytes(w.tmpHash64[:]) 409 } 410 411 func (w *writer) Hash(s *LSym) { 412 if !s.ContentAddressable() { 413 panic("Hash of non-content-addressable symbol") 414 } 415 w.tmpHash = w.contentHash(s) 416 w.Bytes(w.tmpHash[:]) 417 } 418 419 // contentHashSection returns a mnemonic for s's section. 420 // The goal is to prevent content-addressability from moving symbols between sections. 421 // contentHashSection only distinguishes between sets of sections for which this matters. 422 // Allowing flexibility increases the effectiveness of content-addressibility. 423 // But in some cases, such as doing addressing based on a base symbol, 424 // we need to ensure that a symbol is always in a prticular section. 425 // Some of these conditions are duplicated in cmd/link/internal/ld.(*Link).symtab. 426 // TODO: instead of duplicating them, have the compiler decide where symbols go. 427 func contentHashSection(s *LSym) byte { 428 name := s.Name 429 if s.IsPcdata() { 430 return 'P' 431 } 432 if strings.HasPrefix(name, "gcargs.") || 433 strings.HasPrefix(name, "gclocals.") || 434 strings.HasPrefix(name, "gclocals·") || 435 strings.HasSuffix(name, ".opendefer") || 436 strings.HasSuffix(name, ".arginfo0") || 437 strings.HasSuffix(name, ".arginfo1") || 438 strings.HasSuffix(name, ".argliveinfo") || 439 strings.HasSuffix(name, ".wrapinfo") || 440 strings.HasSuffix(name, ".args_stackmap") || 441 strings.HasSuffix(name, ".stkobj") { 442 return 'F' // go:func.* or go:funcrel.* 443 } 444 if strings.HasPrefix(name, "type:") { 445 return 'T' 446 } 447 return 0 448 } 449 450 func contentHash64(s *LSym) goobj.Hash64Type { 451 if contentHashSection(s) != 0 { 452 panic("short hash of non-default-section sym " + s.Name) 453 } 454 var b goobj.Hash64Type 455 copy(b[:], s.P) 456 return b 457 } 458 459 // Compute the content hash for a content-addressable symbol. 460 // We build a content hash based on its content and relocations. 461 // Depending on the category of the referenced symbol, we choose 462 // different hash algorithms such that the hash is globally 463 // consistent. 464 // - For referenced content-addressable symbol, its content hash 465 // is globally consistent. 466 // - For package symbol and builtin symbol, its local index is 467 // globally consistent. 468 // - For non-package symbol, its fully-expanded name is globally 469 // consistent. For now, we require we know the current package 470 // path so we can always expand symbol names. (Otherwise, 471 // symbols with relocations are not considered hashable.) 472 // 473 // For now, we assume there is no circular dependencies among 474 // hashed symbols. 475 func (w *writer) contentHash(s *LSym) goobj.HashType { 476 h := notsha256.New() 477 var tmp [14]byte 478 479 // Include the size of the symbol in the hash. 480 // This preserves the length of symbols, preventing the following two symbols 481 // from hashing the same: 482 // 483 // [2]int{1,2} ≠ [10]int{1,2,0,0,0...} 484 // 485 // In this case, if the smaller symbol is alive, the larger is not kept unless 486 // needed. 487 binary.LittleEndian.PutUint64(tmp[:8], uint64(s.Size)) 488 // Some symbols require being in separate sections. 489 tmp[8] = contentHashSection(s) 490 h.Write(tmp[:9]) 491 492 // The compiler trims trailing zeros _sometimes_. We just do 493 // it always. 494 h.Write(bytes.TrimRight(s.P, "\x00")) 495 for i := range s.R { 496 r := &s.R[i] 497 binary.LittleEndian.PutUint32(tmp[:4], uint32(r.Off)) 498 tmp[4] = r.Siz 499 tmp[5] = uint8(r.Type) 500 binary.LittleEndian.PutUint64(tmp[6:14], uint64(r.Add)) 501 h.Write(tmp[:]) 502 rs := r.Sym 503 if rs == nil { 504 fmt.Printf("symbol: %s\n", s) 505 fmt.Printf("relocation: %#v\n", r) 506 panic("nil symbol target in relocation") 507 } 508 switch rs.PkgIdx { 509 case goobj.PkgIdxHashed64: 510 h.Write([]byte{0}) 511 t := contentHash64(rs) 512 h.Write(t[:]) 513 case goobj.PkgIdxHashed: 514 h.Write([]byte{1}) 515 t := w.contentHash(rs) 516 h.Write(t[:]) 517 case goobj.PkgIdxNone: 518 h.Write([]byte{2}) 519 io.WriteString(h, rs.Name) // name is already expanded at this point 520 case goobj.PkgIdxBuiltin: 521 h.Write([]byte{3}) 522 binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx)) 523 h.Write(tmp[:4]) 524 case goobj.PkgIdxSelf: 525 io.WriteString(h, w.pkgpath) 526 binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx)) 527 h.Write(tmp[:4]) 528 default: 529 io.WriteString(h, rs.Pkg) 530 binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx)) 531 h.Write(tmp[:4]) 532 } 533 } 534 var b goobj.HashType 535 copy(b[:], h.Sum(nil)) 536 return b 537 } 538 539 func makeSymRef(s *LSym) goobj.SymRef { 540 if s == nil { 541 return goobj.SymRef{} 542 } 543 if s.PkgIdx == 0 || !s.Indexed() { 544 fmt.Printf("unindexed symbol reference: %v\n", s) 545 panic("unindexed symbol reference") 546 } 547 return goobj.SymRef{PkgIdx: uint32(s.PkgIdx), SymIdx: uint32(s.SymIdx)} 548 } 549 550 func (w *writer) Reloc(r *Reloc) { 551 o := &w.tmpReloc 552 o.SetOff(r.Off) 553 o.SetSiz(r.Siz) 554 o.SetType(uint16(r.Type)) 555 o.SetAdd(r.Add) 556 o.SetSym(makeSymRef(r.Sym)) 557 o.Write(w.Writer) 558 } 559 560 func (w *writer) aux1(typ uint8, rs *LSym) { 561 o := &w.tmpAux 562 o.SetType(typ) 563 o.SetSym(makeSymRef(rs)) 564 o.Write(w.Writer) 565 } 566 567 func (w *writer) Aux(s *LSym) { 568 if s.Gotype != nil { 569 w.aux1(goobj.AuxGotype, s.Gotype) 570 } 571 if fn := s.Func(); fn != nil { 572 w.aux1(goobj.AuxFuncInfo, fn.FuncInfoSym) 573 574 for _, d := range fn.Pcln.Funcdata { 575 w.aux1(goobj.AuxFuncdata, d) 576 } 577 578 if fn.dwarfInfoSym != nil && fn.dwarfInfoSym.Size != 0 { 579 w.aux1(goobj.AuxDwarfInfo, fn.dwarfInfoSym) 580 } 581 if fn.dwarfLocSym != nil && fn.dwarfLocSym.Size != 0 { 582 w.aux1(goobj.AuxDwarfLoc, fn.dwarfLocSym) 583 } 584 if fn.dwarfRangesSym != nil && fn.dwarfRangesSym.Size != 0 { 585 w.aux1(goobj.AuxDwarfRanges, fn.dwarfRangesSym) 586 } 587 if fn.dwarfDebugLinesSym != nil && fn.dwarfDebugLinesSym.Size != 0 { 588 w.aux1(goobj.AuxDwarfLines, fn.dwarfDebugLinesSym) 589 } 590 if fn.Pcln.Pcsp != nil && fn.Pcln.Pcsp.Size != 0 { 591 w.aux1(goobj.AuxPcsp, fn.Pcln.Pcsp) 592 } 593 if fn.Pcln.Pcfile != nil && fn.Pcln.Pcfile.Size != 0 { 594 w.aux1(goobj.AuxPcfile, fn.Pcln.Pcfile) 595 } 596 if fn.Pcln.Pcline != nil && fn.Pcln.Pcline.Size != 0 { 597 w.aux1(goobj.AuxPcline, fn.Pcln.Pcline) 598 } 599 if fn.Pcln.Pcinline != nil && fn.Pcln.Pcinline.Size != 0 { 600 w.aux1(goobj.AuxPcinline, fn.Pcln.Pcinline) 601 } 602 for _, pcSym := range fn.Pcln.Pcdata { 603 w.aux1(goobj.AuxPcdata, pcSym) 604 } 605 606 } 607 } 608 609 // Emits flags of referenced indexed symbols. 610 func (w *writer) refFlags() { 611 seen := make(map[*LSym]bool) 612 w.ctxt.traverseSyms(traverseRefs, func(rs *LSym) { // only traverse refs, not auxs, as tools don't need auxs 613 switch rs.PkgIdx { 614 case goobj.PkgIdxNone, goobj.PkgIdxHashed64, goobj.PkgIdxHashed, goobj.PkgIdxBuiltin, goobj.PkgIdxSelf: // not an external indexed reference 615 return 616 case goobj.PkgIdxInvalid: 617 panic("unindexed symbol reference") 618 } 619 if seen[rs] { 620 return 621 } 622 seen[rs] = true 623 symref := makeSymRef(rs) 624 flag2 := uint8(0) 625 if rs.UsedInIface() { 626 flag2 |= goobj.SymFlagUsedInIface 627 } 628 if flag2 == 0 { 629 return // no need to write zero flags 630 } 631 o := &w.tmpRefFlags 632 o.SetSym(symref) 633 o.SetFlag2(flag2) 634 o.Write(w.Writer) 635 }) 636 } 637 638 // Emits names of referenced indexed symbols, used by tools (objdump, nm) 639 // only. 640 func (w *writer) refNames() { 641 if w.ctxt.Flag_noRefName { 642 return 643 } 644 seen := make(map[*LSym]bool) 645 w.ctxt.traverseSyms(traverseRefs, func(rs *LSym) { // only traverse refs, not auxs, as tools don't need auxs 646 switch rs.PkgIdx { 647 case goobj.PkgIdxNone, goobj.PkgIdxHashed64, goobj.PkgIdxHashed, goobj.PkgIdxBuiltin, goobj.PkgIdxSelf: // not an external indexed reference 648 return 649 case goobj.PkgIdxInvalid: 650 panic("unindexed symbol reference") 651 } 652 if seen[rs] { 653 return 654 } 655 seen[rs] = true 656 symref := makeSymRef(rs) 657 o := &w.tmpRefName 658 o.SetSym(symref) 659 o.SetName(rs.Name, w.Writer) 660 o.Write(w.Writer) 661 }) 662 // TODO: output in sorted order? 663 // Currently tools (cmd/internal/goobj package) doesn't use mmap, 664 // and it just read it into a map in memory upfront. If it uses 665 // mmap, if the output is sorted, it probably could avoid reading 666 // into memory and just do lookups in the mmap'd object file. 667 } 668 669 // return the number of aux symbols s have. 670 func nAuxSym(s *LSym) int { 671 n := 0 672 if s.Gotype != nil { 673 n++ 674 } 675 if fn := s.Func(); fn != nil { 676 // FuncInfo is an aux symbol, each Funcdata is an aux symbol 677 n += 1 + len(fn.Pcln.Funcdata) 678 if fn.dwarfInfoSym != nil && fn.dwarfInfoSym.Size != 0 { 679 n++ 680 } 681 if fn.dwarfLocSym != nil && fn.dwarfLocSym.Size != 0 { 682 n++ 683 } 684 if fn.dwarfRangesSym != nil && fn.dwarfRangesSym.Size != 0 { 685 n++ 686 } 687 if fn.dwarfDebugLinesSym != nil && fn.dwarfDebugLinesSym.Size != 0 { 688 n++ 689 } 690 if fn.Pcln.Pcsp != nil && fn.Pcln.Pcsp.Size != 0 { 691 n++ 692 } 693 if fn.Pcln.Pcfile != nil && fn.Pcln.Pcfile.Size != 0 { 694 n++ 695 } 696 if fn.Pcln.Pcline != nil && fn.Pcln.Pcline.Size != 0 { 697 n++ 698 } 699 if fn.Pcln.Pcinline != nil && fn.Pcln.Pcinline.Size != 0 { 700 n++ 701 } 702 n += len(fn.Pcln.Pcdata) 703 } 704 return n 705 } 706 707 // generate symbols for FuncInfo. 708 func genFuncInfoSyms(ctxt *Link) { 709 infosyms := make([]*LSym, 0, len(ctxt.Text)) 710 var b bytes.Buffer 711 symidx := int32(len(ctxt.defs)) 712 for _, s := range ctxt.Text { 713 fn := s.Func() 714 if fn == nil { 715 continue 716 } 717 o := goobj.FuncInfo{ 718 Args: uint32(fn.Args), 719 Locals: uint32(fn.Locals), 720 FuncID: fn.FuncID, 721 FuncFlag: fn.FuncFlag, 722 StartLine: fn.StartLine, 723 } 724 pc := &fn.Pcln 725 i := 0 726 o.File = make([]goobj.CUFileIndex, len(pc.UsedFiles)) 727 for f := range pc.UsedFiles { 728 o.File[i] = f 729 i++ 730 } 731 sort.Slice(o.File, func(i, j int) bool { return o.File[i] < o.File[j] }) 732 o.InlTree = make([]goobj.InlTreeNode, len(pc.InlTree.nodes)) 733 for i, inl := range pc.InlTree.nodes { 734 f, l := ctxt.getFileIndexAndLine(inl.Pos) 735 o.InlTree[i] = goobj.InlTreeNode{ 736 Parent: int32(inl.Parent), 737 File: goobj.CUFileIndex(f), 738 Line: l, 739 Func: makeSymRef(inl.Func), 740 ParentPC: inl.ParentPC, 741 } 742 } 743 744 o.Write(&b) 745 p := b.Bytes() 746 isym := &LSym{ 747 Type: objabi.SDATA, // for now, I don't think it matters 748 PkgIdx: goobj.PkgIdxSelf, 749 SymIdx: symidx, 750 P: append([]byte(nil), p...), 751 Size: int64(len(p)), 752 } 753 isym.Set(AttrIndexed, true) 754 symidx++ 755 infosyms = append(infosyms, isym) 756 fn.FuncInfoSym = isym 757 b.Reset() 758 759 dwsyms := []*LSym{fn.dwarfRangesSym, fn.dwarfLocSym, fn.dwarfDebugLinesSym, fn.dwarfInfoSym} 760 for _, s := range dwsyms { 761 if s == nil || s.Size == 0 { 762 continue 763 } 764 s.PkgIdx = goobj.PkgIdxSelf 765 s.SymIdx = symidx 766 s.Set(AttrIndexed, true) 767 symidx++ 768 infosyms = append(infosyms, s) 769 } 770 } 771 ctxt.defs = append(ctxt.defs, infosyms...) 772 } 773 774 func writeAuxSymDebug(ctxt *Link, par *LSym, aux *LSym) { 775 // Most aux symbols (ex: funcdata) are not interesting-- 776 // pick out just the DWARF ones for now. 777 if aux.Type != objabi.SDWARFLOC && 778 aux.Type != objabi.SDWARFFCN && 779 aux.Type != objabi.SDWARFABSFCN && 780 aux.Type != objabi.SDWARFLINES && 781 aux.Type != objabi.SDWARFRANGE { 782 return 783 } 784 ctxt.writeSymDebugNamed(aux, "aux for "+par.Name) 785 } 786 787 func debugAsmEmit(ctxt *Link) { 788 if ctxt.Debugasm > 0 { 789 ctxt.traverseSyms(traverseDefs, ctxt.writeSymDebug) 790 if ctxt.Debugasm > 1 { 791 fn := func(par *LSym, aux *LSym) { 792 writeAuxSymDebug(ctxt, par, aux) 793 } 794 ctxt.traverseAuxSyms(traverseAux, fn) 795 } 796 } 797 } 798 799 func (ctxt *Link) writeSymDebug(s *LSym) { 800 ctxt.writeSymDebugNamed(s, s.Name) 801 } 802 803 func (ctxt *Link) writeSymDebugNamed(s *LSym, name string) { 804 ver := "" 805 if ctxt.Debugasm > 1 { 806 ver = fmt.Sprintf("<%d>", s.ABI()) 807 } 808 fmt.Fprintf(ctxt.Bso, "%s%s ", name, ver) 809 if s.Type != 0 { 810 fmt.Fprintf(ctxt.Bso, "%v ", s.Type) 811 } 812 if s.Static() { 813 fmt.Fprint(ctxt.Bso, "static ") 814 } 815 if s.DuplicateOK() { 816 fmt.Fprintf(ctxt.Bso, "dupok ") 817 } 818 if s.CFunc() { 819 fmt.Fprintf(ctxt.Bso, "cfunc ") 820 } 821 if s.NoSplit() { 822 fmt.Fprintf(ctxt.Bso, "nosplit ") 823 } 824 if s.Func() != nil && s.Func().FuncFlag&objabi.FuncFlag_TOPFRAME != 0 { 825 fmt.Fprintf(ctxt.Bso, "topframe ") 826 } 827 if s.Func() != nil && s.Func().FuncFlag&objabi.FuncFlag_ASM != 0 { 828 fmt.Fprintf(ctxt.Bso, "asm ") 829 } 830 fmt.Fprintf(ctxt.Bso, "size=%d", s.Size) 831 if s.Type == objabi.STEXT { 832 fn := s.Func() 833 fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x funcid=%#x align=%#x", uint64(fn.Args), uint64(fn.Locals), uint64(fn.FuncID), uint64(fn.Align)) 834 if s.Leaf() { 835 fmt.Fprintf(ctxt.Bso, " leaf") 836 } 837 } 838 fmt.Fprintf(ctxt.Bso, "\n") 839 if s.Type == objabi.STEXT { 840 for p := s.Func().Text; p != nil; p = p.Link { 841 fmt.Fprintf(ctxt.Bso, "\t%#04x ", uint(int(p.Pc))) 842 if ctxt.Debugasm > 1 { 843 io.WriteString(ctxt.Bso, p.String()) 844 } else { 845 p.InnermostString(ctxt.Bso) 846 } 847 fmt.Fprintln(ctxt.Bso) 848 } 849 } 850 for i := 0; i < len(s.P); i += 16 { 851 fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i)) 852 j := i 853 for ; j < i+16 && j < len(s.P); j++ { 854 fmt.Fprintf(ctxt.Bso, " %02x", s.P[j]) 855 } 856 for ; j < i+16; j++ { 857 fmt.Fprintf(ctxt.Bso, " ") 858 } 859 fmt.Fprintf(ctxt.Bso, " ") 860 for j = i; j < i+16 && j < len(s.P); j++ { 861 c := int(s.P[j]) 862 b := byte('.') 863 if ' ' <= c && c <= 0x7e { 864 b = byte(c) 865 } 866 ctxt.Bso.WriteByte(b) 867 } 868 869 fmt.Fprintf(ctxt.Bso, "\n") 870 } 871 872 sort.Sort(relocByOff(s.R)) // generate stable output 873 for _, r := range s.R { 874 name := "" 875 ver := "" 876 if r.Sym != nil { 877 name = r.Sym.Name 878 if ctxt.Debugasm > 1 { 879 ver = fmt.Sprintf("<%d>", r.Sym.ABI()) 880 } 881 } else if r.Type == objabi.R_TLS_LE { 882 name = "TLS" 883 } 884 if ctxt.Arch.InFamily(sys.ARM, sys.PPC64) { 885 fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s%s+%x\n", int(r.Off), r.Siz, r.Type, name, ver, uint64(r.Add)) 886 } else { 887 fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s%s+%d\n", int(r.Off), r.Siz, r.Type, name, ver, r.Add) 888 } 889 } 890 } 891 892 // relocByOff sorts relocations by their offsets. 893 type relocByOff []Reloc 894 895 func (x relocByOff) Len() int { return len(x) } 896 func (x relocByOff) Less(i, j int) bool { return x[i].Off < x[j].Off } 897 func (x relocByOff) Swap(i, j int) { x[i], x[j] = x[j], x[i] }