objfile.go raw

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