1// Copyright 2019 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// This package defines the Go object file format, and provide "low-level" functions 6// for reading and writing object files. 7 8// The object file is understood by the compiler, assembler, linker, and tools. They 9// have "high level" code that operates on object files, handling application-specific 10// logics, and use this package for the actual reading and writing. Specifically, the 11// code below: 12// 13// - cmd/internal/obj/objfile.go (used by cmd/asm and cmd/compile) 14// - cmd/internal/objfile/goobj.go (used cmd/nm, cmd/objdump) 15// - cmd/link/internal/loader package (used by cmd/link) 16// 17// If the object file format changes, they may (or may not) need to change. 18 19package goobj 20 21import ( 22 "cmd/internal/bio" 23 "encoding/binary" 24 "errors" 25 "fmt" 26 "unsafe" 27) 28 29// New object file format. 30// 31// Header struct { 32// Magic [...]byte // "\x00go120ld" 33// Fingerprint [8]byte 34// Flags uint32 35// Offsets [...]uint32 // byte offset of each block below 36// } 37// 38// Strings [...]struct { 39// Data [...]byte 40// } 41// 42// Autolib [...]struct { // imported packages (for file loading) 43// Pkg string 44// Fingerprint [8]byte 45// } 46// 47// PkgIndex [...]string // referenced packages by index 48// 49// Files [...]string 50// 51// SymbolDefs [...]struct { 52// Name string 53// ABI uint16 54// Type uint8 55// Flag uint8 56// Flag2 uint8 57// Size uint32 58// } 59// Hashed64Defs [...]struct { // short hashed (content-addressable) symbol definitions 60// ... // same as SymbolDefs 61// } 62// HashedDefs [...]struct { // hashed (content-addressable) symbol definitions 63// ... // same as SymbolDefs 64// } 65// NonPkgDefs [...]struct { // non-pkg symbol definitions 66// ... // same as SymbolDefs 67// } 68// NonPkgRefs [...]struct { // non-pkg symbol references 69// ... // same as SymbolDefs 70// } 71// 72// RefFlags [...]struct { // referenced symbol flags 73// Sym symRef 74// Flag uint8 75// Flag2 uint8 76// } 77// 78// Hash64 [...][8]byte 79// Hash [...][N]byte 80// 81// RelocIndex [...]uint32 // index to Relocs 82// AuxIndex [...]uint32 // index to Aux 83// DataIndex [...]uint32 // offset to Data 84// 85// Relocs [...]struct { 86// Off int32 87// Size uint8 88// Type uint16 89// Add int64 90// Sym symRef 91// } 92// 93// Aux [...]struct { 94// Type uint8 95// Sym symRef 96// } 97// 98// Data [...]byte 99// 100// // blocks only used by tools (objdump, nm) 101// 102// RefNames [...]struct { // referenced symbol names 103// Sym symRef 104// Name string 105// // TODO: include ABI version as well? 106// } 107// 108// string is encoded as is a uint32 length followed by a uint32 offset 109// that points to the corresponding string bytes. 110// 111// symRef is struct { PkgIdx, SymIdx uint32 }. 112// 113// Slice type (e.g. []symRef) is encoded as a length prefix (uint32) 114// followed by that number of elements. 115// 116// The types below correspond to the encoded data structure in the 117// object file. 118 119// Symbol indexing. 120// 121// Each symbol is referenced with a pair of indices, { PkgIdx, SymIdx }, 122// as the symRef struct above. 123// 124// PkgIdx is either a predeclared index (see PkgIdxNone below) or 125// an index of an imported package. For the latter case, PkgIdx is the 126// index of the package in the PkgIndex array. 0 is an invalid index. 127// 128// SymIdx is the index of the symbol in the given package. 129// - If PkgIdx is PkgIdxSelf, SymIdx is the index of the symbol in the 130// SymbolDefs array. 131// - If PkgIdx is PkgIdxHashed64, SymIdx is the index of the symbol in the 132// Hashed64Defs array. 133// - If PkgIdx is PkgIdxHashed, SymIdx is the index of the symbol in the 134// HashedDefs array. 135// - If PkgIdx is PkgIdxNone, SymIdx is the index of the symbol in the 136// NonPkgDefs array (could naturally overflow to NonPkgRefs array). 137// - Otherwise, SymIdx is the index of the symbol in some other package's 138// SymbolDefs array. 139// 140// {0, 0} represents a nil symbol. Otherwise PkgIdx should not be 0. 141// 142// Hash contains the content hashes of content-addressable symbols, of 143// which PkgIdx is PkgIdxHashed, in the same order of HashedDefs array. 144// Hash64 is similar, for PkgIdxHashed64 symbols. 145// 146// RelocIndex, AuxIndex, and DataIndex contains indices/offsets to 147// Relocs/Aux/Data blocks, one element per symbol, first for all the 148// defined symbols, then all the defined hashed and non-package symbols, 149// in the same order of SymbolDefs/Hashed64Defs/HashedDefs/NonPkgDefs 150// arrays. For N total defined symbols, the array is of length N+1. The 151// last element is the total number of relocations (aux symbols, data 152// blocks, etc.). 153// 154// They can be accessed by index. For the i-th symbol, its relocations 155// are the RelocIndex[i]-th (inclusive) to RelocIndex[i+1]-th (exclusive) 156// elements in the Relocs array. Aux/Data are likewise. (The index is 157// 0-based.) 158 159// Auxiliary symbols. 160// 161// Each symbol may (or may not) be associated with a number of auxiliary 162// symbols. They are described in the Aux block. See Aux struct below. 163// Currently a symbol's Gotype, FuncInfo, and associated DWARF symbols 164// are auxiliary symbols. 165 166const stringRefSize = 8 // two uint32s 167 168type FingerprintType [8]byte 169 170func (fp FingerprintType) IsZero() bool { return fp == FingerprintType{} } 171 172// Package Index. 173const ( 174 PkgIdxNone = (1<<31 - 1) - iota // Non-package symbols 175 PkgIdxHashed64 // Short hashed (content-addressable) symbols 176 PkgIdxHashed // Hashed (content-addressable) symbols 177 PkgIdxBuiltin // Predefined runtime symbols (ex: runtime.newobject) 178 PkgIdxSelf // Symbols defined in the current package 179 PkgIdxSpecial = PkgIdxSelf // Indices above it has special meanings 180 PkgIdxInvalid = 0 181 // The index of other referenced packages starts from 1. 182) 183 184// Blocks 185const ( 186 BlkAutolib = iota 187 BlkPkgIdx 188 BlkFile 189 BlkSymdef 190 BlkHashed64def 191 BlkHasheddef 192 BlkNonpkgdef 193 BlkNonpkgref 194 BlkRefFlags 195 BlkHash64 196 BlkHash 197 BlkRelocIdx 198 BlkAuxIdx 199 BlkDataIdx 200 BlkReloc 201 BlkAux 202 BlkData 203 BlkRefName 204 BlkEnd 205 NBlk 206) 207 208// File header. 209// TODO: probably no need to export this. 210type Header struct { 211 Magic string 212 Fingerprint FingerprintType 213 Flags uint32 214 Offsets [NBlk]uint32 215} 216 217const Magic = "\x00go120ld" 218 219func (h *Header) Write(w *Writer) { 220 w.RawString(h.Magic) 221 w.Bytes(h.Fingerprint[:]) 222 w.Uint32(h.Flags) 223 for _, x := range h.Offsets { 224 w.Uint32(x) 225 } 226} 227 228func (h *Header) Read(r *Reader) error { 229 b := r.BytesAt(0, len(Magic)) 230 h.Magic = string(b) 231 if h.Magic != Magic { 232 return errors.New("wrong magic, not a Go object file") 233 } 234 off := uint32(len(h.Magic)) 235 copy(h.Fingerprint[:], r.BytesAt(off, len(h.Fingerprint))) 236 off += 8 237 h.Flags = r.uint32At(off) 238 off += 4 239 for i := range h.Offsets { 240 h.Offsets[i] = r.uint32At(off) 241 off += 4 242 } 243 return nil 244} 245 246func (h *Header) Size() int { 247 return len(h.Magic) + len(h.Fingerprint) + 4 + 4*len(h.Offsets) 248} 249 250// Autolib 251type ImportedPkg struct { 252 Pkg string 253 Fingerprint FingerprintType 254} 255 256const importedPkgSize = stringRefSize + 8 257 258func (p *ImportedPkg) Write(w *Writer) { 259 w.StringRef(p.Pkg) 260 w.Bytes(p.Fingerprint[:]) 261} 262 263// Symbol definition. 264// 265// Serialized format: 266// 267// Sym struct { 268// Name string 269// ABI uint16 270// Type uint8 271// Flag uint8 272// Flag2 uint8 273// Siz uint32 274// Align uint32 275// } 276type Sym [SymSize]byte 277 278const SymSize = stringRefSize + 2 + 1 + 1 + 1 + 4 + 4 279 280const SymABIstatic = ^uint16(0) 281 282const ( 283 ObjFlagShared = 1 << iota // this object is built with -shared 284 _ // was ObjFlagNeedNameExpansion 285 ObjFlagFromAssembly // object is from asm src, not go 286 ObjFlagUnlinkable // unlinkable package (linker will emit an error) 287 ObjFlagStd // standard library package 288) 289 290// Sym.Flag 291const ( 292 SymFlagDupok = 1 << iota 293 SymFlagLocal 294 SymFlagTypelink 295 SymFlagLeaf 296 SymFlagNoSplit 297 SymFlagReflectMethod 298 SymFlagGoType 299) 300 301// Sym.Flag2 302const ( 303 SymFlagUsedInIface = 1 << iota 304 SymFlagItab 305 SymFlagDict 306 SymFlagPkgInit 307 SymFlagLinkname 308 SymFlagABIWrapper 309) 310 311// Returns the length of the name of the symbol. 312func (s *Sym) NameLen(r *Reader) int { 313 return int(binary.LittleEndian.Uint32(s[:])) 314} 315 316func (s *Sym) Name(r *Reader) string { 317 len := binary.LittleEndian.Uint32(s[:]) 318 off := binary.LittleEndian.Uint32(s[4:]) 319 return r.StringAt(off, len) 320} 321 322func (s *Sym) ABI() uint16 { return binary.LittleEndian.Uint16(s[8:]) } 323func (s *Sym) Type() uint8 { return s[10] } 324func (s *Sym) Flag() uint8 { return s[11] } 325func (s *Sym) Flag2() uint8 { return s[12] } 326func (s *Sym) Siz() uint32 { return binary.LittleEndian.Uint32(s[13:]) } 327func (s *Sym) Align() uint32 { return binary.LittleEndian.Uint32(s[17:]) } 328 329func (s *Sym) Dupok() bool { return s.Flag()&SymFlagDupok != 0 } 330func (s *Sym) Local() bool { return s.Flag()&SymFlagLocal != 0 } 331func (s *Sym) Typelink() bool { return s.Flag()&SymFlagTypelink != 0 } 332func (s *Sym) Leaf() bool { return s.Flag()&SymFlagLeaf != 0 } 333func (s *Sym) NoSplit() bool { return s.Flag()&SymFlagNoSplit != 0 } 334func (s *Sym) ReflectMethod() bool { return s.Flag()&SymFlagReflectMethod != 0 } 335func (s *Sym) IsGoType() bool { return s.Flag()&SymFlagGoType != 0 } 336func (s *Sym) UsedInIface() bool { return s.Flag2()&SymFlagUsedInIface != 0 } 337func (s *Sym) IsItab() bool { return s.Flag2()&SymFlagItab != 0 } 338func (s *Sym) IsDict() bool { return s.Flag2()&SymFlagDict != 0 } 339func (s *Sym) IsPkgInit() bool { return s.Flag2()&SymFlagPkgInit != 0 } 340func (s *Sym) IsLinkname() bool { return s.Flag2()&SymFlagLinkname != 0 } 341func (s *Sym) ABIWrapper() bool { return s.Flag2()&SymFlagABIWrapper != 0 } 342 343func (s *Sym) SetName(x string, w *Writer) { 344 binary.LittleEndian.PutUint32(s[:], uint32(len(x))) 345 binary.LittleEndian.PutUint32(s[4:], w.stringOff(x)) 346} 347 348func (s *Sym) SetABI(x uint16) { binary.LittleEndian.PutUint16(s[8:], x) } 349func (s *Sym) SetType(x uint8) { s[10] = x } 350func (s *Sym) SetFlag(x uint8) { s[11] = x } 351func (s *Sym) SetFlag2(x uint8) { s[12] = x } 352func (s *Sym) SetSiz(x uint32) { binary.LittleEndian.PutUint32(s[13:], x) } 353func (s *Sym) SetAlign(x uint32) { binary.LittleEndian.PutUint32(s[17:], x) } 354 355func (s *Sym) Write(w *Writer) { w.Bytes(s[:]) } 356 357// for testing 358func (s *Sym) fromBytes(b []byte) { copy(s[:], b) } 359 360// Symbol reference. 361type SymRef struct { 362 PkgIdx uint32 363 SymIdx uint32 364} 365 366func (s SymRef) IsZero() bool { return s == SymRef{} } 367 368// Hash64 369type Hash64Type [Hash64Size]byte 370 371const Hash64Size = 8 372 373// Hash 374type HashType [HashSize]byte 375 376const HashSize = 16 // truncated SHA256 377 378// Relocation. 379// 380// Serialized format: 381// 382// Reloc struct { 383// Off int32 384// Siz uint8 385// Type uint16 386// Add int64 387// Sym SymRef 388// } 389type Reloc [RelocSize]byte 390 391const RelocSize = 4 + 1 + 2 + 8 + 8 392 393func (r *Reloc) Off() int32 { return int32(binary.LittleEndian.Uint32(r[:])) } 394func (r *Reloc) Siz() uint8 { return r[4] } 395func (r *Reloc) Type() uint16 { return binary.LittleEndian.Uint16(r[5:]) } 396func (r *Reloc) Add() int64 { return int64(binary.LittleEndian.Uint64(r[7:])) } 397func (r *Reloc) Sym() SymRef { 398 return SymRef{binary.LittleEndian.Uint32(r[15:]), binary.LittleEndian.Uint32(r[19:])} 399} 400 401func (r *Reloc) SetOff(x int32) { binary.LittleEndian.PutUint32(r[:], uint32(x)) } 402func (r *Reloc) SetSiz(x uint8) { r[4] = x } 403func (r *Reloc) SetType(x uint16) { binary.LittleEndian.PutUint16(r[5:], x) } 404func (r *Reloc) SetAdd(x int64) { binary.LittleEndian.PutUint64(r[7:], uint64(x)) } 405func (r *Reloc) SetSym(x SymRef) { 406 binary.LittleEndian.PutUint32(r[15:], x.PkgIdx) 407 binary.LittleEndian.PutUint32(r[19:], x.SymIdx) 408} 409 410func (r *Reloc) Set(off int32, size uint8, typ uint16, add int64, sym SymRef) { 411 r.SetOff(off) 412 r.SetSiz(size) 413 r.SetType(typ) 414 r.SetAdd(add) 415 r.SetSym(sym) 416} 417 418func (r *Reloc) Write(w *Writer) { w.Bytes(r[:]) } 419 420// for testing 421func (r *Reloc) fromBytes(b []byte) { copy(r[:], b) } 422 423// Aux symbol info. 424// 425// Serialized format: 426// 427// Aux struct { 428// Type uint8 429// Sym SymRef 430// } 431type Aux [AuxSize]byte 432 433const AuxSize = 1 + 8 434 435// Aux Type 436const ( 437 AuxGotype = iota 438 AuxFuncInfo 439 AuxFuncdata 440 AuxDwarfInfo 441 AuxDwarfLoc 442 AuxDwarfRanges 443 AuxDwarfLines 444 AuxPcsp 445 AuxPcfile 446 AuxPcline 447 AuxPcinline 448 AuxPcdata 449 AuxWasmImport 450 AuxSehUnwindInfo 451) 452 453func (a *Aux) Type() uint8 { return a[0] } 454func (a *Aux) Sym() SymRef { 455 return SymRef{binary.LittleEndian.Uint32(a[1:]), binary.LittleEndian.Uint32(a[5:])} 456} 457 458func (a *Aux) SetType(x uint8) { a[0] = x } 459func (a *Aux) SetSym(x SymRef) { 460 binary.LittleEndian.PutUint32(a[1:], x.PkgIdx) 461 binary.LittleEndian.PutUint32(a[5:], x.SymIdx) 462} 463 464func (a *Aux) Write(w *Writer) { w.Bytes(a[:]) } 465 466// for testing 467func (a *Aux) fromBytes(b []byte) { copy(a[:], b) } 468 469// Referenced symbol flags. 470// 471// Serialized format: 472// 473// RefFlags struct { 474// Sym symRef 475// Flag uint8 476// Flag2 uint8 477// } 478type RefFlags [RefFlagsSize]byte 479 480const RefFlagsSize = 8 + 1 + 1 481 482func (r *RefFlags) Sym() SymRef { 483 return SymRef{binary.LittleEndian.Uint32(r[:]), binary.LittleEndian.Uint32(r[4:])} 484} 485func (r *RefFlags) Flag() uint8 { return r[8] } 486func (r *RefFlags) Flag2() uint8 { return r[9] } 487 488func (r *RefFlags) SetSym(x SymRef) { 489 binary.LittleEndian.PutUint32(r[:], x.PkgIdx) 490 binary.LittleEndian.PutUint32(r[4:], x.SymIdx) 491} 492func (r *RefFlags) SetFlag(x uint8) { r[8] = x } 493func (r *RefFlags) SetFlag2(x uint8) { r[9] = x } 494 495func (r *RefFlags) Write(w *Writer) { w.Bytes(r[:]) } 496 497// Used to construct an artificially large array type when reading an 498// item from the object file relocs section or aux sym section (needs 499// to work on 32-bit as well as 64-bit). See issue 41621. 500const huge = (1<<31 - 1) / RelocSize 501 502// Referenced symbol name. 503// 504// Serialized format: 505// 506// RefName struct { 507// Sym symRef 508// Name string 509// } 510type RefName [RefNameSize]byte 511 512const RefNameSize = 8 + stringRefSize 513 514func (n *RefName) Sym() SymRef { 515 return SymRef{binary.LittleEndian.Uint32(n[:]), binary.LittleEndian.Uint32(n[4:])} 516} 517func (n *RefName) Name(r *Reader) string { 518 len := binary.LittleEndian.Uint32(n[8:]) 519 off := binary.LittleEndian.Uint32(n[12:]) 520 return r.StringAt(off, len) 521} 522 523func (n *RefName) SetSym(x SymRef) { 524 binary.LittleEndian.PutUint32(n[:], x.PkgIdx) 525 binary.LittleEndian.PutUint32(n[4:], x.SymIdx) 526} 527func (n *RefName) SetName(x string, w *Writer) { 528 binary.LittleEndian.PutUint32(n[8:], uint32(len(x))) 529 binary.LittleEndian.PutUint32(n[12:], w.stringOff(x)) 530} 531 532func (n *RefName) Write(w *Writer) { w.Bytes(n[:]) } 533 534type Writer struct { 535 wr *bio.Writer 536 stringMap map[string]uint32 537 off uint32 // running offset 538 539 b [8]byte // scratch space for writing bytes 540} 541 542func NewWriter(wr *bio.Writer) *Writer { 543 return &Writer{wr: wr, stringMap: make(map[string]uint32)} 544} 545 546func (w *Writer) AddString(s string) { 547 if _, ok := w.stringMap[s]; ok { 548 return 549 } 550 w.stringMap[s] = w.off 551 w.RawString(s) 552} 553 554func (w *Writer) stringOff(s string) uint32 { 555 off, ok := w.stringMap[s] 556 if !ok { 557 panic(fmt.Sprintf("writeStringRef: string not added: %q", s)) 558 } 559 return off 560} 561 562func (w *Writer) StringRef(s string) { 563 w.Uint32(uint32(len(s))) 564 w.Uint32(w.stringOff(s)) 565} 566 567func (w *Writer) RawString(s string) { 568 w.wr.WriteString(s) 569 w.off += uint32(len(s)) 570} 571 572func (w *Writer) Bytes(s []byte) { 573 w.wr.Write(s) 574 w.off += uint32(len(s)) 575} 576 577func (w *Writer) Uint64(x uint64) { 578 binary.LittleEndian.PutUint64(w.b[:], x) 579 w.wr.Write(w.b[:]) 580 w.off += 8 581} 582 583func (w *Writer) Uint32(x uint32) { 584 binary.LittleEndian.PutUint32(w.b[:4], x) 585 w.wr.Write(w.b[:4]) 586 w.off += 4 587} 588 589func (w *Writer) Uint16(x uint16) { 590 binary.LittleEndian.PutUint16(w.b[:2], x) 591 w.wr.Write(w.b[:2]) 592 w.off += 2 593} 594 595func (w *Writer) Uint8(x uint8) { 596 w.wr.WriteByte(x) 597 w.off++ 598} 599 600func (w *Writer) Offset() uint32 { 601 return w.off 602} 603 604type Reader struct { 605 b []byte // mmapped bytes, if not nil 606 readonly bool // whether b is backed with read-only memory 607 608 start uint32 609 h Header // keep block offsets 610} 611 612func NewReaderFromBytes(b []byte, readonly bool) *Reader { 613 r := &Reader{b: b, readonly: readonly, start: 0} 614 err := r.h.Read(r) 615 if err != nil { 616 return nil 617 } 618 return r 619} 620 621func (r *Reader) BytesAt(off uint32, len int) []byte { 622 if len == 0 { 623 return nil 624 } 625 end := int(off) + len 626 return r.b[int(off):end:end] 627} 628 629func (r *Reader) uint64At(off uint32) uint64 { 630 b := r.BytesAt(off, 8) 631 return binary.LittleEndian.Uint64(b) 632} 633 634func (r *Reader) int64At(off uint32) int64 { 635 return int64(r.uint64At(off)) 636} 637 638func (r *Reader) uint32At(off uint32) uint32 { 639 b := r.BytesAt(off, 4) 640 return binary.LittleEndian.Uint32(b) 641} 642 643func (r *Reader) int32At(off uint32) int32 { 644 return int32(r.uint32At(off)) 645} 646 647func (r *Reader) uint16At(off uint32) uint16 { 648 b := r.BytesAt(off, 2) 649 return binary.LittleEndian.Uint16(b) 650} 651 652func (r *Reader) uint8At(off uint32) uint8 { 653 b := r.BytesAt(off, 1) 654 return b[0] 655} 656 657func (r *Reader) StringAt(off uint32, len uint32) string { 658 b := r.b[off : off+len] 659 if r.readonly { 660 return toString(b) // backed by RO memory, ok to make unsafe string 661 } 662 return string(b) 663} 664 665func toString(b []byte) string { 666 if len(b) == 0 { 667 return "" 668 } 669 return unsafe.String(&b[0], len(b)) 670} 671 672func (r *Reader) StringRef(off uint32) string { 673 l := r.uint32At(off) 674 return r.StringAt(r.uint32At(off+4), l) 675} 676 677func (r *Reader) Fingerprint() FingerprintType { 678 return r.h.Fingerprint 679} 680 681func (r *Reader) Autolib() []ImportedPkg { 682 n := (r.h.Offsets[BlkAutolib+1] - r.h.Offsets[BlkAutolib]) / importedPkgSize 683 s := make([]ImportedPkg, n) 684 off := r.h.Offsets[BlkAutolib] 685 for i := range s { 686 s[i].Pkg = r.StringRef(off) 687 copy(s[i].Fingerprint[:], r.BytesAt(off+stringRefSize, len(s[i].Fingerprint))) 688 off += importedPkgSize 689 } 690 return s 691} 692 693func (r *Reader) Pkglist() []string { 694 n := (r.h.Offsets[BlkPkgIdx+1] - r.h.Offsets[BlkPkgIdx]) / stringRefSize 695 s := make([]string, n) 696 off := r.h.Offsets[BlkPkgIdx] 697 for i := range s { 698 s[i] = r.StringRef(off) 699 off += stringRefSize 700 } 701 return s 702} 703 704func (r *Reader) NPkg() int { 705 return int(r.h.Offsets[BlkPkgIdx+1]-r.h.Offsets[BlkPkgIdx]) / stringRefSize 706} 707 708func (r *Reader) Pkg(i int) string { 709 off := r.h.Offsets[BlkPkgIdx] + uint32(i)*stringRefSize 710 return r.StringRef(off) 711} 712 713func (r *Reader) NFile() int { 714 return int(r.h.Offsets[BlkFile+1]-r.h.Offsets[BlkFile]) / stringRefSize 715} 716 717func (r *Reader) File(i int) string { 718 off := r.h.Offsets[BlkFile] + uint32(i)*stringRefSize 719 return r.StringRef(off) 720} 721 722func (r *Reader) NSym() int { 723 return int(r.h.Offsets[BlkSymdef+1]-r.h.Offsets[BlkSymdef]) / SymSize 724} 725 726func (r *Reader) NHashed64def() int { 727 return int(r.h.Offsets[BlkHashed64def+1]-r.h.Offsets[BlkHashed64def]) / SymSize 728} 729 730func (r *Reader) NHasheddef() int { 731 return int(r.h.Offsets[BlkHasheddef+1]-r.h.Offsets[BlkHasheddef]) / SymSize 732} 733 734func (r *Reader) NNonpkgdef() int { 735 return int(r.h.Offsets[BlkNonpkgdef+1]-r.h.Offsets[BlkNonpkgdef]) / SymSize 736} 737 738func (r *Reader) NNonpkgref() int { 739 return int(r.h.Offsets[BlkNonpkgref+1]-r.h.Offsets[BlkNonpkgref]) / SymSize 740} 741 742// SymOff returns the offset of the i-th symbol. 743func (r *Reader) SymOff(i uint32) uint32 { 744 return r.h.Offsets[BlkSymdef] + uint32(i*SymSize) 745} 746 747// Sym returns a pointer to the i-th symbol. 748func (r *Reader) Sym(i uint32) *Sym { 749 off := r.SymOff(i) 750 return (*Sym)(unsafe.Pointer(&r.b[off])) 751} 752 753// NRefFlags returns the number of referenced symbol flags. 754func (r *Reader) NRefFlags() int { 755 return int(r.h.Offsets[BlkRefFlags+1]-r.h.Offsets[BlkRefFlags]) / RefFlagsSize 756} 757 758// RefFlags returns a pointer to the i-th referenced symbol flags. 759// Note: here i is not a local symbol index, just a counter. 760func (r *Reader) RefFlags(i int) *RefFlags { 761 off := r.h.Offsets[BlkRefFlags] + uint32(i*RefFlagsSize) 762 return (*RefFlags)(unsafe.Pointer(&r.b[off])) 763} 764 765// Hash64 returns the i-th short hashed symbol's hash. 766// Note: here i is the index of short hashed symbols, not all symbols 767// (unlike other accessors). 768func (r *Reader) Hash64(i uint32) uint64 { 769 off := r.h.Offsets[BlkHash64] + uint32(i*Hash64Size) 770 return r.uint64At(off) 771} 772 773// Hash returns a pointer to the i-th hashed symbol's hash. 774// Note: here i is the index of hashed symbols, not all symbols 775// (unlike other accessors). 776func (r *Reader) Hash(i uint32) *HashType { 777 off := r.h.Offsets[BlkHash] + uint32(i*HashSize) 778 return (*HashType)(unsafe.Pointer(&r.b[off])) 779} 780 781// NReloc returns the number of relocations of the i-th symbol. 782func (r *Reader) NReloc(i uint32) int { 783 relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4) 784 return int(r.uint32At(relocIdxOff+4) - r.uint32At(relocIdxOff)) 785} 786 787// RelocOff returns the offset of the j-th relocation of the i-th symbol. 788func (r *Reader) RelocOff(i uint32, j int) uint32 { 789 relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4) 790 relocIdx := r.uint32At(relocIdxOff) 791 return r.h.Offsets[BlkReloc] + (relocIdx+uint32(j))*uint32(RelocSize) 792} 793 794// Reloc returns a pointer to the j-th relocation of the i-th symbol. 795func (r *Reader) Reloc(i uint32, j int) *Reloc { 796 off := r.RelocOff(i, j) 797 return (*Reloc)(unsafe.Pointer(&r.b[off])) 798} 799 800// Relocs returns a pointer to the relocations of the i-th symbol. 801func (r *Reader) Relocs(i uint32) []Reloc { 802 off := r.RelocOff(i, 0) 803 n := r.NReloc(i) 804 return (*[huge]Reloc)(unsafe.Pointer(&r.b[off]))[:n:n] 805} 806 807// NAux returns the number of aux symbols of the i-th symbol. 808func (r *Reader) NAux(i uint32) int { 809 auxIdxOff := r.h.Offsets[BlkAuxIdx] + i*4 810 return int(r.uint32At(auxIdxOff+4) - r.uint32At(auxIdxOff)) 811} 812 813// AuxOff returns the offset of the j-th aux symbol of the i-th symbol. 814func (r *Reader) AuxOff(i uint32, j int) uint32 { 815 auxIdxOff := r.h.Offsets[BlkAuxIdx] + i*4 816 auxIdx := r.uint32At(auxIdxOff) 817 return r.h.Offsets[BlkAux] + (auxIdx+uint32(j))*uint32(AuxSize) 818} 819 820// Aux returns a pointer to the j-th aux symbol of the i-th symbol. 821func (r *Reader) Aux(i uint32, j int) *Aux { 822 off := r.AuxOff(i, j) 823 return (*Aux)(unsafe.Pointer(&r.b[off])) 824} 825 826// Auxs returns the aux symbols of the i-th symbol. 827func (r *Reader) Auxs(i uint32) []Aux { 828 off := r.AuxOff(i, 0) 829 n := r.NAux(i) 830 return (*[huge]Aux)(unsafe.Pointer(&r.b[off]))[:n:n] 831} 832 833// DataOff returns the offset of the i-th symbol's data. 834func (r *Reader) DataOff(i uint32) uint32 { 835 dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4 836 return r.h.Offsets[BlkData] + r.uint32At(dataIdxOff) 837} 838 839// DataSize returns the size of the i-th symbol's data. 840func (r *Reader) DataSize(i uint32) int { 841 dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4 842 return int(r.uint32At(dataIdxOff+4) - r.uint32At(dataIdxOff)) 843} 844 845// Data returns the i-th symbol's data. 846func (r *Reader) Data(i uint32) []byte { 847 dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4 848 base := r.h.Offsets[BlkData] 849 off := r.uint32At(dataIdxOff) 850 end := r.uint32At(dataIdxOff + 4) 851 return r.BytesAt(base+off, int(end-off)) 852} 853 854// DataString returns the i-th symbol's data as a string. 855func (r *Reader) DataString(i uint32) string { 856 dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4 857 base := r.h.Offsets[BlkData] 858 off := r.uint32At(dataIdxOff) 859 end := r.uint32At(dataIdxOff + 4) 860 return r.StringAt(base+off, end-off) 861} 862 863// NRefName returns the number of referenced symbol names. 864func (r *Reader) NRefName() int { 865 return int(r.h.Offsets[BlkRefName+1]-r.h.Offsets[BlkRefName]) / RefNameSize 866} 867 868// RefName returns a pointer to the i-th referenced symbol name. 869// Note: here i is not a local symbol index, just a counter. 870func (r *Reader) RefName(i int) *RefName { 871 off := r.h.Offsets[BlkRefName] + uint32(i*RefNameSize) 872 return (*RefName)(unsafe.Pointer(&r.b[off])) 873} 874 875// ReadOnly returns whether r.BytesAt returns read-only bytes. 876func (r *Reader) ReadOnly() bool { 877 return r.readonly 878} 879 880// Flags returns the flag bits read from the object file header. 881func (r *Reader) Flags() uint32 { 882 return r.h.Flags 883} 884 885func (r *Reader) Shared() bool { return r.Flags()&ObjFlagShared != 0 } 886func (r *Reader) FromAssembly() bool { return r.Flags()&ObjFlagFromAssembly != 0 } 887func (r *Reader) Unlinkable() bool { return r.Flags()&ObjFlagUnlinkable != 0 } 888func (r *Reader) Std() bool { return r.Flags()&ObjFlagStd != 0 } 889