github.com/euank/go@v0.0.0-20160829210321-495514729181/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\x00go17ld"
    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\xffgo17ld"
    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  	"cmd/internal/dwarf"
   113  	"cmd/internal/sys"
   114  	"fmt"
   115  	"log"
   116  	"path/filepath"
   117  	"sort"
   118  )
   119  
   120  // The Go and C compilers, and the assembler, call writeobj to write
   121  // out a Go object file. The linker does not call this; the linker
   122  // does not write out object files.
   123  func Writeobjdirect(ctxt *Link, b *bufio.Writer) {
   124  	Flushplist(ctxt)
   125  	WriteObjFile(ctxt, b)
   126  }
   127  
   128  // objWriter writes Go object files.
   129  type objWriter struct {
   130  	wr   *bufio.Writer
   131  	ctxt *Link
   132  	// Temporary buffer for zigzag int writing.
   133  	varintbuf [10]uint8
   134  
   135  	// Provide the the index of a symbol reference by symbol name.
   136  	// One map for versioned symbols and one for unversioned symbols.
   137  	// Used for deduplicating the symbol reference list.
   138  	refIdx  map[string]int
   139  	vrefIdx map[string]int
   140  
   141  	// Number of objects written of each type.
   142  	nRefs     int
   143  	nData     int
   144  	nReloc    int
   145  	nPcdata   int
   146  	nAutom    int
   147  	nFuncdata int
   148  	nFile     int
   149  }
   150  
   151  func (w *objWriter) addLengths(s *LSym) {
   152  	w.nData += len(s.P)
   153  	w.nReloc += len(s.R)
   154  
   155  	if s.Type != STEXT {
   156  		return
   157  	}
   158  
   159  	pc := s.Pcln
   160  
   161  	data := 0
   162  	data += len(pc.Pcsp.P)
   163  	data += len(pc.Pcfile.P)
   164  	data += len(pc.Pcline.P)
   165  	for i := 0; i < len(pc.Pcdata); i++ {
   166  		data += len(pc.Pcdata[i].P)
   167  	}
   168  
   169  	w.nData += data
   170  	w.nPcdata += len(pc.Pcdata)
   171  
   172  	autom := 0
   173  	for a := s.Autom; a != nil; a = a.Link {
   174  		autom++
   175  	}
   176  	w.nAutom += autom
   177  	w.nFuncdata += len(pc.Funcdataoff)
   178  	w.nFile += len(pc.File)
   179  }
   180  
   181  func (w *objWriter) writeLengths() {
   182  	w.writeInt(int64(w.nData))
   183  	w.writeInt(int64(w.nReloc))
   184  	w.writeInt(int64(w.nPcdata))
   185  	w.writeInt(int64(w.nAutom))
   186  	w.writeInt(int64(w.nFuncdata))
   187  	w.writeInt(int64(w.nFile))
   188  }
   189  
   190  func newObjWriter(ctxt *Link, b *bufio.Writer) *objWriter {
   191  	return &objWriter{
   192  		ctxt:    ctxt,
   193  		wr:      b,
   194  		vrefIdx: make(map[string]int),
   195  		refIdx:  make(map[string]int),
   196  	}
   197  }
   198  
   199  func WriteObjFile(ctxt *Link, b *bufio.Writer) {
   200  	w := newObjWriter(ctxt, b)
   201  
   202  	// Magic header
   203  	w.wr.WriteString("\x00\x00go17ld")
   204  
   205  	// Version
   206  	w.wr.WriteByte(1)
   207  
   208  	// Autolib
   209  	for _, pkg := range ctxt.Imports {
   210  		w.writeString(pkg)
   211  	}
   212  	w.writeString("")
   213  
   214  	// Symbol references
   215  	for _, s := range ctxt.Text {
   216  		w.writeRefs(s)
   217  		w.addLengths(s)
   218  	}
   219  	for _, s := range ctxt.Data {
   220  		w.writeRefs(s)
   221  		w.addLengths(s)
   222  	}
   223  	// End symbol references
   224  	w.wr.WriteByte(0xff)
   225  
   226  	// Lengths
   227  	w.writeLengths()
   228  
   229  	// Data block
   230  	for _, s := range ctxt.Text {
   231  		w.wr.Write(s.P)
   232  		pc := s.Pcln
   233  		w.wr.Write(pc.Pcsp.P)
   234  		w.wr.Write(pc.Pcfile.P)
   235  		w.wr.Write(pc.Pcline.P)
   236  		for i := 0; i < len(pc.Pcdata); i++ {
   237  			w.wr.Write(pc.Pcdata[i].P)
   238  		}
   239  	}
   240  	for _, s := range ctxt.Data {
   241  		w.wr.Write(s.P)
   242  	}
   243  
   244  	// Symbols
   245  	for _, s := range ctxt.Text {
   246  		w.writeSym(s)
   247  	}
   248  	for _, s := range ctxt.Data {
   249  		w.writeSym(s)
   250  	}
   251  
   252  	// Magic footer
   253  	w.wr.WriteString("\xff\xffgo17ld")
   254  }
   255  
   256  // Symbols are prefixed so their content doesn't get confused with the magic footer.
   257  const symPrefix = 0xfe
   258  
   259  func (w *objWriter) writeRef(s *LSym, isPath bool) {
   260  	if s == nil || s.RefIdx != 0 {
   261  		return
   262  	}
   263  	var m map[string]int
   264  	switch s.Version {
   265  	case 0:
   266  		m = w.refIdx
   267  	case 1:
   268  		m = w.vrefIdx
   269  	default:
   270  		log.Fatalf("%s: invalid version number %d", s.Name, s.Version)
   271  	}
   272  
   273  	idx := m[s.Name]
   274  	if idx != 0 {
   275  		s.RefIdx = idx
   276  		return
   277  	}
   278  	w.wr.WriteByte(symPrefix)
   279  	if isPath {
   280  		w.writeString(filepath.ToSlash(s.Name))
   281  	} else {
   282  		w.writeString(s.Name)
   283  	}
   284  	w.writeInt(int64(s.Version))
   285  	w.nRefs++
   286  	s.RefIdx = w.nRefs
   287  	m[s.Name] = w.nRefs
   288  }
   289  
   290  func (w *objWriter) writeRefs(s *LSym) {
   291  	w.writeRef(s, false)
   292  	w.writeRef(s.Gotype, false)
   293  	for i := range s.R {
   294  		w.writeRef(s.R[i].Sym, false)
   295  	}
   296  
   297  	if s.Type == STEXT {
   298  		for a := s.Autom; a != nil; a = a.Link {
   299  			w.writeRef(a.Asym, false)
   300  			w.writeRef(a.Gotype, false)
   301  		}
   302  		pc := s.Pcln
   303  		for _, d := range pc.Funcdata {
   304  			w.writeRef(d, false)
   305  		}
   306  		for _, f := range pc.File {
   307  			w.writeRef(f, true)
   308  		}
   309  	}
   310  }
   311  
   312  func (w *objWriter) writeSymDebug(s *LSym) {
   313  	ctxt := w.ctxt
   314  	fmt.Fprintf(ctxt.Bso, "%s ", s.Name)
   315  	if s.Version != 0 {
   316  		fmt.Fprintf(ctxt.Bso, "v=%d ", s.Version)
   317  	}
   318  	if s.Type != 0 {
   319  		fmt.Fprintf(ctxt.Bso, "t=%d ", s.Type)
   320  	}
   321  	if s.Dupok {
   322  		fmt.Fprintf(ctxt.Bso, "dupok ")
   323  	}
   324  	if s.Cfunc {
   325  		fmt.Fprintf(ctxt.Bso, "cfunc ")
   326  	}
   327  	if s.Nosplit {
   328  		fmt.Fprintf(ctxt.Bso, "nosplit ")
   329  	}
   330  	fmt.Fprintf(ctxt.Bso, "size=%d", s.Size)
   331  	if s.Type == STEXT {
   332  		fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x", uint64(s.Args), uint64(s.Locals))
   333  		if s.Leaf {
   334  			fmt.Fprintf(ctxt.Bso, " leaf")
   335  		}
   336  	}
   337  
   338  	fmt.Fprintf(ctxt.Bso, "\n")
   339  	for p := s.Text; p != nil; p = p.Link {
   340  		fmt.Fprintf(ctxt.Bso, "\t%#04x %v\n", uint(int(p.Pc)), p)
   341  	}
   342  	var c int
   343  	var j int
   344  	for i := 0; i < len(s.P); {
   345  		fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i))
   346  		for j = i; j < i+16 && j < len(s.P); j++ {
   347  			fmt.Fprintf(ctxt.Bso, " %02x", s.P[j])
   348  		}
   349  		for ; j < i+16; j++ {
   350  			fmt.Fprintf(ctxt.Bso, "   ")
   351  		}
   352  		fmt.Fprintf(ctxt.Bso, "  ")
   353  		for j = i; j < i+16 && j < len(s.P); j++ {
   354  			c = int(s.P[j])
   355  			if ' ' <= c && c <= 0x7e {
   356  				fmt.Fprintf(ctxt.Bso, "%c", c)
   357  			} else {
   358  				fmt.Fprintf(ctxt.Bso, ".")
   359  			}
   360  		}
   361  
   362  		fmt.Fprintf(ctxt.Bso, "\n")
   363  		i += 16
   364  	}
   365  
   366  	sort.Sort(relocByOff(s.R)) // generate stable output
   367  	for _, r := range s.R {
   368  		name := ""
   369  		if r.Sym != nil {
   370  			name = r.Sym.Name
   371  		} else if r.Type == R_TLS_LE {
   372  			name = "TLS"
   373  		}
   374  		if ctxt.Arch.InFamily(sys.ARM, sys.PPC64) {
   375  			fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%x\n", int(r.Off), r.Siz, r.Type, name, uint64(r.Add))
   376  		} else {
   377  			fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, name, r.Add)
   378  		}
   379  	}
   380  }
   381  
   382  func (w *objWriter) writeSym(s *LSym) {
   383  	ctxt := w.ctxt
   384  	if ctxt.Debugasm != 0 {
   385  		w.writeSymDebug(s)
   386  	}
   387  
   388  	w.wr.WriteByte(symPrefix)
   389  	w.writeInt(int64(s.Type))
   390  	w.writeRefIndex(s)
   391  	flags := int64(0)
   392  	if s.Dupok {
   393  		flags |= 1
   394  	}
   395  	if s.Local {
   396  		flags |= 1 << 1
   397  	}
   398  	w.writeInt(flags)
   399  	w.writeInt(s.Size)
   400  	w.writeRefIndex(s.Gotype)
   401  	w.writeInt(int64(len(s.P)))
   402  
   403  	w.writeInt(int64(len(s.R)))
   404  	var r *Reloc
   405  	for i := 0; i < len(s.R); i++ {
   406  		r = &s.R[i]
   407  		w.writeInt(int64(r.Off))
   408  		w.writeInt(int64(r.Siz))
   409  		w.writeInt(int64(r.Type))
   410  		w.writeInt(r.Add)
   411  		w.writeRefIndex(r.Sym)
   412  	}
   413  
   414  	if s.Type != STEXT {
   415  		return
   416  	}
   417  
   418  	w.writeInt(int64(s.Args))
   419  	w.writeInt(int64(s.Locals))
   420  	if s.Nosplit {
   421  		w.writeInt(1)
   422  	} else {
   423  		w.writeInt(0)
   424  	}
   425  	flags = int64(0)
   426  	if s.Leaf {
   427  		flags |= 1
   428  	}
   429  	if s.Cfunc {
   430  		flags |= 1 << 1
   431  	}
   432  	if s.ReflectMethod {
   433  		flags |= 1 << 2
   434  	}
   435  	w.writeInt(flags)
   436  	n := 0
   437  	for a := s.Autom; a != nil; a = a.Link {
   438  		n++
   439  	}
   440  	w.writeInt(int64(n))
   441  	for a := s.Autom; a != nil; a = a.Link {
   442  		w.writeRefIndex(a.Asym)
   443  		w.writeInt(int64(a.Aoffset))
   444  		if a.Name == NAME_AUTO {
   445  			w.writeInt(A_AUTO)
   446  		} else if a.Name == NAME_PARAM {
   447  			w.writeInt(A_PARAM)
   448  		} else {
   449  			log.Fatalf("%s: invalid local variable type %d", s.Name, a.Name)
   450  		}
   451  		w.writeRefIndex(a.Gotype)
   452  	}
   453  
   454  	pc := s.Pcln
   455  	w.writeInt(int64(len(pc.Pcsp.P)))
   456  	w.writeInt(int64(len(pc.Pcfile.P)))
   457  	w.writeInt(int64(len(pc.Pcline.P)))
   458  	w.writeInt(int64(len(pc.Pcdata)))
   459  	for i := 0; i < len(pc.Pcdata); i++ {
   460  		w.writeInt(int64(len(pc.Pcdata[i].P)))
   461  	}
   462  	w.writeInt(int64(len(pc.Funcdataoff)))
   463  	for i := 0; i < len(pc.Funcdataoff); i++ {
   464  		w.writeRefIndex(pc.Funcdata[i])
   465  	}
   466  	for i := 0; i < len(pc.Funcdataoff); i++ {
   467  		w.writeInt(pc.Funcdataoff[i])
   468  	}
   469  	w.writeInt(int64(len(pc.File)))
   470  	for _, f := range pc.File {
   471  		w.writeRefIndex(f)
   472  	}
   473  }
   474  
   475  func (w *objWriter) writeInt(sval int64) {
   476  	var v uint64
   477  	uv := (uint64(sval) << 1) ^ uint64(sval>>63)
   478  	p := w.varintbuf[:]
   479  	for v = uv; v >= 0x80; v >>= 7 {
   480  		p[0] = uint8(v | 0x80)
   481  		p = p[1:]
   482  	}
   483  	p[0] = uint8(v)
   484  	p = p[1:]
   485  	w.wr.Write(w.varintbuf[:len(w.varintbuf)-len(p)])
   486  }
   487  
   488  func (w *objWriter) writeString(s string) {
   489  	w.writeInt(int64(len(s)))
   490  	w.wr.WriteString(s)
   491  }
   492  
   493  func (w *objWriter) writeRefIndex(s *LSym) {
   494  	if s == nil {
   495  		w.writeInt(0)
   496  		return
   497  	}
   498  	if s.RefIdx == 0 {
   499  		log.Fatalln("writing an unreferenced symbol", s.Name)
   500  	}
   501  	w.writeInt(int64(s.RefIdx))
   502  }
   503  
   504  // relocByOff sorts relocations by their offsets.
   505  type relocByOff []Reloc
   506  
   507  func (x relocByOff) Len() int           { return len(x) }
   508  func (x relocByOff) Less(i, j int) bool { return x[i].Off < x[j].Off }
   509  func (x relocByOff) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
   510  
   511  // implement dwarf.Context
   512  type dwCtxt struct{ *Link }
   513  
   514  func (c dwCtxt) PtrSize() int {
   515  	return c.Arch.PtrSize
   516  }
   517  func (c dwCtxt) AddInt(s dwarf.Sym, size int, i int64) {
   518  	ls := s.(*LSym)
   519  	ls.WriteInt(c.Link, ls.Size, size, i)
   520  }
   521  func (c dwCtxt) AddBytes(s dwarf.Sym, b []byte) {
   522  	ls := s.(*LSym)
   523  	ls.WriteBytes(c.Link, ls.Size, b)
   524  }
   525  func (c dwCtxt) AddString(s dwarf.Sym, v string) {
   526  	ls := s.(*LSym)
   527  	ls.WriteString(c.Link, ls.Size, len(v), v)
   528  	ls.WriteInt(c.Link, ls.Size, 1, 0)
   529  }
   530  func (c dwCtxt) SymValue(s dwarf.Sym) int64 {
   531  	return 0
   532  }
   533  func (c dwCtxt) AddAddress(s dwarf.Sym, data interface{}, value int64) {
   534  	rsym := data.(*LSym)
   535  	ls := s.(*LSym)
   536  	size := c.PtrSize()
   537  	ls.WriteAddr(c.Link, ls.Size, size, rsym, value)
   538  }
   539  func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) {
   540  	ls := s.(*LSym)
   541  	rsym := t.(*LSym)
   542  	ls.WriteAddr(c.Link, ls.Size, size, rsym, ofs)
   543  	r := &ls.R[len(ls.R)-1]
   544  	r.Type = R_DWARFREF
   545  }
   546  
   547  func gendwarf(ctxt *Link, text []*LSym) []*LSym {
   548  	dctxt := dwCtxt{ctxt}
   549  	var dw []*LSym
   550  
   551  	for _, s := range text {
   552  		dsym := Linklookup(ctxt, dwarf.InfoPrefix+s.Name, int(s.Version))
   553  		if dsym.Size != 0 {
   554  			continue
   555  		}
   556  		dw = append(dw, dsym)
   557  		dsym.Type = SDWARFINFO
   558  		dsym.Dupok = s.Dupok
   559  		var vars dwarf.Var
   560  		var abbrev int
   561  		var offs int32
   562  		for a := s.Autom; a != nil; a = a.Link {
   563  			switch a.Name {
   564  			case NAME_AUTO:
   565  				abbrev = dwarf.DW_ABRV_AUTO
   566  				offs = a.Aoffset
   567  				if ctxt.FixedFrameSize() == 0 {
   568  					offs -= int32(ctxt.Arch.PtrSize)
   569  				}
   570  				if Framepointer_enabled(Getgoos(), Getgoarch()) {
   571  					offs -= int32(ctxt.Arch.PtrSize)
   572  				}
   573  
   574  			case NAME_PARAM:
   575  				abbrev = dwarf.DW_ABRV_PARAM
   576  				offs = a.Aoffset + int32(ctxt.FixedFrameSize())
   577  
   578  			default:
   579  				continue
   580  			}
   581  			typename := dwarf.InfoPrefix + a.Gotype.Name[len("type."):]
   582  			dwvar := &dwarf.Var{
   583  				Name:   a.Asym.Name,
   584  				Abbrev: abbrev,
   585  				Offset: int32(offs),
   586  				Type:   Linklookup(ctxt, typename, 0),
   587  			}
   588  			dws := &vars.Link
   589  			for ; *dws != nil; dws = &(*dws).Link {
   590  				if offs <= (*dws).Offset {
   591  					break
   592  				}
   593  			}
   594  			dwvar.Link = *dws
   595  			*dws = dwvar
   596  		}
   597  		dwarf.PutFunc(dctxt, dsym, s.Name, s.Version == 0, s, s.Size, vars.Link)
   598  	}
   599  	return dw
   600  }