Help us shape the future of Go! Take the 2026 Go Developer Survey

Source file src/cmd/internal/goobj/objfile.go

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

View as plain text