github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/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  // - github.com/go-asm/go/cmd/obj/objfile.go (used by cmd/asm and cmd/compile)
    14  // - github.com/go-asm/go/cmd/objfile/goobj.go (used cmd/nm, cmd/objdump)
    15  // - github.com/go-asm/go/cmd/link/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  	"encoding/binary"
    23  	"errors"
    24  	"fmt"
    25  	"unsafe"
    26  
    27  	"github.com/go-asm/go/cmd/bio"
    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 naturally 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) + len(h.Fingerprint) + 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  	SymFlagPkgInit
   307  )
   308  
   309  // Returns the length of the name of the symbol.
   310  func (s *Sym) NameLen(r *Reader) int {
   311  	return int(binary.LittleEndian.Uint32(s[:]))
   312  }
   313  
   314  func (s *Sym) Name(r *Reader) string {
   315  	len := binary.LittleEndian.Uint32(s[:])
   316  	off := binary.LittleEndian.Uint32(s[4:])
   317  	return r.StringAt(off, len)
   318  }
   319  
   320  func (s *Sym) ABI() uint16   { return binary.LittleEndian.Uint16(s[8:]) }
   321  func (s *Sym) Type() uint8   { return s[10] }
   322  func (s *Sym) Flag() uint8   { return s[11] }
   323  func (s *Sym) Flag2() uint8  { return s[12] }
   324  func (s *Sym) Siz() uint32   { return binary.LittleEndian.Uint32(s[13:]) }
   325  func (s *Sym) Align() uint32 { return binary.LittleEndian.Uint32(s[17:]) }
   326  
   327  func (s *Sym) Dupok() bool         { return s.Flag()&SymFlagDupok != 0 }
   328  func (s *Sym) Local() bool         { return s.Flag()&SymFlagLocal != 0 }
   329  func (s *Sym) Typelink() bool      { return s.Flag()&SymFlagTypelink != 0 }
   330  func (s *Sym) Leaf() bool          { return s.Flag()&SymFlagLeaf != 0 }
   331  func (s *Sym) NoSplit() bool       { return s.Flag()&SymFlagNoSplit != 0 }
   332  func (s *Sym) ReflectMethod() bool { return s.Flag()&SymFlagReflectMethod != 0 }
   333  func (s *Sym) IsGoType() bool      { return s.Flag()&SymFlagGoType != 0 }
   334  func (s *Sym) UsedInIface() bool   { return s.Flag2()&SymFlagUsedInIface != 0 }
   335  func (s *Sym) IsItab() bool        { return s.Flag2()&SymFlagItab != 0 }
   336  func (s *Sym) IsDict() bool        { return s.Flag2()&SymFlagDict != 0 }
   337  func (s *Sym) IsPkgInit() bool     { return s.Flag2()&SymFlagPkgInit != 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  func (s SymRef) IsZero() bool { return s == SymRef{} }
   363  
   364  // Hash64
   365  type Hash64Type [Hash64Size]byte
   366  
   367  const Hash64Size = 8
   368  
   369  // Hash
   370  type HashType [HashSize]byte
   371  
   372  const HashSize = 16 // truncated SHA256
   373  
   374  // Relocation.
   375  //
   376  // Serialized format:
   377  //
   378  //	Reloc struct {
   379  //	   Off  int32
   380  //	   Siz  uint8
   381  //	   Type uint16
   382  //	   Add  int64
   383  //	   Sym  SymRef
   384  //	}
   385  type Reloc [RelocSize]byte
   386  
   387  const RelocSize = 4 + 1 + 2 + 8 + 8
   388  
   389  func (r *Reloc) Off() int32   { return int32(binary.LittleEndian.Uint32(r[:])) }
   390  func (r *Reloc) Siz() uint8   { return r[4] }
   391  func (r *Reloc) Type() uint16 { return binary.LittleEndian.Uint16(r[5:]) }
   392  func (r *Reloc) Add() int64   { return int64(binary.LittleEndian.Uint64(r[7:])) }
   393  func (r *Reloc) Sym() SymRef {
   394  	return SymRef{binary.LittleEndian.Uint32(r[15:]), binary.LittleEndian.Uint32(r[19:])}
   395  }
   396  
   397  func (r *Reloc) SetOff(x int32)   { binary.LittleEndian.PutUint32(r[:], uint32(x)) }
   398  func (r *Reloc) SetSiz(x uint8)   { r[4] = x }
   399  func (r *Reloc) SetType(x uint16) { binary.LittleEndian.PutUint16(r[5:], x) }
   400  func (r *Reloc) SetAdd(x int64)   { binary.LittleEndian.PutUint64(r[7:], uint64(x)) }
   401  func (r *Reloc) SetSym(x SymRef) {
   402  	binary.LittleEndian.PutUint32(r[15:], x.PkgIdx)
   403  	binary.LittleEndian.PutUint32(r[19:], x.SymIdx)
   404  }
   405  
   406  func (r *Reloc) Set(off int32, size uint8, typ uint16, add int64, sym SymRef) {
   407  	r.SetOff(off)
   408  	r.SetSiz(size)
   409  	r.SetType(typ)
   410  	r.SetAdd(add)
   411  	r.SetSym(sym)
   412  }
   413  
   414  func (r *Reloc) Write(w *Writer) { w.Bytes(r[:]) }
   415  
   416  // for testing
   417  func (r *Reloc) fromBytes(b []byte) { copy(r[:], b) }
   418  
   419  // Aux symbol info.
   420  //
   421  // Serialized format:
   422  //
   423  //	Aux struct {
   424  //	   Type uint8
   425  //	   Sym  SymRef
   426  //	}
   427  type Aux [AuxSize]byte
   428  
   429  const AuxSize = 1 + 8
   430  
   431  // Aux Type
   432  const (
   433  	AuxGotype = iota
   434  	AuxFuncInfo
   435  	AuxFuncdata
   436  	AuxDwarfInfo
   437  	AuxDwarfLoc
   438  	AuxDwarfRanges
   439  	AuxDwarfLines
   440  	AuxPcsp
   441  	AuxPcfile
   442  	AuxPcline
   443  	AuxPcinline
   444  	AuxPcdata
   445  	AuxWasmImport
   446  	AuxSehUnwindInfo
   447  )
   448  
   449  func (a *Aux) Type() uint8 { return a[0] }
   450  func (a *Aux) Sym() SymRef {
   451  	return SymRef{binary.LittleEndian.Uint32(a[1:]), binary.LittleEndian.Uint32(a[5:])}
   452  }
   453  
   454  func (a *Aux) SetType(x uint8) { a[0] = x }
   455  func (a *Aux) SetSym(x SymRef) {
   456  	binary.LittleEndian.PutUint32(a[1:], x.PkgIdx)
   457  	binary.LittleEndian.PutUint32(a[5:], x.SymIdx)
   458  }
   459  
   460  func (a *Aux) Write(w *Writer) { w.Bytes(a[:]) }
   461  
   462  // for testing
   463  func (a *Aux) fromBytes(b []byte) { copy(a[:], b) }
   464  
   465  // Referenced symbol flags.
   466  //
   467  // Serialized format:
   468  //
   469  //	RefFlags struct {
   470  //	   Sym   symRef
   471  //	   Flag  uint8
   472  //	   Flag2 uint8
   473  //	}
   474  type RefFlags [RefFlagsSize]byte
   475  
   476  const RefFlagsSize = 8 + 1 + 1
   477  
   478  func (r *RefFlags) Sym() SymRef {
   479  	return SymRef{binary.LittleEndian.Uint32(r[:]), binary.LittleEndian.Uint32(r[4:])}
   480  }
   481  func (r *RefFlags) Flag() uint8  { return r[8] }
   482  func (r *RefFlags) Flag2() uint8 { return r[9] }
   483  
   484  func (r *RefFlags) SetSym(x SymRef) {
   485  	binary.LittleEndian.PutUint32(r[:], x.PkgIdx)
   486  	binary.LittleEndian.PutUint32(r[4:], x.SymIdx)
   487  }
   488  func (r *RefFlags) SetFlag(x uint8)  { r[8] = x }
   489  func (r *RefFlags) SetFlag2(x uint8) { r[9] = x }
   490  
   491  func (r *RefFlags) Write(w *Writer) { w.Bytes(r[:]) }
   492  
   493  // Used to construct an artificially large array type when reading an
   494  // item from the object file relocs section or aux sym section (needs
   495  // to work on 32-bit as well as 64-bit). See issue 41621.
   496  const huge = (1<<31 - 1) / RelocSize
   497  
   498  // Referenced symbol name.
   499  //
   500  // Serialized format:
   501  //
   502  //	RefName struct {
   503  //	   Sym  symRef
   504  //	   Name string
   505  //	}
   506  type RefName [RefNameSize]byte
   507  
   508  const RefNameSize = 8 + stringRefSize
   509  
   510  func (n *RefName) Sym() SymRef {
   511  	return SymRef{binary.LittleEndian.Uint32(n[:]), binary.LittleEndian.Uint32(n[4:])}
   512  }
   513  func (n *RefName) Name(r *Reader) string {
   514  	len := binary.LittleEndian.Uint32(n[8:])
   515  	off := binary.LittleEndian.Uint32(n[12:])
   516  	return r.StringAt(off, len)
   517  }
   518  
   519  func (n *RefName) SetSym(x SymRef) {
   520  	binary.LittleEndian.PutUint32(n[:], x.PkgIdx)
   521  	binary.LittleEndian.PutUint32(n[4:], x.SymIdx)
   522  }
   523  func (n *RefName) SetName(x string, w *Writer) {
   524  	binary.LittleEndian.PutUint32(n[8:], uint32(len(x)))
   525  	binary.LittleEndian.PutUint32(n[12:], w.stringOff(x))
   526  }
   527  
   528  func (n *RefName) Write(w *Writer) { w.Bytes(n[:]) }
   529  
   530  type Writer struct {
   531  	wr        *bio.Writer
   532  	stringMap map[string]uint32
   533  	off       uint32 // running offset
   534  
   535  	b [8]byte // scratch space for writing bytes
   536  }
   537  
   538  func NewWriter(wr *bio.Writer) *Writer {
   539  	return &Writer{wr: wr, stringMap: make(map[string]uint32)}
   540  }
   541  
   542  func (w *Writer) AddString(s string) {
   543  	if _, ok := w.stringMap[s]; ok {
   544  		return
   545  	}
   546  	w.stringMap[s] = w.off
   547  	w.RawString(s)
   548  }
   549  
   550  func (w *Writer) stringOff(s string) uint32 {
   551  	off, ok := w.stringMap[s]
   552  	if !ok {
   553  		panic(fmt.Sprintf("writeStringRef: string not added: %q", s))
   554  	}
   555  	return off
   556  }
   557  
   558  func (w *Writer) StringRef(s string) {
   559  	w.Uint32(uint32(len(s)))
   560  	w.Uint32(w.stringOff(s))
   561  }
   562  
   563  func (w *Writer) RawString(s string) {
   564  	w.wr.WriteString(s)
   565  	w.off += uint32(len(s))
   566  }
   567  
   568  func (w *Writer) Bytes(s []byte) {
   569  	w.wr.Write(s)
   570  	w.off += uint32(len(s))
   571  }
   572  
   573  func (w *Writer) Uint64(x uint64) {
   574  	binary.LittleEndian.PutUint64(w.b[:], x)
   575  	w.wr.Write(w.b[:])
   576  	w.off += 8
   577  }
   578  
   579  func (w *Writer) Uint32(x uint32) {
   580  	binary.LittleEndian.PutUint32(w.b[:4], x)
   581  	w.wr.Write(w.b[:4])
   582  	w.off += 4
   583  }
   584  
   585  func (w *Writer) Uint16(x uint16) {
   586  	binary.LittleEndian.PutUint16(w.b[:2], x)
   587  	w.wr.Write(w.b[:2])
   588  	w.off += 2
   589  }
   590  
   591  func (w *Writer) Uint8(x uint8) {
   592  	w.wr.WriteByte(x)
   593  	w.off++
   594  }
   595  
   596  func (w *Writer) Offset() uint32 {
   597  	return w.off
   598  }
   599  
   600  type Reader struct {
   601  	b        []byte // mmapped bytes, if not nil
   602  	readonly bool   // whether b is backed with read-only memory
   603  
   604  	start uint32
   605  	h     Header // keep block offsets
   606  }
   607  
   608  func NewReaderFromBytes(b []byte, readonly bool) *Reader {
   609  	r := &Reader{b: b, readonly: readonly, start: 0}
   610  	err := r.h.Read(r)
   611  	if err != nil {
   612  		return nil
   613  	}
   614  	return r
   615  }
   616  
   617  func (r *Reader) BytesAt(off uint32, len int) []byte {
   618  	if len == 0 {
   619  		return nil
   620  	}
   621  	end := int(off) + len
   622  	return r.b[int(off):end:end]
   623  }
   624  
   625  func (r *Reader) uint64At(off uint32) uint64 {
   626  	b := r.BytesAt(off, 8)
   627  	return binary.LittleEndian.Uint64(b)
   628  }
   629  
   630  func (r *Reader) int64At(off uint32) int64 {
   631  	return int64(r.uint64At(off))
   632  }
   633  
   634  func (r *Reader) uint32At(off uint32) uint32 {
   635  	b := r.BytesAt(off, 4)
   636  	return binary.LittleEndian.Uint32(b)
   637  }
   638  
   639  func (r *Reader) int32At(off uint32) int32 {
   640  	return int32(r.uint32At(off))
   641  }
   642  
   643  func (r *Reader) uint16At(off uint32) uint16 {
   644  	b := r.BytesAt(off, 2)
   645  	return binary.LittleEndian.Uint16(b)
   646  }
   647  
   648  func (r *Reader) uint8At(off uint32) uint8 {
   649  	b := r.BytesAt(off, 1)
   650  	return b[0]
   651  }
   652  
   653  func (r *Reader) StringAt(off uint32, len uint32) string {
   654  	b := r.b[off : off+len]
   655  	if r.readonly {
   656  		return toString(b) // backed by RO memory, ok to make unsafe string
   657  	}
   658  	return string(b)
   659  }
   660  
   661  func toString(b []byte) string {
   662  	if len(b) == 0 {
   663  		return ""
   664  	}
   665  	return unsafe.String(&b[0], len(b))
   666  }
   667  
   668  func (r *Reader) StringRef(off uint32) string {
   669  	l := r.uint32At(off)
   670  	return r.StringAt(r.uint32At(off+4), l)
   671  }
   672  
   673  func (r *Reader) Fingerprint() FingerprintType {
   674  	return r.h.Fingerprint
   675  }
   676  
   677  func (r *Reader) Autolib() []ImportedPkg {
   678  	n := (r.h.Offsets[BlkAutolib+1] - r.h.Offsets[BlkAutolib]) / importedPkgSize
   679  	s := make([]ImportedPkg, n)
   680  	off := r.h.Offsets[BlkAutolib]
   681  	for i := range s {
   682  		s[i].Pkg = r.StringRef(off)
   683  		copy(s[i].Fingerprint[:], r.BytesAt(off+stringRefSize, len(s[i].Fingerprint)))
   684  		off += importedPkgSize
   685  	}
   686  	return s
   687  }
   688  
   689  func (r *Reader) Pkglist() []string {
   690  	n := (r.h.Offsets[BlkPkgIdx+1] - r.h.Offsets[BlkPkgIdx]) / stringRefSize
   691  	s := make([]string, n)
   692  	off := r.h.Offsets[BlkPkgIdx]
   693  	for i := range s {
   694  		s[i] = r.StringRef(off)
   695  		off += stringRefSize
   696  	}
   697  	return s
   698  }
   699  
   700  func (r *Reader) NPkg() int {
   701  	return int(r.h.Offsets[BlkPkgIdx+1]-r.h.Offsets[BlkPkgIdx]) / stringRefSize
   702  }
   703  
   704  func (r *Reader) Pkg(i int) string {
   705  	off := r.h.Offsets[BlkPkgIdx] + uint32(i)*stringRefSize
   706  	return r.StringRef(off)
   707  }
   708  
   709  func (r *Reader) NFile() int {
   710  	return int(r.h.Offsets[BlkFile+1]-r.h.Offsets[BlkFile]) / stringRefSize
   711  }
   712  
   713  func (r *Reader) File(i int) string {
   714  	off := r.h.Offsets[BlkFile] + uint32(i)*stringRefSize
   715  	return r.StringRef(off)
   716  }
   717  
   718  func (r *Reader) NSym() int {
   719  	return int(r.h.Offsets[BlkSymdef+1]-r.h.Offsets[BlkSymdef]) / SymSize
   720  }
   721  
   722  func (r *Reader) NHashed64def() int {
   723  	return int(r.h.Offsets[BlkHashed64def+1]-r.h.Offsets[BlkHashed64def]) / SymSize
   724  }
   725  
   726  func (r *Reader) NHasheddef() int {
   727  	return int(r.h.Offsets[BlkHasheddef+1]-r.h.Offsets[BlkHasheddef]) / SymSize
   728  }
   729  
   730  func (r *Reader) NNonpkgdef() int {
   731  	return int(r.h.Offsets[BlkNonpkgdef+1]-r.h.Offsets[BlkNonpkgdef]) / SymSize
   732  }
   733  
   734  func (r *Reader) NNonpkgref() int {
   735  	return int(r.h.Offsets[BlkNonpkgref+1]-r.h.Offsets[BlkNonpkgref]) / SymSize
   736  }
   737  
   738  // SymOff returns the offset of the i-th symbol.
   739  func (r *Reader) SymOff(i uint32) uint32 {
   740  	return r.h.Offsets[BlkSymdef] + uint32(i*SymSize)
   741  }
   742  
   743  // Sym returns a pointer to the i-th symbol.
   744  func (r *Reader) Sym(i uint32) *Sym {
   745  	off := r.SymOff(i)
   746  	return (*Sym)(unsafe.Pointer(&r.b[off]))
   747  }
   748  
   749  // NRefFlags returns the number of referenced symbol flags.
   750  func (r *Reader) NRefFlags() int {
   751  	return int(r.h.Offsets[BlkRefFlags+1]-r.h.Offsets[BlkRefFlags]) / RefFlagsSize
   752  }
   753  
   754  // RefFlags returns a pointer to the i-th referenced symbol flags.
   755  // Note: here i is not a local symbol index, just a counter.
   756  func (r *Reader) RefFlags(i int) *RefFlags {
   757  	off := r.h.Offsets[BlkRefFlags] + uint32(i*RefFlagsSize)
   758  	return (*RefFlags)(unsafe.Pointer(&r.b[off]))
   759  }
   760  
   761  // Hash64 returns the i-th short hashed symbol's hash.
   762  // Note: here i is the index of short hashed symbols, not all symbols
   763  // (unlike other accessors).
   764  func (r *Reader) Hash64(i uint32) uint64 {
   765  	off := r.h.Offsets[BlkHash64] + uint32(i*Hash64Size)
   766  	return r.uint64At(off)
   767  }
   768  
   769  // Hash returns a pointer to the i-th hashed symbol's hash.
   770  // Note: here i is the index of hashed symbols, not all symbols
   771  // (unlike other accessors).
   772  func (r *Reader) Hash(i uint32) *HashType {
   773  	off := r.h.Offsets[BlkHash] + uint32(i*HashSize)
   774  	return (*HashType)(unsafe.Pointer(&r.b[off]))
   775  }
   776  
   777  // NReloc returns the number of relocations of the i-th symbol.
   778  func (r *Reader) NReloc(i uint32) int {
   779  	relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4)
   780  	return int(r.uint32At(relocIdxOff+4) - r.uint32At(relocIdxOff))
   781  }
   782  
   783  // RelocOff returns the offset of the j-th relocation of the i-th symbol.
   784  func (r *Reader) RelocOff(i uint32, j int) uint32 {
   785  	relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4)
   786  	relocIdx := r.uint32At(relocIdxOff)
   787  	return r.h.Offsets[BlkReloc] + (relocIdx+uint32(j))*uint32(RelocSize)
   788  }
   789  
   790  // Reloc returns a pointer to the j-th relocation of the i-th symbol.
   791  func (r *Reader) Reloc(i uint32, j int) *Reloc {
   792  	off := r.RelocOff(i, j)
   793  	return (*Reloc)(unsafe.Pointer(&r.b[off]))
   794  }
   795  
   796  // Relocs returns a pointer to the relocations of the i-th symbol.
   797  func (r *Reader) Relocs(i uint32) []Reloc {
   798  	off := r.RelocOff(i, 0)
   799  	n := r.NReloc(i)
   800  	return (*[huge]Reloc)(unsafe.Pointer(&r.b[off]))[:n:n]
   801  }
   802  
   803  // NAux returns the number of aux symbols of the i-th symbol.
   804  func (r *Reader) NAux(i uint32) int {
   805  	auxIdxOff := r.h.Offsets[BlkAuxIdx] + i*4
   806  	return int(r.uint32At(auxIdxOff+4) - r.uint32At(auxIdxOff))
   807  }
   808  
   809  // AuxOff returns the offset of the j-th aux symbol of the i-th symbol.
   810  func (r *Reader) AuxOff(i uint32, j int) uint32 {
   811  	auxIdxOff := r.h.Offsets[BlkAuxIdx] + i*4
   812  	auxIdx := r.uint32At(auxIdxOff)
   813  	return r.h.Offsets[BlkAux] + (auxIdx+uint32(j))*uint32(AuxSize)
   814  }
   815  
   816  // Aux returns a pointer to the j-th aux symbol of the i-th symbol.
   817  func (r *Reader) Aux(i uint32, j int) *Aux {
   818  	off := r.AuxOff(i, j)
   819  	return (*Aux)(unsafe.Pointer(&r.b[off]))
   820  }
   821  
   822  // Auxs returns the aux symbols of the i-th symbol.
   823  func (r *Reader) Auxs(i uint32) []Aux {
   824  	off := r.AuxOff(i, 0)
   825  	n := r.NAux(i)
   826  	return (*[huge]Aux)(unsafe.Pointer(&r.b[off]))[:n:n]
   827  }
   828  
   829  // DataOff returns the offset of the i-th symbol's data.
   830  func (r *Reader) DataOff(i uint32) uint32 {
   831  	dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
   832  	return r.h.Offsets[BlkData] + r.uint32At(dataIdxOff)
   833  }
   834  
   835  // DataSize returns the size of the i-th symbol's data.
   836  func (r *Reader) DataSize(i uint32) int {
   837  	dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
   838  	return int(r.uint32At(dataIdxOff+4) - r.uint32At(dataIdxOff))
   839  }
   840  
   841  // Data returns the i-th symbol's data.
   842  func (r *Reader) Data(i uint32) []byte {
   843  	dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
   844  	base := r.h.Offsets[BlkData]
   845  	off := r.uint32At(dataIdxOff)
   846  	end := r.uint32At(dataIdxOff + 4)
   847  	return r.BytesAt(base+off, int(end-off))
   848  }
   849  
   850  // DataString returns the i-th symbol's data as a string.
   851  func (r *Reader) DataString(i uint32) string {
   852  	dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
   853  	base := r.h.Offsets[BlkData]
   854  	off := r.uint32At(dataIdxOff)
   855  	end := r.uint32At(dataIdxOff + 4)
   856  	return r.StringAt(base+off, end-off)
   857  }
   858  
   859  // NRefName returns the number of referenced symbol names.
   860  func (r *Reader) NRefName() int {
   861  	return int(r.h.Offsets[BlkRefName+1]-r.h.Offsets[BlkRefName]) / RefNameSize
   862  }
   863  
   864  // RefName returns a pointer to the i-th referenced symbol name.
   865  // Note: here i is not a local symbol index, just a counter.
   866  func (r *Reader) RefName(i int) *RefName {
   867  	off := r.h.Offsets[BlkRefName] + uint32(i*RefNameSize)
   868  	return (*RefName)(unsafe.Pointer(&r.b[off]))
   869  }
   870  
   871  // ReadOnly returns whether r.BytesAt returns read-only bytes.
   872  func (r *Reader) ReadOnly() bool {
   873  	return r.readonly
   874  }
   875  
   876  // Flags returns the flag bits read from the object file header.
   877  func (r *Reader) Flags() uint32 {
   878  	return r.h.Flags
   879  }
   880  
   881  func (r *Reader) Shared() bool       { return r.Flags()&ObjFlagShared != 0 }
   882  func (r *Reader) FromAssembly() bool { return r.Flags()&ObjFlagFromAssembly != 0 }
   883  func (r *Reader) Unlinkable() bool   { return r.Flags()&ObjFlagUnlinkable != 0 }