github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/internal/goobj2/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  // Go new object file format, reading and writing.
     6  
     7  package goobj2 // TODO: replace the goobj package?
     8  
     9  import (
    10  	"bytes"
    11  	"github.com/gagliardetto/golang-go/cmd/internal/bio"
    12  	"encoding/binary"
    13  	"errors"
    14  	"fmt"
    15  	"io"
    16  	"unsafe"
    17  )
    18  
    19  // New object file format.
    20  //
    21  //    Header struct {
    22  //       Magic   [...]byte   // "\x00go114LD"
    23  //       Flags   uint32
    24  //       // TODO: Fingerprint
    25  //       Offsets [...]uint32 // byte offset of each block below
    26  //    }
    27  //
    28  //    Strings [...]struct {
    29  //       Len  uint32
    30  //       Data [...]byte
    31  //    }
    32  //
    33  //    Autolib  [...]stringOff // imported packages (for file loading) // TODO: add fingerprints
    34  //    PkgIndex [...]stringOff // referenced packages by index
    35  //
    36  //    DwarfFiles [...]stringOff
    37  //
    38  //    SymbolDefs [...]struct {
    39  //       Name stringOff
    40  //       ABI  uint16
    41  //       Type uint8
    42  //       Flag uint8
    43  //       Size uint32
    44  //    }
    45  //    NonPkgDefs [...]struct { // non-pkg symbol definitions
    46  //       ... // same as SymbolDefs
    47  //    }
    48  //    NonPkgRefs [...]struct { // non-pkg symbol references
    49  //       ... // same as SymbolDefs
    50  //    }
    51  //
    52  //    RelocIndex [...]uint32 // index to Relocs
    53  //    AuxIndex   [...]uint32 // index to Aux
    54  //    DataIndex  [...]uint32 // offset to Data
    55  //
    56  //    Relocs [...]struct {
    57  //       Off  int32
    58  //       Size uint8
    59  //       Type uint8
    60  //       Add  int64
    61  //       Sym  symRef
    62  //    }
    63  //
    64  //    Aux [...]struct {
    65  //       Type uint8
    66  //       Sym  symRef
    67  //    }
    68  //
    69  //    Data   [...]byte
    70  //    Pcdata [...]byte
    71  //
    72  // stringOff is a uint32 (?) offset that points to the corresponding
    73  // string, which is a uint32 length followed by that number of bytes.
    74  //
    75  // symRef is struct { PkgIdx, SymIdx uint32 }.
    76  //
    77  // Slice type (e.g. []symRef) is encoded as a length prefix (uint32)
    78  // followed by that number of elements.
    79  //
    80  // The types below correspond to the encoded data structure in the
    81  // object file.
    82  
    83  // Symbol indexing.
    84  //
    85  // Each symbol is referenced with a pair of indices, { PkgIdx, SymIdx },
    86  // as the symRef struct above.
    87  //
    88  // PkgIdx is either a predeclared index (see PkgIdxNone below) or
    89  // an index of an imported package. For the latter case, PkgIdx is the
    90  // index of the package in the PkgIndex array. 0 is an invalid index.
    91  //
    92  // SymIdx is the index of the symbol in the given package.
    93  // - If PkgIdx is PkgIdxSelf, SymIdx is the index of the symbol in the
    94  //   SymbolDefs array.
    95  // - If PkgIdx is PkgIdxNone, SymIdx is the index of the symbol in the
    96  //   NonPkgDefs array (could natually overflow to NonPkgRefs array).
    97  // - Otherwise, SymIdx is the index of the symbol in some other package's
    98  //   SymbolDefs array.
    99  //
   100  // {0, 0} represents a nil symbol. Otherwise PkgIdx should not be 0.
   101  //
   102  // RelocIndex, AuxIndex, and DataIndex contains indices/offsets to
   103  // Relocs/Aux/Data blocks, one element per symbol, first for all the
   104  // defined symbols, then all the defined non-package symbols, in the
   105  // same order of SymbolDefs/NonPkgDefs arrays. For N total defined
   106  // symbols, the array is of length N+1. The last element is the total
   107  // number of relocations (aux symbols, data blocks, etc.).
   108  //
   109  // They can be accessed by index. For the i-th symbol, its relocations
   110  // are the RelocIndex[i]-th (inclusive) to RelocIndex[i+1]-th (exclusive)
   111  // elements in the Relocs array. Aux/Data are likewise. (The index is
   112  // 0-based.)
   113  
   114  // Auxiliary symbols.
   115  //
   116  // Each symbol may (or may not) be associated with a number of auxiliary
   117  // symbols. They are described in the Aux block. See Aux struct below.
   118  // Currently a symbol's Gotype and FuncInfo are auxiliary symbols. We
   119  // may make use of aux symbols in more cases, e.g. DWARF symbols.
   120  
   121  // Package Index.
   122  const (
   123  	PkgIdxNone    = (1<<31 - 1) - iota // Non-package symbols
   124  	PkgIdxBuiltin                      // Predefined symbols // TODO: not used for now, we could use it for compiler-generated symbols like runtime.newobject
   125  	PkgIdxSelf                         // Symbols defined in the current package
   126  	PkgIdxInvalid = 0
   127  	// The index of other referenced packages starts from 1.
   128  )
   129  
   130  // Blocks
   131  const (
   132  	BlkAutolib = iota
   133  	BlkPkgIdx
   134  	BlkDwarfFile
   135  	BlkSymdef
   136  	BlkNonpkgdef
   137  	BlkNonpkgref
   138  	BlkRelocIdx
   139  	BlkAuxIdx
   140  	BlkDataIdx
   141  	BlkReloc
   142  	BlkAux
   143  	BlkData
   144  	BlkPcdata
   145  	NBlk
   146  )
   147  
   148  // File header.
   149  // TODO: probably no need to export this.
   150  type Header struct {
   151  	Magic   string
   152  	Flags   uint32
   153  	Offsets [NBlk]uint32
   154  }
   155  
   156  const Magic = "\x00go114LD"
   157  
   158  func (h *Header) Write(w *Writer) {
   159  	w.RawString(h.Magic)
   160  	w.Uint32(h.Flags)
   161  	for _, x := range h.Offsets {
   162  		w.Uint32(x)
   163  	}
   164  }
   165  
   166  func (h *Header) Read(r *Reader) error {
   167  	b := r.BytesAt(0, len(Magic))
   168  	h.Magic = string(b)
   169  	if h.Magic != Magic {
   170  		return errors.New("wrong magic, not a Go object file")
   171  	}
   172  	off := uint32(len(h.Magic))
   173  	h.Flags = r.uint32At(off)
   174  	off += 4
   175  	for i := range h.Offsets {
   176  		h.Offsets[i] = r.uint32At(off)
   177  		off += 4
   178  	}
   179  	return nil
   180  }
   181  
   182  func (h *Header) Size() int {
   183  	return len(h.Magic) + 4 + 4*len(h.Offsets)
   184  }
   185  
   186  // Symbol definition.
   187  type Sym struct {
   188  	Name string
   189  	ABI  uint16
   190  	Type uint8
   191  	Flag uint8
   192  	Siz  uint32
   193  }
   194  
   195  const SymABIstatic = ^uint16(0)
   196  
   197  const (
   198  	ObjFlagShared = 1 << iota
   199  )
   200  
   201  const (
   202  	SymFlagDupok = 1 << iota
   203  	SymFlagLocal
   204  	SymFlagTypelink
   205  	SymFlagLeaf
   206  	SymFlagCFunc
   207  	SymFlagReflectMethod
   208  	SymFlagGoType
   209  	SymFlagTopFrame
   210  )
   211  
   212  func (s *Sym) Write(w *Writer) {
   213  	w.StringRef(s.Name)
   214  	w.Uint16(s.ABI)
   215  	w.Uint8(s.Type)
   216  	w.Uint8(s.Flag)
   217  	w.Uint32(s.Siz)
   218  }
   219  
   220  func (s *Sym) Read(r *Reader, off uint32) {
   221  	s.Name = r.StringRef(off)
   222  	s.ABI = r.uint16At(off + 4)
   223  	s.Type = r.uint8At(off + 6)
   224  	s.Flag = r.uint8At(off + 7)
   225  	s.Siz = r.uint32At(off + 8)
   226  }
   227  
   228  func (s *Sym) Size() int {
   229  	return 4 + 2 + 1 + 1 + 4
   230  }
   231  
   232  func (s *Sym) Dupok() bool         { return s.Flag&SymFlagDupok != 0 }
   233  func (s *Sym) Local() bool         { return s.Flag&SymFlagLocal != 0 }
   234  func (s *Sym) Typelink() bool      { return s.Flag&SymFlagTypelink != 0 }
   235  func (s *Sym) Leaf() bool          { return s.Flag&SymFlagLeaf != 0 }
   236  func (s *Sym) CFunc() bool         { return s.Flag&SymFlagCFunc != 0 }
   237  func (s *Sym) ReflectMethod() bool { return s.Flag&SymFlagReflectMethod != 0 }
   238  func (s *Sym) IsGoType() bool      { return s.Flag&SymFlagGoType != 0 }
   239  func (s *Sym) TopFrame() bool      { return s.Flag&SymFlagTopFrame != 0 }
   240  
   241  // Symbol reference.
   242  type SymRef struct {
   243  	PkgIdx uint32
   244  	SymIdx uint32
   245  }
   246  
   247  func (s *SymRef) Write(w *Writer) {
   248  	w.Uint32(s.PkgIdx)
   249  	w.Uint32(s.SymIdx)
   250  }
   251  
   252  func (s *SymRef) Read(r *Reader, off uint32) {
   253  	s.PkgIdx = r.uint32At(off)
   254  	s.SymIdx = r.uint32At(off + 4)
   255  }
   256  
   257  func (s *SymRef) Size() int {
   258  	return 4 + 4
   259  }
   260  
   261  // Relocation.
   262  type Reloc struct {
   263  	Off  int32
   264  	Siz  uint8
   265  	Type uint8
   266  	Add  int64
   267  	Sym  SymRef
   268  }
   269  
   270  func (r *Reloc) Write(w *Writer) {
   271  	w.Uint32(uint32(r.Off))
   272  	w.Uint8(r.Siz)
   273  	w.Uint8(r.Type)
   274  	w.Uint64(uint64(r.Add))
   275  	r.Sym.Write(w)
   276  }
   277  
   278  func (o *Reloc) Read(r *Reader, off uint32) {
   279  	o.Off = r.int32At(off)
   280  	o.Siz = r.uint8At(off + 4)
   281  	o.Type = r.uint8At(off + 5)
   282  	o.Add = r.int64At(off + 6)
   283  	o.Sym.Read(r, off+14)
   284  }
   285  
   286  func (r *Reloc) Size() int {
   287  	return 4 + 1 + 1 + 8 + r.Sym.Size()
   288  }
   289  
   290  // Aux symbol info.
   291  type Aux struct {
   292  	Type uint8
   293  	Sym  SymRef
   294  }
   295  
   296  // Aux Type
   297  const (
   298  	AuxGotype = iota
   299  	AuxFuncInfo
   300  	AuxFuncdata
   301  	AuxDwarfInfo
   302  	AuxDwarfLoc
   303  	AuxDwarfRanges
   304  	AuxDwarfLines
   305  
   306  	// TODO: more. Pcdata?
   307  )
   308  
   309  func (a *Aux) Write(w *Writer) {
   310  	w.Uint8(a.Type)
   311  	a.Sym.Write(w)
   312  }
   313  
   314  func (a *Aux) Read(r *Reader, off uint32) {
   315  	a.Type = r.uint8At(off)
   316  	a.Sym.Read(r, off+1)
   317  }
   318  
   319  func (a *Aux) Size() int {
   320  	return 1 + a.Sym.Size()
   321  }
   322  
   323  type Writer struct {
   324  	wr        *bio.Writer
   325  	stringMap map[string]uint32
   326  	off       uint32 // running offset
   327  }
   328  
   329  func NewWriter(wr *bio.Writer) *Writer {
   330  	return &Writer{wr: wr, stringMap: make(map[string]uint32)}
   331  }
   332  
   333  func (w *Writer) AddString(s string) {
   334  	if _, ok := w.stringMap[s]; ok {
   335  		return
   336  	}
   337  	w.stringMap[s] = w.off
   338  	w.Uint32(uint32(len(s)))
   339  	w.RawString(s)
   340  }
   341  
   342  func (w *Writer) StringRef(s string) {
   343  	off, ok := w.stringMap[s]
   344  	if !ok {
   345  		panic(fmt.Sprintf("writeStringRef: string not added: %q", s))
   346  	}
   347  	w.Uint32(off)
   348  }
   349  
   350  func (w *Writer) RawString(s string) {
   351  	w.wr.WriteString(s)
   352  	w.off += uint32(len(s))
   353  }
   354  
   355  func (w *Writer) Bytes(s []byte) {
   356  	w.wr.Write(s)
   357  	w.off += uint32(len(s))
   358  }
   359  
   360  func (w *Writer) Uint64(x uint64) {
   361  	var b [8]byte
   362  	binary.LittleEndian.PutUint64(b[:], x)
   363  	w.wr.Write(b[:])
   364  	w.off += 8
   365  }
   366  
   367  func (w *Writer) Uint32(x uint32) {
   368  	var b [4]byte
   369  	binary.LittleEndian.PutUint32(b[:], x)
   370  	w.wr.Write(b[:])
   371  	w.off += 4
   372  }
   373  
   374  func (w *Writer) Uint16(x uint16) {
   375  	var b [2]byte
   376  	binary.LittleEndian.PutUint16(b[:], x)
   377  	w.wr.Write(b[:])
   378  	w.off += 2
   379  }
   380  
   381  func (w *Writer) Uint8(x uint8) {
   382  	w.wr.WriteByte(x)
   383  	w.off++
   384  }
   385  
   386  func (w *Writer) Offset() uint32 {
   387  	return w.off
   388  }
   389  
   390  type Reader struct {
   391  	b        []byte // mmapped bytes, if not nil
   392  	readonly bool   // whether b is backed with read-only memory
   393  
   394  	rd    io.ReaderAt
   395  	start uint32
   396  	h     Header // keep block offsets
   397  }
   398  
   399  func NewReaderFromBytes(b []byte, readonly bool) *Reader {
   400  	r := &Reader{b: b, readonly: readonly, rd: bytes.NewReader(b), start: 0}
   401  	err := r.h.Read(r)
   402  	if err != nil {
   403  		return nil
   404  	}
   405  	return r
   406  }
   407  
   408  func (r *Reader) BytesAt(off uint32, len int) []byte {
   409  	if len == 0 {
   410  		return nil
   411  	}
   412  	end := int(off) + len
   413  	return r.b[int(off):end:end]
   414  }
   415  
   416  func (r *Reader) uint64At(off uint32) uint64 {
   417  	b := r.BytesAt(off, 8)
   418  	return binary.LittleEndian.Uint64(b)
   419  }
   420  
   421  func (r *Reader) int64At(off uint32) int64 {
   422  	return int64(r.uint64At(off))
   423  }
   424  
   425  func (r *Reader) uint32At(off uint32) uint32 {
   426  	b := r.BytesAt(off, 4)
   427  	return binary.LittleEndian.Uint32(b)
   428  }
   429  
   430  func (r *Reader) int32At(off uint32) int32 {
   431  	return int32(r.uint32At(off))
   432  }
   433  
   434  func (r *Reader) uint16At(off uint32) uint16 {
   435  	b := r.BytesAt(off, 2)
   436  	return binary.LittleEndian.Uint16(b)
   437  }
   438  
   439  func (r *Reader) uint8At(off uint32) uint8 {
   440  	b := r.BytesAt(off, 1)
   441  	return b[0]
   442  }
   443  
   444  func (r *Reader) StringAt(off uint32) string {
   445  	l := r.uint32At(off)
   446  	b := r.b[off+4 : off+4+l]
   447  	if r.readonly {
   448  		return toString(b) // backed by RO memory, ok to make unsafe string
   449  	}
   450  	return string(b)
   451  }
   452  
   453  func toString(b []byte) string {
   454  	type stringHeader struct {
   455  		str unsafe.Pointer
   456  		len int
   457  	}
   458  
   459  	if len(b) == 0 {
   460  		return ""
   461  	}
   462  	ss := stringHeader{str: unsafe.Pointer(&b[0]), len: len(b)}
   463  	s := *(*string)(unsafe.Pointer(&ss))
   464  	return s
   465  }
   466  
   467  func (r *Reader) StringRef(off uint32) string {
   468  	return r.StringAt(r.uint32At(off))
   469  }
   470  
   471  func (r *Reader) Autolib() []string {
   472  	n := (r.h.Offsets[BlkAutolib+1] - r.h.Offsets[BlkAutolib]) / 4
   473  	s := make([]string, n)
   474  	for i := range s {
   475  		off := r.h.Offsets[BlkAutolib] + uint32(i)*4
   476  		s[i] = r.StringRef(off)
   477  	}
   478  	return s
   479  }
   480  
   481  func (r *Reader) Pkglist() []string {
   482  	n := (r.h.Offsets[BlkPkgIdx+1] - r.h.Offsets[BlkPkgIdx]) / 4
   483  	s := make([]string, n)
   484  	for i := range s {
   485  		off := r.h.Offsets[BlkPkgIdx] + uint32(i)*4
   486  		s[i] = r.StringRef(off)
   487  	}
   488  	return s
   489  }
   490  
   491  func (r *Reader) NPkg() int {
   492  	return int(r.h.Offsets[BlkPkgIdx+1]-r.h.Offsets[BlkPkgIdx]) / 4
   493  }
   494  
   495  func (r *Reader) Pkg(i int) string {
   496  	off := r.h.Offsets[BlkPkgIdx] + uint32(i)*4
   497  	return r.StringRef(off)
   498  }
   499  
   500  func (r *Reader) NDwarfFile() int {
   501  	return int(r.h.Offsets[BlkDwarfFile+1]-r.h.Offsets[BlkDwarfFile]) / 4
   502  }
   503  
   504  func (r *Reader) DwarfFile(i int) string {
   505  	off := r.h.Offsets[BlkDwarfFile] + uint32(i)*4
   506  	return r.StringRef(off)
   507  }
   508  
   509  func (r *Reader) NSym() int {
   510  	symsiz := (&Sym{}).Size()
   511  	return int(r.h.Offsets[BlkSymdef+1]-r.h.Offsets[BlkSymdef]) / symsiz
   512  }
   513  
   514  func (r *Reader) NNonpkgdef() int {
   515  	symsiz := (&Sym{}).Size()
   516  	return int(r.h.Offsets[BlkNonpkgdef+1]-r.h.Offsets[BlkNonpkgdef]) / symsiz
   517  }
   518  
   519  func (r *Reader) NNonpkgref() int {
   520  	symsiz := (&Sym{}).Size()
   521  	return int(r.h.Offsets[BlkNonpkgref+1]-r.h.Offsets[BlkNonpkgref]) / symsiz
   522  }
   523  
   524  // SymOff returns the offset of the i-th symbol.
   525  func (r *Reader) SymOff(i int) uint32 {
   526  	symsiz := (&Sym{}).Size()
   527  	return r.h.Offsets[BlkSymdef] + uint32(i*symsiz)
   528  }
   529  
   530  // NReloc returns the number of relocations of the i-th symbol.
   531  func (r *Reader) NReloc(i int) int {
   532  	relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4)
   533  	return int(r.uint32At(relocIdxOff+4) - r.uint32At(relocIdxOff))
   534  }
   535  
   536  // RelocOff returns the offset of the j-th relocation of the i-th symbol.
   537  func (r *Reader) RelocOff(i int, j int) uint32 {
   538  	relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4)
   539  	relocIdx := r.uint32At(relocIdxOff)
   540  	relocsiz := (&Reloc{}).Size()
   541  	return r.h.Offsets[BlkReloc] + (relocIdx+uint32(j))*uint32(relocsiz)
   542  }
   543  
   544  // NAux returns the number of aux symbols of the i-th symbol.
   545  func (r *Reader) NAux(i int) int {
   546  	auxIdxOff := r.h.Offsets[BlkAuxIdx] + uint32(i*4)
   547  	return int(r.uint32At(auxIdxOff+4) - r.uint32At(auxIdxOff))
   548  }
   549  
   550  // AuxOff returns the offset of the j-th aux symbol of the i-th symbol.
   551  func (r *Reader) AuxOff(i int, j int) uint32 {
   552  	auxIdxOff := r.h.Offsets[BlkAuxIdx] + uint32(i*4)
   553  	auxIdx := r.uint32At(auxIdxOff)
   554  	auxsiz := (&Aux{}).Size()
   555  	return r.h.Offsets[BlkAux] + (auxIdx+uint32(j))*uint32(auxsiz)
   556  }
   557  
   558  // DataOff returns the offset of the i-th symbol's data.
   559  func (r *Reader) DataOff(i int) uint32 {
   560  	dataIdxOff := r.h.Offsets[BlkDataIdx] + uint32(i*4)
   561  	return r.h.Offsets[BlkData] + r.uint32At(dataIdxOff)
   562  }
   563  
   564  // DataSize returns the size of the i-th symbol's data.
   565  func (r *Reader) DataSize(i int) int {
   566  	return int(r.DataOff(i+1) - r.DataOff(i))
   567  }
   568  
   569  // Data returns the i-th symbol's data.
   570  func (r *Reader) Data(i int) []byte {
   571  	return r.BytesAt(r.DataOff(i), r.DataSize(i))
   572  }
   573  
   574  // AuxDataBase returns the base offset of the aux data block.
   575  func (r *Reader) PcdataBase() uint32 {
   576  	return r.h.Offsets[BlkPcdata]
   577  }
   578  
   579  // ReadOnly returns whether r.BytesAt returns read-only bytes.
   580  func (r *Reader) ReadOnly() bool {
   581  	return r.readonly
   582  }
   583  
   584  // Flags returns the flag bits read from the object file header.
   585  func (r *Reader) Flags() uint32 {
   586  	return r.h.Flags
   587  }