github.com/bir3/gocompiler@v0.3.205/src/cmd/internal/goobj/objfile.go (about)

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