github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/src/cmd/internal/obj/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  // Writing of Go object files.
     6  //
     7  // Originally, Go object files were Plan 9 object files, but no longer.
     8  // Now they are more like standard object files, in that each symbol is defined
     9  // by an associated memory image (bytes) and a list of relocations to apply
    10  // during linking. We do not (yet?) use a standard file format, however.
    11  // For now, the format is chosen to be as simple as possible to read and write.
    12  // It may change for reasons of efficiency, or we may even switch to a
    13  // standard file format if there are compelling benefits to doing so.
    14  // See golang.org/s/go13linker for more background.
    15  //
    16  // The file format is:
    17  //
    18  //	- magic header: "\x00\x00go13ld"
    19  //	- byte 1 - version number
    20  //	- sequence of strings giving dependencies (imported packages)
    21  //	- empty string (marks end of sequence)
    22  //	- sequence of symbol references used by the defined symbols
    23  //	- byte 0xff (marks end of sequence)
    24  //	- sequence of integer lengths:
    25  //		- total data length
    26  //		- total number of relocations
    27  //		- total number of pcdata
    28  //		- total number of automatics
    29  //		- total number of funcdata
    30  //		- total number of files
    31  //	- data, the content of the defined symbols
    32  //	- sequence of defined symbols
    33  //	- byte 0xff (marks end of sequence)
    34  //	- magic footer: "\xff\xffgo13ld"
    35  //
    36  // All integers are stored in a zigzag varint format.
    37  // See golang.org/s/go12symtab for a definition.
    38  //
    39  // Data blocks and strings are both stored as an integer
    40  // followed by that many bytes.
    41  //
    42  // A symbol reference is a string name followed by a version.
    43  //
    44  // A symbol points to other symbols using an index into the symbol
    45  // reference sequence. Index 0 corresponds to a nil LSym* pointer.
    46  // In the symbol layout described below "symref index" stands for this
    47  // index.
    48  //
    49  // Each symbol is laid out as the following fields (taken from LSym*):
    50  //
    51  //	- byte 0xfe (sanity check for synchronization)
    52  //	- type [int]
    53  //	- name & version [symref index]
    54  //	- flags [int]
    55  //		1 dupok
    56  //	- size [int]
    57  //	- gotype [symref index]
    58  //	- p [data block]
    59  //	- nr [int]
    60  //	- r [nr relocations, sorted by off]
    61  //
    62  // If type == STEXT, there are a few more fields:
    63  //
    64  //	- args [int]
    65  //	- locals [int]
    66  //	- nosplit [int]
    67  //	- flags [int]
    68  //		1<<0 leaf
    69  //		1<<1 C function
    70  //		1<<2 function may call reflect.Type.Method
    71  //	- nlocal [int]
    72  //	- local [nlocal automatics]
    73  //	- pcln [pcln table]
    74  //
    75  // Each relocation has the encoding:
    76  //
    77  //	- off [int]
    78  //	- siz [int]
    79  //	- type [int]
    80  //	- add [int]
    81  //	- sym [symref index]
    82  //
    83  // Each local has the encoding:
    84  //
    85  //	- asym [symref index]
    86  //	- offset [int]
    87  //	- type [int]
    88  //	- gotype [symref index]
    89  //
    90  // The pcln table has the encoding:
    91  //
    92  //	- pcsp [data block]
    93  //	- pcfile [data block]
    94  //	- pcline [data block]
    95  //	- npcdata [int]
    96  //	- pcdata [npcdata data blocks]
    97  //	- nfuncdata [int]
    98  //	- funcdata [nfuncdata symref index]
    99  //	- funcdatasym [nfuncdata ints]
   100  //	- nfile [int]
   101  //	- file [nfile symref index]
   102  //
   103  // The file layout and meaning of type integers are architecture-independent.
   104  //
   105  // TODO(rsc): The file format is good for a first pass but needs work.
   106  //	- There are SymID in the object file that should really just be strings.
   107  
   108  package obj
   109  
   110  import (
   111  	"bufio"
   112  	"fmt"
   113  	"log"
   114  	"path/filepath"
   115  	"sort"
   116  	"strings"
   117  )
   118  
   119  // The Go and C compilers, and the assembler, call writeobj to write
   120  // out a Go object file. The linker does not call this; the linker
   121  // does not write out object files.
   122  func Writeobjdirect(ctxt *Link, b *Biobuf) {
   123  	Flushplist(ctxt)
   124  	WriteObjFile(ctxt, b)
   125  }
   126  
   127  func Flushplist(ctxt *Link) {
   128  	flushplist(ctxt, ctxt.Debugasm == 0)
   129  }
   130  func FlushplistNoFree(ctxt *Link) {
   131  	flushplist(ctxt, false)
   132  }
   133  func flushplist(ctxt *Link, freeProgs bool) {
   134  	// Build list of symbols, and assign instructions to lists.
   135  	// Ignore ctxt->plist boundaries. There are no guarantees there,
   136  	// and the assemblers just use one big list.
   137  	var curtext *LSym
   138  	var etext *Prog
   139  	var text []*LSym
   140  
   141  	for pl := ctxt.Plist; pl != nil; pl = pl.Link {
   142  		var plink *Prog
   143  		for p := pl.Firstpc; p != nil; p = plink {
   144  			if ctxt.Debugasm != 0 && ctxt.Debugvlog != 0 {
   145  				fmt.Printf("obj: %v\n", p)
   146  			}
   147  			plink = p.Link
   148  			p.Link = nil
   149  
   150  			switch p.As {
   151  			case AEND:
   152  				continue
   153  
   154  			case ATYPE:
   155  				// Assume each TYPE instruction describes
   156  				// a different local variable or parameter,
   157  				// so no dedup.
   158  				// Using only the TYPE instructions means
   159  				// that we discard location information about local variables
   160  				// in C and assembly functions; that information is inferred
   161  				// from ordinary references, because there are no TYPE
   162  				// instructions there. Without the type information, gdb can't
   163  				// use the locations, so we don't bother to save them.
   164  				// If something else could use them, we could arrange to
   165  				// preserve them.
   166  				if curtext == nil {
   167  					continue
   168  				}
   169  				a := new(Auto)
   170  				a.Asym = p.From.Sym
   171  				a.Aoffset = int32(p.From.Offset)
   172  				a.Name = int16(p.From.Name)
   173  				a.Gotype = p.From.Gotype
   174  				a.Link = curtext.Autom
   175  				curtext.Autom = a
   176  				continue
   177  
   178  			case AGLOBL:
   179  				s := p.From.Sym
   180  				if s.Seenglobl {
   181  					fmt.Printf("duplicate %v\n", p)
   182  				}
   183  				s.Seenglobl = true
   184  				if s.Onlist {
   185  					log.Fatalf("symbol %s listed multiple times", s.Name)
   186  				}
   187  				s.Onlist = true
   188  				ctxt.Data = append(ctxt.Data, s)
   189  				s.Size = p.To.Offset
   190  				if s.Type == 0 || s.Type == SXREF {
   191  					s.Type = SBSS
   192  				}
   193  				flag := int(p.From3.Offset)
   194  				if flag&DUPOK != 0 {
   195  					s.Dupok = true
   196  				}
   197  				if flag&RODATA != 0 {
   198  					s.Type = SRODATA
   199  				} else if flag&NOPTR != 0 {
   200  					s.Type = SNOPTRBSS
   201  				} else if flag&TLSBSS != 0 {
   202  					s.Type = STLSBSS
   203  				}
   204  				continue
   205  
   206  			case ATEXT:
   207  				s := p.From.Sym
   208  				if s == nil {
   209  					// func _() { }
   210  					curtext = nil
   211  
   212  					continue
   213  				}
   214  
   215  				if s.Text != nil {
   216  					log.Fatalf("duplicate TEXT for %s", s.Name)
   217  				}
   218  				if s.Onlist {
   219  					log.Fatalf("symbol %s listed multiple times", s.Name)
   220  				}
   221  				s.Onlist = true
   222  				text = append(text, s)
   223  				flag := int(p.From3Offset())
   224  				if flag&DUPOK != 0 {
   225  					s.Dupok = true
   226  				}
   227  				if flag&NOSPLIT != 0 {
   228  					s.Nosplit = true
   229  				}
   230  				if flag&REFLECTMETHOD != 0 {
   231  					s.ReflectMethod = true
   232  				}
   233  				s.Type = STEXT
   234  				s.Text = p
   235  				etext = p
   236  				curtext = s
   237  				continue
   238  
   239  			case AFUNCDATA:
   240  				// Rewrite reference to go_args_stackmap(SB) to the Go-provided declaration information.
   241  				if curtext == nil { // func _() {}
   242  					continue
   243  				}
   244  				if p.To.Sym.Name == "go_args_stackmap" {
   245  					if p.From.Type != TYPE_CONST || p.From.Offset != FUNCDATA_ArgsPointerMaps {
   246  						ctxt.Diag("FUNCDATA use of go_args_stackmap(SB) without FUNCDATA_ArgsPointerMaps")
   247  					}
   248  					p.To.Sym = Linklookup(ctxt, fmt.Sprintf("%s.args_stackmap", curtext.Name), int(curtext.Version))
   249  				}
   250  
   251  			}
   252  
   253  			if curtext == nil {
   254  				etext = nil
   255  				continue
   256  			}
   257  			etext.Link = p
   258  			etext = p
   259  		}
   260  	}
   261  
   262  	// Add reference to Go arguments for C or assembly functions without them.
   263  	for _, s := range text {
   264  		if !strings.HasPrefix(s.Name, "\"\".") {
   265  			continue
   266  		}
   267  		found := false
   268  		var p *Prog
   269  		for p = s.Text; p != nil; p = p.Link {
   270  			if p.As == AFUNCDATA && p.From.Type == TYPE_CONST && p.From.Offset == FUNCDATA_ArgsPointerMaps {
   271  				found = true
   272  				break
   273  			}
   274  		}
   275  
   276  		if !found {
   277  			p = Appendp(ctxt, s.Text)
   278  			p.As = AFUNCDATA
   279  			p.From.Type = TYPE_CONST
   280  			p.From.Offset = FUNCDATA_ArgsPointerMaps
   281  			p.To.Type = TYPE_MEM
   282  			p.To.Name = NAME_EXTERN
   283  			p.To.Sym = Linklookup(ctxt, fmt.Sprintf("%s.args_stackmap", s.Name), int(s.Version))
   284  		}
   285  	}
   286  
   287  	// Turn functions into machine code images.
   288  	for _, s := range text {
   289  		mkfwd(s)
   290  		linkpatch(ctxt, s)
   291  		if ctxt.Flag_optimize {
   292  			ctxt.Arch.Follow(ctxt, s)
   293  		}
   294  		ctxt.Arch.Preprocess(ctxt, s)
   295  		ctxt.Arch.Assemble(ctxt, s)
   296  		fieldtrack(ctxt, s)
   297  		linkpcln(ctxt, s)
   298  		if freeProgs {
   299  			s.Text = nil
   300  		}
   301  	}
   302  
   303  	// Add to running list in ctxt.
   304  	ctxt.Text = append(ctxt.Text, text...)
   305  	ctxt.Plist = nil
   306  	ctxt.Plast = nil
   307  	ctxt.Curp = nil
   308  	if freeProgs {
   309  		ctxt.freeProgs()
   310  	}
   311  }
   312  
   313  // objWriter writes Go object files.
   314  type objWriter struct {
   315  	wr   *bufio.Writer
   316  	ctxt *Link
   317  	// Temporary buffer for zigzag int writing.
   318  	varintbuf [10]uint8
   319  
   320  	// Provide the the index of a symbol reference by symbol name.
   321  	// One map for versioned symbols and one for unversioned symbols.
   322  	// Used for deduplicating the symbol reference list.
   323  	refIdx  map[string]int
   324  	vrefIdx map[string]int
   325  
   326  	// Number of objects written of each type.
   327  	nRefs     int
   328  	nData     int
   329  	nReloc    int
   330  	nPcdata   int
   331  	nAutom    int
   332  	nFuncdata int
   333  	nFile     int
   334  }
   335  
   336  func (w *objWriter) addLengths(s *LSym) {
   337  	w.nData += len(s.P)
   338  	w.nReloc += len(s.R)
   339  
   340  	if s.Type != STEXT {
   341  		return
   342  	}
   343  
   344  	pc := s.Pcln
   345  
   346  	data := 0
   347  	data += len(pc.Pcsp.P)
   348  	data += len(pc.Pcfile.P)
   349  	data += len(pc.Pcline.P)
   350  	for i := 0; i < len(pc.Pcdata); i++ {
   351  		data += len(pc.Pcdata[i].P)
   352  	}
   353  
   354  	w.nData += data
   355  	w.nPcdata += len(pc.Pcdata)
   356  
   357  	autom := 0
   358  	for a := s.Autom; a != nil; a = a.Link {
   359  		autom++
   360  	}
   361  	w.nAutom += autom
   362  	w.nFuncdata += len(pc.Funcdataoff)
   363  	w.nFile += len(pc.File)
   364  }
   365  
   366  func (w *objWriter) writeLengths() {
   367  	w.writeInt(int64(w.nData))
   368  	w.writeInt(int64(w.nReloc))
   369  	w.writeInt(int64(w.nPcdata))
   370  	w.writeInt(int64(w.nAutom))
   371  	w.writeInt(int64(w.nFuncdata))
   372  	w.writeInt(int64(w.nFile))
   373  }
   374  
   375  func newObjWriter(ctxt *Link, b *Biobuf) *objWriter {
   376  	return &objWriter{
   377  		ctxt:    ctxt,
   378  		wr:      b.w,
   379  		vrefIdx: make(map[string]int),
   380  		refIdx:  make(map[string]int),
   381  	}
   382  }
   383  
   384  func WriteObjFile(ctxt *Link, b *Biobuf) {
   385  	w := newObjWriter(ctxt, b)
   386  
   387  	// Magic header
   388  	w.wr.WriteString("\x00\x00go13ld")
   389  
   390  	// Version
   391  	w.wr.WriteByte(1)
   392  
   393  	// Autolib
   394  	for _, pkg := range ctxt.Imports {
   395  		w.writeString(pkg)
   396  	}
   397  	w.writeString("")
   398  
   399  	// Symbol references
   400  	for _, s := range ctxt.Text {
   401  		w.writeRefs(s)
   402  		w.addLengths(s)
   403  	}
   404  	for _, s := range ctxt.Data {
   405  		w.writeRefs(s)
   406  		w.addLengths(s)
   407  	}
   408  	// End symbol references
   409  	w.wr.WriteByte(0xff)
   410  
   411  	// Lengths
   412  	w.writeLengths()
   413  
   414  	// Data block
   415  	for _, s := range ctxt.Text {
   416  		w.wr.Write(s.P)
   417  		pc := s.Pcln
   418  		w.wr.Write(pc.Pcsp.P)
   419  		w.wr.Write(pc.Pcfile.P)
   420  		w.wr.Write(pc.Pcline.P)
   421  		for i := 0; i < len(pc.Pcdata); i++ {
   422  			w.wr.Write(pc.Pcdata[i].P)
   423  		}
   424  	}
   425  	for _, s := range ctxt.Data {
   426  		w.wr.Write(s.P)
   427  	}
   428  
   429  	// Symbols
   430  	for _, s := range ctxt.Text {
   431  		w.writeSym(s)
   432  	}
   433  	for _, s := range ctxt.Data {
   434  		w.writeSym(s)
   435  	}
   436  
   437  	// Magic footer
   438  	w.wr.WriteString("\xff\xffgo13ld")
   439  }
   440  
   441  // Symbols are prefixed so their content doesn't get confused with the magic footer.
   442  const symPrefix = 0xfe
   443  
   444  func (w *objWriter) writeRef(s *LSym, isPath bool) {
   445  	if s == nil || s.RefIdx != 0 {
   446  		return
   447  	}
   448  	var m map[string]int
   449  	switch s.Version {
   450  	case 0:
   451  		m = w.refIdx
   452  	case 1:
   453  		m = w.vrefIdx
   454  	default:
   455  		log.Fatalf("%s: invalid version number %d", s.Name, s.Version)
   456  	}
   457  
   458  	idx := m[s.Name]
   459  	if idx != 0 {
   460  		s.RefIdx = idx
   461  		return
   462  	}
   463  	w.wr.WriteByte(symPrefix)
   464  	if isPath {
   465  		w.writeString(filepath.ToSlash(s.Name))
   466  	} else {
   467  		w.writeString(s.Name)
   468  	}
   469  	w.writeInt(int64(s.Version))
   470  	w.nRefs++
   471  	s.RefIdx = w.nRefs
   472  	m[s.Name] = w.nRefs
   473  }
   474  
   475  func (w *objWriter) writeRefs(s *LSym) {
   476  	w.writeRef(s, false)
   477  	w.writeRef(s.Gotype, false)
   478  	for i := range s.R {
   479  		w.writeRef(s.R[i].Sym, false)
   480  	}
   481  
   482  	if s.Type == STEXT {
   483  		for a := s.Autom; a != nil; a = a.Link {
   484  			w.writeRef(a.Asym, false)
   485  			w.writeRef(a.Gotype, false)
   486  		}
   487  		pc := s.Pcln
   488  		for _, d := range pc.Funcdata {
   489  			w.writeRef(d, false)
   490  		}
   491  		for _, f := range pc.File {
   492  			w.writeRef(f, true)
   493  		}
   494  	}
   495  }
   496  
   497  func (w *objWriter) writeSymDebug(s *LSym) {
   498  	ctxt := w.ctxt
   499  	fmt.Fprintf(ctxt.Bso, "%s ", s.Name)
   500  	if s.Version != 0 {
   501  		fmt.Fprintf(ctxt.Bso, "v=%d ", s.Version)
   502  	}
   503  	if s.Type != 0 {
   504  		fmt.Fprintf(ctxt.Bso, "t=%d ", s.Type)
   505  	}
   506  	if s.Dupok {
   507  		fmt.Fprintf(ctxt.Bso, "dupok ")
   508  	}
   509  	if s.Cfunc {
   510  		fmt.Fprintf(ctxt.Bso, "cfunc ")
   511  	}
   512  	if s.Nosplit {
   513  		fmt.Fprintf(ctxt.Bso, "nosplit ")
   514  	}
   515  	fmt.Fprintf(ctxt.Bso, "size=%d", s.Size)
   516  	if s.Type == STEXT {
   517  		fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x", uint64(s.Args), uint64(s.Locals))
   518  		if s.Leaf {
   519  			fmt.Fprintf(ctxt.Bso, " leaf")
   520  		}
   521  	}
   522  
   523  	fmt.Fprintf(ctxt.Bso, "\n")
   524  	for p := s.Text; p != nil; p = p.Link {
   525  		fmt.Fprintf(ctxt.Bso, "\t%#04x %v\n", uint(int(p.Pc)), p)
   526  	}
   527  	var c int
   528  	var j int
   529  	for i := 0; i < len(s.P); {
   530  		fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i))
   531  		for j = i; j < i+16 && j < len(s.P); j++ {
   532  			fmt.Fprintf(ctxt.Bso, " %02x", s.P[j])
   533  		}
   534  		for ; j < i+16; j++ {
   535  			fmt.Fprintf(ctxt.Bso, "   ")
   536  		}
   537  		fmt.Fprintf(ctxt.Bso, "  ")
   538  		for j = i; j < i+16 && j < len(s.P); j++ {
   539  			c = int(s.P[j])
   540  			if ' ' <= c && c <= 0x7e {
   541  				fmt.Fprintf(ctxt.Bso, "%c", c)
   542  			} else {
   543  				fmt.Fprintf(ctxt.Bso, ".")
   544  			}
   545  		}
   546  
   547  		fmt.Fprintf(ctxt.Bso, "\n")
   548  		i += 16
   549  	}
   550  
   551  	sort.Sort(relocByOff(s.R)) // generate stable output
   552  	for _, r := range s.R {
   553  		name := ""
   554  		if r.Sym != nil {
   555  			name = r.Sym.Name
   556  		}
   557  		if ctxt.Arch.Thechar == '5' || ctxt.Arch.Thechar == '9' {
   558  			fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%x\n", int(r.Off), r.Siz, r.Type, name, uint64(int64(r.Add)))
   559  		} else {
   560  			fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, name, int64(r.Add))
   561  		}
   562  	}
   563  }
   564  
   565  func (w *objWriter) writeSym(s *LSym) {
   566  	ctxt := w.ctxt
   567  	if ctxt.Debugasm != 0 {
   568  		w.writeSymDebug(s)
   569  	}
   570  
   571  	w.wr.WriteByte(symPrefix)
   572  	w.writeInt(int64(s.Type))
   573  	w.writeRefIndex(s)
   574  	flags := int64(0)
   575  	if s.Dupok {
   576  		flags |= 1
   577  	}
   578  	if s.Local {
   579  		flags |= 1 << 1
   580  	}
   581  	w.writeInt(flags)
   582  	w.writeInt(s.Size)
   583  	w.writeRefIndex(s.Gotype)
   584  	w.writeInt(int64(len(s.P)))
   585  
   586  	w.writeInt(int64(len(s.R)))
   587  	var r *Reloc
   588  	for i := 0; i < len(s.R); i++ {
   589  		r = &s.R[i]
   590  		w.writeInt(int64(r.Off))
   591  		w.writeInt(int64(r.Siz))
   592  		w.writeInt(int64(r.Type))
   593  		w.writeInt(r.Add)
   594  		w.writeRefIndex(r.Sym)
   595  	}
   596  
   597  	if s.Type != STEXT {
   598  		return
   599  	}
   600  
   601  	w.writeInt(int64(s.Args))
   602  	w.writeInt(int64(s.Locals))
   603  	if s.Nosplit {
   604  		w.writeInt(1)
   605  	} else {
   606  		w.writeInt(0)
   607  	}
   608  	flags = int64(0)
   609  	if s.Leaf {
   610  		flags |= 1
   611  	}
   612  	if s.Cfunc {
   613  		flags |= 1 << 1
   614  	}
   615  	if s.ReflectMethod {
   616  		flags |= 1 << 2
   617  	}
   618  	w.writeInt(flags)
   619  	n := 0
   620  	for a := s.Autom; a != nil; a = a.Link {
   621  		n++
   622  	}
   623  	w.writeInt(int64(n))
   624  	for a := s.Autom; a != nil; a = a.Link {
   625  		w.writeRefIndex(a.Asym)
   626  		w.writeInt(int64(a.Aoffset))
   627  		if a.Name == NAME_AUTO {
   628  			w.writeInt(A_AUTO)
   629  		} else if a.Name == NAME_PARAM {
   630  			w.writeInt(A_PARAM)
   631  		} else {
   632  			log.Fatalf("%s: invalid local variable type %d", s.Name, a.Name)
   633  		}
   634  		w.writeRefIndex(a.Gotype)
   635  	}
   636  
   637  	pc := s.Pcln
   638  	w.writeInt(int64(len(pc.Pcsp.P)))
   639  	w.writeInt(int64(len(pc.Pcfile.P)))
   640  	w.writeInt(int64(len(pc.Pcline.P)))
   641  	w.writeInt(int64(len(pc.Pcdata)))
   642  	for i := 0; i < len(pc.Pcdata); i++ {
   643  		w.writeInt(int64(len(pc.Pcdata[i].P)))
   644  	}
   645  	w.writeInt(int64(len(pc.Funcdataoff)))
   646  	for i := 0; i < len(pc.Funcdataoff); i++ {
   647  		w.writeRefIndex(pc.Funcdata[i])
   648  	}
   649  	for i := 0; i < len(pc.Funcdataoff); i++ {
   650  		w.writeInt(pc.Funcdataoff[i])
   651  	}
   652  	w.writeInt(int64(len(pc.File)))
   653  	for _, f := range pc.File {
   654  		w.writeRefIndex(f)
   655  	}
   656  }
   657  
   658  func (w *objWriter) writeInt(sval int64) {
   659  	var v uint64
   660  	uv := (uint64(sval) << 1) ^ uint64(int64(sval>>63))
   661  	p := w.varintbuf[:]
   662  	for v = uv; v >= 0x80; v >>= 7 {
   663  		p[0] = uint8(v | 0x80)
   664  		p = p[1:]
   665  	}
   666  	p[0] = uint8(v)
   667  	p = p[1:]
   668  	w.wr.Write(w.varintbuf[:len(w.varintbuf)-len(p)])
   669  }
   670  
   671  func (w *objWriter) writeString(s string) {
   672  	w.writeInt(int64(len(s)))
   673  	w.wr.WriteString(s)
   674  }
   675  
   676  func (w *objWriter) writeRefIndex(s *LSym) {
   677  	if s == nil {
   678  		w.writeInt(0)
   679  		return
   680  	}
   681  	if s.RefIdx == 0 {
   682  		log.Fatalln("writing an unreferenced symbol", s.Name)
   683  	}
   684  	w.writeInt(int64(s.RefIdx))
   685  }
   686  
   687  // relocByOff sorts relocations by their offsets.
   688  type relocByOff []Reloc
   689  
   690  func (x relocByOff) Len() int           { return len(x) }
   691  func (x relocByOff) Less(i, j int) bool { return x[i].Off < x[j].Off }
   692  func (x relocByOff) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }