github.com/mdempsky/go@v0.0.0-20151201204031-5dd372bd1e70/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 defined symbols
    23  //	- byte 0xff (marks end of sequence)
    24  //	- magic footer: "\xff\xffgo13ld"
    25  //
    26  // All integers are stored in a zigzag varint format.
    27  // See golang.org/s/go12symtab for a definition.
    28  //
    29  // Data blocks and strings are both stored as an integer
    30  // followed by that many bytes.
    31  //
    32  // A symbol reference is a string name followed by a version.
    33  // An empty name corresponds to a nil LSym* pointer.
    34  //
    35  // Each symbol is laid out as the following fields (taken from LSym*):
    36  //
    37  //	- byte 0xfe (sanity check for synchronization)
    38  //	- type [int]
    39  //	- name [string]
    40  //	- version [int]
    41  //	- flags [int]
    42  //		1 dupok
    43  //	- size [int]
    44  //	- gotype [symbol reference]
    45  //	- p [data block]
    46  //	- nr [int]
    47  //	- r [nr relocations, sorted by off]
    48  //
    49  // If type == STEXT, there are a few more fields:
    50  //
    51  //	- args [int]
    52  //	- locals [int]
    53  //	- nosplit [int]
    54  //	- flags [int]
    55  //		1 leaf
    56  //		2 C function
    57  //	- nlocal [int]
    58  //	- local [nlocal automatics]
    59  //	- pcln [pcln table]
    60  //
    61  // Each relocation has the encoding:
    62  //
    63  //	- off [int]
    64  //	- siz [int]
    65  //	- type [int]
    66  //	- add [int]
    67  //	- xadd [int]
    68  //	- sym [symbol reference]
    69  //	- xsym [symbol reference]
    70  //
    71  // Each local has the encoding:
    72  //
    73  //	- asym [symbol reference]
    74  //	- offset [int]
    75  //	- type [int]
    76  //	- gotype [symbol reference]
    77  //
    78  // The pcln table has the encoding:
    79  //
    80  //	- pcsp [data block]
    81  //	- pcfile [data block]
    82  //	- pcline [data block]
    83  //	- npcdata [int]
    84  //	- pcdata [npcdata data blocks]
    85  //	- nfuncdata [int]
    86  //	- funcdata [nfuncdata symbol references]
    87  //	- funcdatasym [nfuncdata ints]
    88  //	- nfile [int]
    89  //	- file [nfile symbol references]
    90  //
    91  // The file layout and meaning of type integers are architecture-independent.
    92  //
    93  // TODO(rsc): The file format is good for a first pass but needs work.
    94  //	- There are SymID in the object file that should really just be strings.
    95  //	- The actual symbol memory images are interlaced with the symbol
    96  //	  metadata. They should be separated, to reduce the I/O required to
    97  //	  load just the metadata.
    98  //	- The symbol references should be shortened, either with a symbol
    99  //	  table or by using a simple backward index to an earlier mentioned symbol.
   100  
   101  package obj
   102  
   103  import (
   104  	"fmt"
   105  	"log"
   106  	"path/filepath"
   107  	"strings"
   108  )
   109  
   110  // The Go and C compilers, and the assembler, call writeobj to write
   111  // out a Go object file.  The linker does not call this; the linker
   112  // does not write out object files.
   113  func Writeobjdirect(ctxt *Link, b *Biobuf) {
   114  	var flag int
   115  	var s *LSym
   116  	var p *Prog
   117  	var plink *Prog
   118  	var a *Auto
   119  
   120  	// Build list of symbols, and assign instructions to lists.
   121  	// Ignore ctxt->plist boundaries. There are no guarantees there,
   122  	// and the C compilers and assemblers just use one big list.
   123  	var text *LSym
   124  
   125  	var curtext *LSym
   126  	var data *LSym
   127  	var etext *LSym
   128  	var edata *LSym
   129  	for pl := ctxt.Plist; pl != nil; pl = pl.Link {
   130  		for p = pl.Firstpc; p != nil; p = plink {
   131  			if ctxt.Debugasm != 0 && ctxt.Debugvlog != 0 {
   132  				fmt.Printf("obj: %v\n", p)
   133  			}
   134  			plink = p.Link
   135  			p.Link = nil
   136  
   137  			if p.As == AEND {
   138  				continue
   139  			}
   140  
   141  			if p.As == ATYPE {
   142  				// Assume each TYPE instruction describes
   143  				// a different local variable or parameter,
   144  				// so no dedup.
   145  				// Using only the TYPE instructions means
   146  				// that we discard location information about local variables
   147  				// in C and assembly functions; that information is inferred
   148  				// from ordinary references, because there are no TYPE
   149  				// instructions there. Without the type information, gdb can't
   150  				// use the locations, so we don't bother to save them.
   151  				// If something else could use them, we could arrange to
   152  				// preserve them.
   153  				if curtext == nil {
   154  					continue
   155  				}
   156  				a = new(Auto)
   157  				a.Asym = p.From.Sym
   158  				a.Aoffset = int32(p.From.Offset)
   159  				a.Name = int16(p.From.Name)
   160  				a.Gotype = p.From.Gotype
   161  				a.Link = curtext.Autom
   162  				curtext.Autom = a
   163  				continue
   164  			}
   165  
   166  			if p.As == AGLOBL {
   167  				s = p.From.Sym
   168  				tmp6 := s.Seenglobl
   169  				s.Seenglobl++
   170  				if tmp6 != 0 {
   171  					fmt.Printf("duplicate %v\n", p)
   172  				}
   173  				if s.Onlist != 0 {
   174  					log.Fatalf("symbol %s listed multiple times", s.Name)
   175  				}
   176  				s.Onlist = 1
   177  				if data == nil {
   178  					data = s
   179  				} else {
   180  					edata.Next = s
   181  				}
   182  				s.Next = nil
   183  				s.Size = p.To.Offset
   184  				if s.Type == 0 || s.Type == SXREF {
   185  					s.Type = SBSS
   186  				}
   187  				flag = int(p.From3.Offset)
   188  				if flag&DUPOK != 0 {
   189  					s.Dupok = 1
   190  				}
   191  				if flag&RODATA != 0 {
   192  					s.Type = SRODATA
   193  				} else if flag&NOPTR != 0 {
   194  					s.Type = SNOPTRBSS
   195  				} else if flag&TLSBSS != 0 {
   196  					s.Type = STLSBSS
   197  				}
   198  				edata = s
   199  				continue
   200  			}
   201  
   202  			if p.As == ADATA {
   203  				savedata(ctxt, p.From.Sym, p, "<input>")
   204  				continue
   205  			}
   206  
   207  			if p.As == ATEXT {
   208  				s = p.From.Sym
   209  				if s == nil {
   210  					// func _() { }
   211  					curtext = nil
   212  
   213  					continue
   214  				}
   215  
   216  				if s.Text != nil {
   217  					log.Fatalf("duplicate TEXT for %s", s.Name)
   218  				}
   219  				if s.Onlist != 0 {
   220  					log.Fatalf("symbol %s listed multiple times", s.Name)
   221  				}
   222  				s.Onlist = 1
   223  				if text == nil {
   224  					text = s
   225  				} else {
   226  					etext.Next = s
   227  				}
   228  				etext = s
   229  				flag = int(p.From3Offset())
   230  				if flag&DUPOK != 0 {
   231  					s.Dupok = 1
   232  				}
   233  				if flag&NOSPLIT != 0 {
   234  					s.Nosplit = 1
   235  				}
   236  				s.Next = nil
   237  				s.Type = STEXT
   238  				s.Text = p
   239  				s.Etext = p
   240  				curtext = s
   241  				continue
   242  			}
   243  
   244  			if p.As == AFUNCDATA {
   245  				// Rewrite reference to go_args_stackmap(SB) to the Go-provided declaration information.
   246  				if curtext == nil { // func _() {}
   247  					continue
   248  				}
   249  				if p.To.Sym.Name == "go_args_stackmap" {
   250  					if p.From.Type != TYPE_CONST || p.From.Offset != FUNCDATA_ArgsPointerMaps {
   251  						ctxt.Diag("FUNCDATA use of go_args_stackmap(SB) without FUNCDATA_ArgsPointerMaps")
   252  					}
   253  					p.To.Sym = Linklookup(ctxt, fmt.Sprintf("%s.args_stackmap", curtext.Name), int(curtext.Version))
   254  				}
   255  			}
   256  
   257  			if curtext == nil {
   258  				continue
   259  			}
   260  			s = curtext
   261  			s.Etext.Link = p
   262  			s.Etext = p
   263  		}
   264  	}
   265  
   266  	// Add reference to Go arguments for C or assembly functions without them.
   267  	var found int
   268  	for s := text; s != nil; s = s.Next {
   269  		if !strings.HasPrefix(s.Name, "\"\".") {
   270  			continue
   271  		}
   272  		found = 0
   273  		for p = s.Text; p != nil; p = p.Link {
   274  			if p.As == AFUNCDATA && p.From.Type == TYPE_CONST && p.From.Offset == FUNCDATA_ArgsPointerMaps {
   275  				found = 1
   276  				break
   277  			}
   278  		}
   279  
   280  		if found == 0 {
   281  			p = Appendp(ctxt, s.Text)
   282  			p.As = AFUNCDATA
   283  			p.From.Type = TYPE_CONST
   284  			p.From.Offset = FUNCDATA_ArgsPointerMaps
   285  			p.To.Type = TYPE_MEM
   286  			p.To.Name = NAME_EXTERN
   287  			p.To.Sym = Linklookup(ctxt, fmt.Sprintf("%s.args_stackmap", s.Name), int(s.Version))
   288  		}
   289  	}
   290  
   291  	// Turn functions into machine code images.
   292  	for s := text; s != nil; s = s.Next {
   293  		mkfwd(s)
   294  		linkpatch(ctxt, s)
   295  		ctxt.Arch.Follow(ctxt, s)
   296  		ctxt.Arch.Preprocess(ctxt, s)
   297  		ctxt.Arch.Assemble(ctxt, s)
   298  		linkpcln(ctxt, s)
   299  	}
   300  
   301  	// Emit header.
   302  	Bputc(b, 0)
   303  
   304  	Bputc(b, 0)
   305  	fmt.Fprintf(b, "go13ld")
   306  	Bputc(b, 1) // version
   307  
   308  	// Emit autolib.
   309  	for _, pkg := range ctxt.Imports {
   310  		wrstring(b, pkg)
   311  	}
   312  	wrstring(b, "")
   313  
   314  	// Emit symbols.
   315  	for s := text; s != nil; s = s.Next {
   316  		writesym(ctxt, b, s)
   317  	}
   318  	for s := data; s != nil; s = s.Next {
   319  		writesym(ctxt, b, s)
   320  	}
   321  
   322  	// Emit footer.
   323  	Bputc(b, 0xff)
   324  
   325  	Bputc(b, 0xff)
   326  	fmt.Fprintf(b, "go13ld")
   327  }
   328  
   329  func writesym(ctxt *Link, b *Biobuf, s *LSym) {
   330  	if ctxt.Debugasm != 0 {
   331  		fmt.Fprintf(ctxt.Bso, "%s ", s.Name)
   332  		if s.Version != 0 {
   333  			fmt.Fprintf(ctxt.Bso, "v=%d ", s.Version)
   334  		}
   335  		if s.Type != 0 {
   336  			fmt.Fprintf(ctxt.Bso, "t=%d ", s.Type)
   337  		}
   338  		if s.Dupok != 0 {
   339  			fmt.Fprintf(ctxt.Bso, "dupok ")
   340  		}
   341  		if s.Cfunc != 0 {
   342  			fmt.Fprintf(ctxt.Bso, "cfunc ")
   343  		}
   344  		if s.Nosplit != 0 {
   345  			fmt.Fprintf(ctxt.Bso, "nosplit ")
   346  		}
   347  		fmt.Fprintf(ctxt.Bso, "size=%d value=%d", int64(s.Size), int64(s.Value))
   348  		if s.Type == STEXT {
   349  			fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x", uint64(s.Args), uint64(s.Locals))
   350  			if s.Leaf != 0 {
   351  				fmt.Fprintf(ctxt.Bso, " leaf")
   352  			}
   353  		}
   354  
   355  		fmt.Fprintf(ctxt.Bso, "\n")
   356  		for p := s.Text; p != nil; p = p.Link {
   357  			fmt.Fprintf(ctxt.Bso, "\t%#04x %v\n", uint(int(p.Pc)), p)
   358  		}
   359  		var c int
   360  		var j int
   361  		for i := 0; i < len(s.P); {
   362  			fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i))
   363  			for j = i; j < i+16 && j < len(s.P); j++ {
   364  				fmt.Fprintf(ctxt.Bso, " %02x", s.P[j])
   365  			}
   366  			for ; j < i+16; j++ {
   367  				fmt.Fprintf(ctxt.Bso, "   ")
   368  			}
   369  			fmt.Fprintf(ctxt.Bso, "  ")
   370  			for j = i; j < i+16 && j < len(s.P); j++ {
   371  				c = int(s.P[j])
   372  				if ' ' <= c && c <= 0x7e {
   373  					fmt.Fprintf(ctxt.Bso, "%c", c)
   374  				} else {
   375  					fmt.Fprintf(ctxt.Bso, ".")
   376  				}
   377  			}
   378  
   379  			fmt.Fprintf(ctxt.Bso, "\n")
   380  			i += 16
   381  		}
   382  
   383  		var r *Reloc
   384  		var name string
   385  		for i := 0; i < len(s.R); i++ {
   386  			r = &s.R[i]
   387  			name = ""
   388  			if r.Sym != nil {
   389  				name = r.Sym.Name
   390  			}
   391  			if ctxt.Arch.Thechar == '5' || ctxt.Arch.Thechar == '9' {
   392  				fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%x\n", int(r.Off), r.Siz, r.Type, name, uint64(int64(r.Add)))
   393  			} else {
   394  				fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, name, int64(r.Add))
   395  			}
   396  		}
   397  	}
   398  
   399  	Bputc(b, 0xfe)
   400  	wrint(b, int64(s.Type))
   401  	wrstring(b, s.Name)
   402  	wrint(b, int64(s.Version))
   403  	flags := int64(s.Dupok)
   404  	if s.Local {
   405  		flags |= 2
   406  	}
   407  	wrint(b, flags)
   408  	wrint(b, s.Size)
   409  	wrsym(b, s.Gotype)
   410  	wrdata(b, s.P)
   411  
   412  	wrint(b, int64(len(s.R)))
   413  	var r *Reloc
   414  	for i := 0; i < len(s.R); i++ {
   415  		r = &s.R[i]
   416  		wrint(b, int64(r.Off))
   417  		wrint(b, int64(r.Siz))
   418  		wrint(b, int64(r.Type))
   419  		wrint(b, r.Add)
   420  		wrint(b, 0) // Xadd, ignored
   421  		wrsym(b, r.Sym)
   422  		wrsym(b, nil) // Xsym, ignored
   423  	}
   424  
   425  	if s.Type == STEXT {
   426  		wrint(b, int64(s.Args))
   427  		wrint(b, int64(s.Locals))
   428  		wrint(b, int64(s.Nosplit))
   429  		wrint(b, int64(s.Leaf)|int64(s.Cfunc)<<1)
   430  		n := 0
   431  		for a := s.Autom; a != nil; a = a.Link {
   432  			n++
   433  		}
   434  		wrint(b, int64(n))
   435  		for a := s.Autom; a != nil; a = a.Link {
   436  			wrsym(b, a.Asym)
   437  			wrint(b, int64(a.Aoffset))
   438  			if a.Name == NAME_AUTO {
   439  				wrint(b, A_AUTO)
   440  			} else if a.Name == NAME_PARAM {
   441  				wrint(b, A_PARAM)
   442  			} else {
   443  				log.Fatalf("%s: invalid local variable type %d", s.Name, a.Name)
   444  			}
   445  			wrsym(b, a.Gotype)
   446  		}
   447  
   448  		pc := s.Pcln
   449  		wrdata(b, pc.Pcsp.P)
   450  		wrdata(b, pc.Pcfile.P)
   451  		wrdata(b, pc.Pcline.P)
   452  		wrint(b, int64(len(pc.Pcdata)))
   453  		for i := 0; i < len(pc.Pcdata); i++ {
   454  			wrdata(b, pc.Pcdata[i].P)
   455  		}
   456  		wrint(b, int64(len(pc.Funcdataoff)))
   457  		for i := 0; i < len(pc.Funcdataoff); i++ {
   458  			wrsym(b, pc.Funcdata[i])
   459  		}
   460  		for i := 0; i < len(pc.Funcdataoff); i++ {
   461  			wrint(b, pc.Funcdataoff[i])
   462  		}
   463  		wrint(b, int64(len(pc.File)))
   464  		for i := 0; i < len(pc.File); i++ {
   465  			wrpathsym(ctxt, b, pc.File[i])
   466  		}
   467  	}
   468  }
   469  
   470  // Reusable buffer to avoid allocations.
   471  // This buffer was responsible for 15% of gc's allocations.
   472  var varintbuf [10]uint8
   473  
   474  func wrint(b *Biobuf, sval int64) {
   475  	var v uint64
   476  	uv := (uint64(sval) << 1) ^ uint64(int64(sval>>63))
   477  	p := varintbuf[:]
   478  	for v = uv; v >= 0x80; v >>= 7 {
   479  		p[0] = uint8(v | 0x80)
   480  		p = p[1:]
   481  	}
   482  	p[0] = uint8(v)
   483  	p = p[1:]
   484  	b.Write(varintbuf[:len(varintbuf)-len(p)])
   485  }
   486  
   487  func wrstring(b *Biobuf, s string) {
   488  	wrint(b, int64(len(s)))
   489  	b.w.WriteString(s)
   490  }
   491  
   492  // wrpath writes a path just like a string, but on windows, it
   493  // translates '\\' to '/' in the process.
   494  func wrpath(ctxt *Link, b *Biobuf, p string) {
   495  	wrstring(b, filepath.ToSlash(p))
   496  }
   497  
   498  func wrdata(b *Biobuf, v []byte) {
   499  	wrint(b, int64(len(v)))
   500  	b.Write(v)
   501  }
   502  
   503  func wrpathsym(ctxt *Link, b *Biobuf, s *LSym) {
   504  	if s == nil {
   505  		wrint(b, 0)
   506  		wrint(b, 0)
   507  		return
   508  	}
   509  
   510  	wrpath(ctxt, b, s.Name)
   511  	wrint(b, int64(s.Version))
   512  }
   513  
   514  func wrsym(b *Biobuf, s *LSym) {
   515  	if s == nil {
   516  		wrint(b, 0)
   517  		wrint(b, 0)
   518  		return
   519  	}
   520  
   521  	wrstring(b, s.Name)
   522  	wrint(b, int64(s.Version))
   523  }