github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/link/internal/objfile/objfile.go (about)

     1  // Copyright 2013 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  // Package objfile reads Go object files for the Go linker, cmd/link.
     6  //
     7  // This package is similar to cmd/internal/objfile which also reads
     8  // Go object files.
     9  package objfile
    10  
    11  import (
    12  	"bufio"
    13  	"bytes"
    14  	"github.com/gagliardetto/golang-go/cmd/internal/bio"
    15  	"github.com/gagliardetto/golang-go/cmd/internal/dwarf"
    16  	"github.com/gagliardetto/golang-go/cmd/internal/obj"
    17  	"github.com/gagliardetto/golang-go/cmd/internal/objabi"
    18  	"github.com/gagliardetto/golang-go/cmd/internal/sys"
    19  	"github.com/gagliardetto/golang-go/cmd/link/internal/sym"
    20  	"fmt"
    21  	"io"
    22  	"log"
    23  	"os"
    24  	"strconv"
    25  	"strings"
    26  	"unsafe"
    27  )
    28  
    29  const (
    30  	startmagic = "\x00go114ld"
    31  	endmagic   = "\xffgo114ld"
    32  )
    33  
    34  var emptyPkg = []byte(`"".`)
    35  
    36  // objReader reads Go object files.
    37  type objReader struct {
    38  	rd              *bio.Reader
    39  	arch            *sys.Arch
    40  	syms            *sym.Symbols
    41  	lib             *sym.Library
    42  	unit            *sym.CompilationUnit
    43  	pn              string
    44  	dupSym          *sym.Symbol
    45  	localSymVersion int
    46  	flags           int
    47  	strictDupMsgs   int
    48  	dataSize        int
    49  
    50  	// rdBuf is used by readString and readSymName as scratch for reading strings.
    51  	rdBuf []byte
    52  
    53  	// List of symbol references for the file being read.
    54  	refs        []*sym.Symbol
    55  	data        []byte
    56  	reloc       []sym.Reloc
    57  	pcdata      []sym.Pcdata
    58  	funcdata    []*sym.Symbol
    59  	funcdataoff []int64
    60  	file        []*sym.Symbol
    61  	pkgpref     string // objabi.PathToPrefix(r.lib.Pkg) + "."
    62  
    63  	roObject []byte // from read-only mmap of object file (may be nil)
    64  	roOffset int64  // offset into readonly object data examined so far
    65  
    66  	dataReadOnly bool // whether data is backed by read-only memory
    67  }
    68  
    69  // Flags to enable optional behavior during object loading/reading.
    70  
    71  const (
    72  	NoFlag int = iota
    73  
    74  	// Sanity-check duplicate symbol contents, issuing warning
    75  	// when duplicates have different lengths or contents.
    76  	StrictDupsWarnFlag
    77  
    78  	// Similar to StrictDupsWarnFlag, but issue fatal error.
    79  	StrictDupsErrFlag
    80  )
    81  
    82  // Load loads an object file f into library lib.
    83  // The symbols loaded are added to syms.
    84  func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, lib *sym.Library, unit *sym.CompilationUnit, length int64, pn string, flags int) int {
    85  	start := f.Offset()
    86  	roObject := f.SliceRO(uint64(length))
    87  	if roObject != nil {
    88  		f.MustSeek(int64(-length), os.SEEK_CUR)
    89  	}
    90  	r := &objReader{
    91  		rd:              f,
    92  		lib:             lib,
    93  		unit:            unit,
    94  		arch:            arch,
    95  		syms:            syms,
    96  		pn:              pn,
    97  		dupSym:          &sym.Symbol{Name: ".dup"},
    98  		localSymVersion: syms.IncVersion(),
    99  		flags:           flags,
   100  		roObject:        roObject,
   101  		pkgpref:         objabi.PathToPrefix(lib.Pkg) + ".",
   102  	}
   103  	r.loadObjFile()
   104  	if roObject != nil {
   105  		if r.roOffset != length {
   106  			log.Fatalf("%s: unexpected end at %d, want %d", pn, r.roOffset, start+length)
   107  		}
   108  		r.rd.MustSeek(int64(length), os.SEEK_CUR)
   109  	} else if f.Offset() != start+length {
   110  		log.Fatalf("%s: unexpected end at %d, want %d", pn, f.Offset(), start+length)
   111  	}
   112  	return r.strictDupMsgs
   113  }
   114  
   115  func (r *objReader) loadObjFile() {
   116  	// Magic header
   117  	var buf [8]uint8
   118  	r.readFull(buf[:])
   119  	if string(buf[:]) != startmagic {
   120  		log.Fatalf("%s: invalid file start %x %x %x %x %x %x %x %x", r.pn, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7])
   121  	}
   122  
   123  	// Version
   124  	c, err := r.readByte()
   125  	if err != nil || c != 1 {
   126  		log.Fatalf("%s: invalid file version number %d", r.pn, c)
   127  	}
   128  
   129  	// Autolib
   130  	for {
   131  		lib := r.readString()
   132  		if lib == "" {
   133  			break
   134  		}
   135  		r.lib.ImportStrings = append(r.lib.ImportStrings, lib)
   136  	}
   137  
   138  	// DWARF strings
   139  	count := r.readInt()
   140  	r.unit.DWARFFileTable = make([]string, count)
   141  	for i := 0; i < count; i++ {
   142  		// TODO: This should probably be a call to mkROString.
   143  		r.unit.DWARFFileTable[i] = r.readString()
   144  	}
   145  
   146  	// Symbol references
   147  	r.refs = []*sym.Symbol{nil} // zeroth ref is nil
   148  	for {
   149  		c, err := r.peek(1)
   150  		if err != nil {
   151  			log.Fatalf("%s: peeking: %v", r.pn, err)
   152  		}
   153  		if c[0] == 0xff {
   154  			r.readByte()
   155  			break
   156  		}
   157  		r.readRef()
   158  	}
   159  
   160  	// Lengths
   161  	r.readSlices()
   162  
   163  	// Data section
   164  	err = r.readDataSection()
   165  	if err != nil {
   166  		log.Fatalf("%s: error reading %s", r.pn, err)
   167  	}
   168  
   169  	// Defined symbols
   170  	for {
   171  		c, err := r.peek(1)
   172  		if err != nil {
   173  			log.Fatalf("%s: peeking: %v", r.pn, err)
   174  		}
   175  		if c[0] == 0xff {
   176  			break
   177  		}
   178  		r.readSym()
   179  	}
   180  
   181  	// Magic footer
   182  	buf = [8]uint8{}
   183  	r.readFull(buf[:])
   184  	if string(buf[:]) != endmagic {
   185  		log.Fatalf("%s: invalid file end", r.pn)
   186  	}
   187  }
   188  
   189  func (r *objReader) readSlices() {
   190  	r.dataSize = r.readInt()
   191  	n := r.readInt()
   192  	r.reloc = make([]sym.Reloc, n)
   193  	n = r.readInt()
   194  	r.pcdata = make([]sym.Pcdata, n)
   195  	_ = r.readInt() // TODO: remove on next object file rev (autom count)
   196  	n = r.readInt()
   197  	r.funcdata = make([]*sym.Symbol, n)
   198  	r.funcdataoff = make([]int64, n)
   199  	n = r.readInt()
   200  	r.file = make([]*sym.Symbol, n)
   201  }
   202  
   203  func (r *objReader) readDataSection() (err error) {
   204  	if r.roObject != nil {
   205  		r.data, r.dataReadOnly, err =
   206  			r.roObject[r.roOffset:r.roOffset+int64(r.dataSize)], true, nil
   207  		r.roOffset += int64(r.dataSize)
   208  		return
   209  	}
   210  	r.data, r.dataReadOnly, err = r.rd.Slice(uint64(r.dataSize))
   211  	return
   212  }
   213  
   214  // Symbols are prefixed so their content doesn't get confused with the magic footer.
   215  const symPrefix = 0xfe
   216  
   217  func (r *objReader) readSym() {
   218  	var c byte
   219  	var err error
   220  	if c, err = r.readByte(); c != symPrefix || err != nil {
   221  		log.Fatalln("readSym out of sync")
   222  	}
   223  	if c, err = r.readByte(); err != nil {
   224  		log.Fatalln("error reading input: ", err)
   225  	}
   226  	t := sym.AbiSymKindToSymKind[c]
   227  	s := r.readSymIndex()
   228  	flags := r.readInt()
   229  	dupok := flags&1 != 0
   230  	local := flags&2 != 0
   231  	makeTypelink := flags&4 != 0
   232  	size := r.readInt()
   233  	typ := r.readSymIndex()
   234  	data := r.readData()
   235  	nreloc := r.readInt()
   236  	isdup := false
   237  
   238  	var dup *sym.Symbol
   239  	if s.Type != 0 && s.Type != sym.SXREF {
   240  		if (t == sym.SDATA || t == sym.SBSS || t == sym.SNOPTRBSS) && len(data) == 0 && nreloc == 0 {
   241  			if s.Size < int64(size) {
   242  				s.Size = int64(size)
   243  			}
   244  			if typ != nil && s.Gotype == nil {
   245  				s.Gotype = typ
   246  			}
   247  			return
   248  		}
   249  
   250  		if (s.Type == sym.SDATA || s.Type == sym.SBSS || s.Type == sym.SNOPTRBSS) && len(s.P) == 0 && len(s.R) == 0 {
   251  			goto overwrite
   252  		}
   253  		if s.Type != sym.SBSS && s.Type != sym.SNOPTRBSS && !dupok && !s.Attr.DuplicateOK() {
   254  			log.Fatalf("duplicate symbol %s (types %d and %d) in %s and %s", s.Name, s.Type, t, s.File, r.pn)
   255  		}
   256  		if len(s.P) > 0 {
   257  			dup = s
   258  			s = r.dupSym
   259  			isdup = true
   260  		}
   261  	}
   262  
   263  overwrite:
   264  	s.File = r.pkgpref[:len(r.pkgpref)-1]
   265  	s.Unit = r.unit
   266  	if dupok {
   267  		s.Attr |= sym.AttrDuplicateOK
   268  	}
   269  	if t == sym.SXREF {
   270  		log.Fatalf("bad sxref")
   271  	}
   272  	if t == 0 {
   273  		log.Fatalf("missing type for %s in %s", s.Name, r.pn)
   274  	}
   275  	if t == sym.SBSS && (s.Type == sym.SRODATA || s.Type == sym.SNOPTRBSS) {
   276  		t = s.Type
   277  	}
   278  	s.Type = t
   279  	if s.Size < int64(size) {
   280  		s.Size = int64(size)
   281  	}
   282  	s.Attr.Set(sym.AttrLocal, local)
   283  	s.Attr.Set(sym.AttrMakeTypelink, makeTypelink)
   284  	if typ != nil {
   285  		s.Gotype = typ
   286  	}
   287  	if isdup && typ != nil { // if bss sym defined multiple times, take type from any one def
   288  		dup.Gotype = typ
   289  	}
   290  	s.P = data
   291  	s.Attr.Set(sym.AttrReadOnly, r.dataReadOnly)
   292  	if nreloc > 0 {
   293  		s.R = r.reloc[:nreloc:nreloc]
   294  		if !isdup {
   295  			r.reloc = r.reloc[nreloc:]
   296  		}
   297  
   298  		for i := 0; i < nreloc; i++ {
   299  			s.R[i] = sym.Reloc{
   300  				Off:  r.readInt32(),
   301  				Siz:  r.readUint8(),
   302  				Type: objabi.RelocType(r.readInt32()),
   303  				Add:  r.readInt64(),
   304  				Sym:  r.readSymIndex(),
   305  			}
   306  		}
   307  	}
   308  
   309  	if s.Type == sym.STEXT {
   310  		s.FuncInfo = new(sym.FuncInfo)
   311  		pc := s.FuncInfo
   312  
   313  		pc.Args = r.readInt32()
   314  		pc.Locals = r.readInt32()
   315  		if r.readUint8() != 0 {
   316  			s.Attr |= sym.AttrNoSplit
   317  		}
   318  		flags := r.readInt()
   319  		if flags&(1<<2) != 0 {
   320  			s.Attr |= sym.AttrReflectMethod
   321  		}
   322  		if flags&(1<<3) != 0 {
   323  			s.Attr |= sym.AttrShared
   324  		}
   325  		if flags&(1<<4) != 0 {
   326  			s.Attr |= sym.AttrTopFrame
   327  		}
   328  		n := r.readInt()
   329  		if n != 0 {
   330  			log.Fatalf("stale object file: autom count nonzero")
   331  		}
   332  
   333  		pc.Pcsp.P = r.readData()
   334  		pc.Pcfile.P = r.readData()
   335  		pc.Pcline.P = r.readData()
   336  		pc.Pcinline.P = r.readData()
   337  		n = r.readInt()
   338  		pc.Pcdata = r.pcdata[:n:n]
   339  		if !isdup {
   340  			r.pcdata = r.pcdata[n:]
   341  		}
   342  		for i := 0; i < n; i++ {
   343  			pc.Pcdata[i].P = r.readData()
   344  		}
   345  		n = r.readInt()
   346  		pc.Funcdata = r.funcdata[:n:n]
   347  		pc.Funcdataoff = r.funcdataoff[:n:n]
   348  		if !isdup {
   349  			r.funcdata = r.funcdata[n:]
   350  			r.funcdataoff = r.funcdataoff[n:]
   351  		}
   352  		for i := 0; i < n; i++ {
   353  			pc.Funcdata[i] = r.readSymIndex()
   354  		}
   355  		for i := 0; i < n; i++ {
   356  			pc.Funcdataoff[i] = r.readInt64()
   357  		}
   358  		n = r.readInt()
   359  		pc.File = r.file[:n:n]
   360  		if !isdup {
   361  			r.file = r.file[n:]
   362  		}
   363  		for i := 0; i < n; i++ {
   364  			pc.File[i] = r.readSymIndex()
   365  		}
   366  		n = r.readInt()
   367  		pc.InlTree = make([]sym.InlinedCall, n)
   368  		for i := 0; i < n; i++ {
   369  			pc.InlTree[i].Parent = r.readInt32()
   370  			pc.InlTree[i].File = r.readSymIndex()
   371  			pc.InlTree[i].Line = r.readInt32()
   372  			pc.InlTree[i].Func = r.readSymIndex().Name
   373  			pc.InlTree[i].ParentPC = r.readInt32()
   374  		}
   375  
   376  		if !dupok {
   377  			if s.Attr.OnList() {
   378  				log.Fatalf("symbol %s listed multiple times", s.Name)
   379  			}
   380  			s.Attr |= sym.AttrOnList
   381  			r.lib.Textp = append(r.lib.Textp, s)
   382  		} else {
   383  			// there may ba a dup in another package
   384  			// put into a temp list and add to text later
   385  			if !isdup {
   386  				r.lib.DupTextSyms = append(r.lib.DupTextSyms, s)
   387  			} else {
   388  				r.lib.DupTextSyms = append(r.lib.DupTextSyms, dup)
   389  			}
   390  		}
   391  	}
   392  	if s.Type == sym.SDWARFINFO {
   393  		r.patchDWARFName(s)
   394  	}
   395  
   396  	if isdup && r.flags&(StrictDupsWarnFlag|StrictDupsErrFlag) != 0 {
   397  		// Compare the just-read symbol with the previously read
   398  		// symbol of the same name, verifying that they have the same
   399  		// payload. If not, issue a warning and possibly an error.
   400  		if !bytes.Equal(s.P, dup.P) {
   401  			reason := "same length but different contents"
   402  			if len(s.P) != len(dup.P) {
   403  				reason = fmt.Sprintf("new length %d != old length %d",
   404  					len(data), len(dup.P))
   405  			}
   406  			fmt.Fprintf(os.Stderr, "github.com/gagliardetto/golang-go/cmd/link: while reading object for '%v': duplicate symbol '%s', previous def at '%v', with mismatched payload: %s\n", r.lib, dup, dup.Unit.Lib, reason)
   407  
   408  			// For the moment, whitelist DWARF subprogram DIEs for
   409  			// auto-generated wrapper functions. What seems to happen
   410  			// here is that we get different line numbers on formal
   411  			// params; I am guessing that the pos is being inherited
   412  			// from the spot where the wrapper is needed.
   413  			whitelist := (strings.HasPrefix(dup.Name, "go.info.go.interface") ||
   414  				strings.HasPrefix(dup.Name, "go.info.go.builtin") ||
   415  				strings.HasPrefix(dup.Name, "go.isstmt.go.builtin") ||
   416  				strings.HasPrefix(dup.Name, "go.debuglines"))
   417  			if !whitelist {
   418  				r.strictDupMsgs++
   419  			}
   420  		}
   421  	}
   422  }
   423  
   424  func (r *objReader) patchDWARFName(s *sym.Symbol) {
   425  	// This is kind of ugly. Really the package name should not
   426  	// even be included here.
   427  	if s.Size < 1 || s.P[0] != dwarf.DW_ABRV_FUNCTION {
   428  		return
   429  	}
   430  	e := bytes.IndexByte(s.P, 0)
   431  	if e == -1 {
   432  		return
   433  	}
   434  	p := bytes.Index(s.P[:e], emptyPkg)
   435  	if p == -1 {
   436  		return
   437  	}
   438  	pkgprefix := []byte(r.pkgpref)
   439  	patched := bytes.Replace(s.P[:e], emptyPkg, pkgprefix, -1)
   440  
   441  	s.P = append(patched, s.P[e:]...)
   442  	delta := int64(len(s.P)) - s.Size
   443  	s.Size = int64(len(s.P))
   444  	for i := range s.R {
   445  		r := &s.R[i]
   446  		if r.Off > int32(e) {
   447  			r.Off += int32(delta)
   448  		}
   449  	}
   450  }
   451  
   452  func (r *objReader) readFull(b []byte) {
   453  	if r.roObject != nil {
   454  		copy(b, r.roObject[r.roOffset:])
   455  		r.roOffset += int64(len(b))
   456  		return
   457  	}
   458  	_, err := io.ReadFull(r.rd, b)
   459  	if err != nil {
   460  		log.Fatalf("%s: error reading %s", r.pn, err)
   461  	}
   462  }
   463  
   464  func (r *objReader) readByte() (byte, error) {
   465  	if r.roObject != nil {
   466  		b := r.roObject[r.roOffset]
   467  		r.roOffset++
   468  		return b, nil
   469  	}
   470  	return r.rd.ReadByte()
   471  }
   472  
   473  func (r *objReader) peek(n int) ([]byte, error) {
   474  	if r.roObject != nil {
   475  		return r.roObject[r.roOffset : r.roOffset+int64(n)], nil
   476  	}
   477  	return r.rd.Peek(n)
   478  }
   479  
   480  func (r *objReader) readRef() {
   481  	if c, err := r.readByte(); c != symPrefix || err != nil {
   482  		log.Fatalf("readSym out of sync")
   483  	}
   484  	name := r.readSymName()
   485  	var v int
   486  	if abi := r.readInt(); abi == -1 {
   487  		// Static
   488  		v = r.localSymVersion
   489  	} else if abiver := sym.ABIToVersion(obj.ABI(abi)); abiver != -1 {
   490  		// Note that data symbols are "ABI0", which maps to version 0.
   491  		v = abiver
   492  	} else {
   493  		log.Fatalf("invalid symbol ABI for %q: %d", name, abi)
   494  	}
   495  	s := r.syms.Lookup(name, v)
   496  	r.refs = append(r.refs, s)
   497  
   498  	if s == nil || v == r.localSymVersion {
   499  		return
   500  	}
   501  	if s.Name[0] == '$' && len(s.Name) > 5 && s.Type == 0 && len(s.P) == 0 {
   502  		x, err := strconv.ParseUint(s.Name[5:], 16, 64)
   503  		if err != nil {
   504  			log.Panicf("failed to parse $-symbol %s: %v", s.Name, err)
   505  		}
   506  		s.Type = sym.SRODATA
   507  		s.Attr |= sym.AttrLocal
   508  		switch s.Name[:5] {
   509  		case "$f32.":
   510  			if uint64(uint32(x)) != x {
   511  				log.Panicf("$-symbol %s too large: %d", s.Name, x)
   512  			}
   513  			s.AddUint32(r.arch, uint32(x))
   514  		case "$f64.", "$i64.":
   515  			s.AddUint64(r.arch, x)
   516  		default:
   517  			log.Panicf("unrecognized $-symbol: %s", s.Name)
   518  		}
   519  		s.Attr.Set(sym.AttrReachable, false)
   520  	}
   521  	if strings.HasPrefix(s.Name, "runtime.gcbits.") {
   522  		s.Attr |= sym.AttrLocal
   523  	}
   524  }
   525  
   526  func (r *objReader) readInt64() int64 {
   527  	uv := uint64(0)
   528  	for shift := uint(0); ; shift += 7 {
   529  		if shift >= 64 {
   530  			log.Fatalf("corrupt input")
   531  		}
   532  		c, err := r.readByte()
   533  		if err != nil {
   534  			log.Fatalln("error reading input: ", err)
   535  		}
   536  		uv |= uint64(c&0x7F) << shift
   537  		if c&0x80 == 0 {
   538  			break
   539  		}
   540  	}
   541  
   542  	return int64(uv>>1) ^ (int64(uv<<63) >> 63)
   543  }
   544  
   545  func (r *objReader) readInt() int {
   546  	n := r.readInt64()
   547  	if int64(int(n)) != n {
   548  		log.Panicf("%v out of range for int", n)
   549  	}
   550  	return int(n)
   551  }
   552  
   553  func (r *objReader) readInt32() int32 {
   554  	n := r.readInt64()
   555  	if int64(int32(n)) != n {
   556  		log.Panicf("%v out of range for int32", n)
   557  	}
   558  	return int32(n)
   559  }
   560  
   561  func (r *objReader) readInt16() int16 {
   562  	n := r.readInt64()
   563  	if int64(int16(n)) != n {
   564  		log.Panicf("%v out of range for int16", n)
   565  	}
   566  	return int16(n)
   567  }
   568  
   569  func (r *objReader) readUint8() uint8 {
   570  	n := r.readInt64()
   571  	if int64(uint8(n)) != n {
   572  		log.Panicf("%v out of range for uint8", n)
   573  	}
   574  	return uint8(n)
   575  }
   576  
   577  func (r *objReader) readString() string {
   578  	n := r.readInt()
   579  	if cap(r.rdBuf) < n {
   580  		r.rdBuf = make([]byte, 2*n)
   581  	}
   582  	r.readFull(r.rdBuf[:n])
   583  	return string(r.rdBuf[:n])
   584  }
   585  
   586  func (r *objReader) readData() []byte {
   587  	n := r.readInt()
   588  	p := r.data[:n:n]
   589  	r.data = r.data[n:]
   590  	return p
   591  }
   592  
   593  type stringHeader struct {
   594  	str unsafe.Pointer
   595  	len int
   596  }
   597  
   598  func mkROString(rodata []byte) string {
   599  	if len(rodata) == 0 {
   600  		return ""
   601  	}
   602  	ss := stringHeader{str: unsafe.Pointer(&rodata[0]), len: len(rodata)}
   603  	s := *(*string)(unsafe.Pointer(&ss))
   604  	return s
   605  }
   606  
   607  // readSymName reads a symbol name, replacing all "". with pkg.
   608  func (r *objReader) readSymName() string {
   609  	n := r.readInt()
   610  	if n == 0 {
   611  		r.readInt64()
   612  		return ""
   613  	}
   614  	if cap(r.rdBuf) < n {
   615  		r.rdBuf = make([]byte, 2*n)
   616  	}
   617  	sOffset := r.roOffset
   618  	origName, err := r.peek(n)
   619  	if err == bufio.ErrBufferFull {
   620  		// Long symbol names are rare but exist. One source is type
   621  		// symbols for types with long string forms. See #15104.
   622  		origName = make([]byte, n)
   623  		r.readFull(origName)
   624  	} else if err != nil {
   625  		log.Fatalf("%s: error reading symbol: %v", r.pn, err)
   626  	}
   627  	adjName := r.rdBuf[:0]
   628  	nPkgRefs := 0
   629  	for {
   630  		i := bytes.Index(origName, emptyPkg)
   631  		if i == -1 {
   632  			var s string
   633  			if r.roObject != nil && nPkgRefs == 0 {
   634  				s = mkROString(r.roObject[sOffset : sOffset+int64(n)])
   635  			} else {
   636  				s = string(append(adjName, origName...))
   637  			}
   638  			// Read past the peeked origName, now that we're done with it,
   639  			// using the rfBuf (also no longer used) as the scratch space.
   640  			// TODO: use bufio.Reader.Discard if available instead?
   641  			if err == nil {
   642  				r.readFull(r.rdBuf[:n])
   643  			}
   644  			r.rdBuf = adjName[:0] // in case 2*n wasn't enough
   645  			return s
   646  		}
   647  		nPkgRefs++
   648  		adjName = append(adjName, origName[:i]...)
   649  		adjName = append(adjName, r.pkgpref[:len(r.pkgpref)-1]...)
   650  		adjName = append(adjName, '.')
   651  		origName = origName[i+len(emptyPkg):]
   652  	}
   653  }
   654  
   655  // Reads the index of a symbol reference and resolves it to a symbol
   656  func (r *objReader) readSymIndex() *sym.Symbol {
   657  	i := r.readInt()
   658  	return r.refs[i]
   659  }