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