rsc.io/go@v0.0.0-20150416155037-e040fd465409/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  var outfile string
   111  
   112  // The Go and C compilers, and the assembler, call writeobj to write
   113  // out a Go object file.  The linker does not call this; the linker
   114  // does not write out object files.
   115  func Writeobjdirect(ctxt *Link, b *Biobuf) {
   116  	var flag int
   117  	var s *LSym
   118  	var p *Prog
   119  	var plink *Prog
   120  	var a *Auto
   121  
   122  	// Build list of symbols, and assign instructions to lists.
   123  	// Ignore ctxt->plist boundaries. There are no guarantees there,
   124  	// and the C compilers and assemblers just use one big list.
   125  	var text *LSym
   126  
   127  	var curtext *LSym
   128  	var data *LSym
   129  	var etext *LSym
   130  	var edata *LSym
   131  	for pl := ctxt.Plist; pl != nil; pl = pl.Link {
   132  		for p = pl.Firstpc; p != nil; p = plink {
   133  			if ctxt.Debugasm != 0 && ctxt.Debugvlog != 0 {
   134  				fmt.Printf("obj: %v\n", p)
   135  			}
   136  			plink = p.Link
   137  			p.Link = nil
   138  
   139  			if p.As == AEND {
   140  				continue
   141  			}
   142  
   143  			if p.As == ATYPE {
   144  				// Assume each TYPE instruction describes
   145  				// a different local variable or parameter,
   146  				// so no dedup.
   147  				// Using only the TYPE instructions means
   148  				// that we discard location information about local variables
   149  				// in C and assembly functions; that information is inferred
   150  				// from ordinary references, because there are no TYPE
   151  				// instructions there. Without the type information, gdb can't
   152  				// use the locations, so we don't bother to save them.
   153  				// If something else could use them, we could arrange to
   154  				// preserve them.
   155  				if curtext == nil {
   156  					continue
   157  				}
   158  				a = new(Auto)
   159  				a.Asym = p.From.Sym
   160  				a.Aoffset = int32(p.From.Offset)
   161  				a.Name = int16(p.From.Name)
   162  				a.Gotype = p.From.Gotype
   163  				a.Link = curtext.Autom
   164  				curtext.Autom = a
   165  				continue
   166  			}
   167  
   168  			if p.As == AGLOBL {
   169  				s = p.From.Sym
   170  				tmp6 := s.Seenglobl
   171  				s.Seenglobl++
   172  				if tmp6 != 0 {
   173  					fmt.Printf("duplicate %v\n", p)
   174  				}
   175  				if s.Onlist != 0 {
   176  					log.Fatalf("symbol %s listed multiple times", s.Name)
   177  				}
   178  				s.Onlist = 1
   179  				if data == nil {
   180  					data = s
   181  				} else {
   182  					edata.Next = s
   183  				}
   184  				s.Next = nil
   185  				s.Size = p.To.Offset
   186  				if s.Type == 0 || s.Type == SXREF {
   187  					s.Type = SBSS
   188  				}
   189  				flag = int(p.From3.Offset)
   190  				if flag&DUPOK != 0 {
   191  					s.Dupok = 1
   192  				}
   193  				if flag&RODATA != 0 {
   194  					s.Type = SRODATA
   195  				} else if flag&NOPTR != 0 {
   196  					s.Type = SNOPTRBSS
   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.From3.Offset)
   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  	wrint(b, int64(s.Dupok))
   404  	wrint(b, s.Size)
   405  	wrsym(b, s.Gotype)
   406  	wrdata(b, s.P)
   407  
   408  	wrint(b, int64(len(s.R)))
   409  	var r *Reloc
   410  	for i := 0; i < len(s.R); i++ {
   411  		r = &s.R[i]
   412  		wrint(b, int64(r.Off))
   413  		wrint(b, int64(r.Siz))
   414  		wrint(b, int64(r.Type))
   415  		wrint(b, r.Add)
   416  		wrint(b, r.Xadd)
   417  		wrsym(b, r.Sym)
   418  		wrsym(b, r.Xsym)
   419  	}
   420  
   421  	if s.Type == STEXT {
   422  		wrint(b, int64(s.Args))
   423  		wrint(b, int64(s.Locals))
   424  		wrint(b, int64(s.Nosplit))
   425  		wrint(b, int64(s.Leaf)|int64(s.Cfunc)<<1)
   426  		n := 0
   427  		for a := s.Autom; a != nil; a = a.Link {
   428  			n++
   429  		}
   430  		wrint(b, int64(n))
   431  		for a := s.Autom; a != nil; a = a.Link {
   432  			wrsym(b, a.Asym)
   433  			wrint(b, int64(a.Aoffset))
   434  			if a.Name == NAME_AUTO {
   435  				wrint(b, A_AUTO)
   436  			} else if a.Name == NAME_PARAM {
   437  				wrint(b, A_PARAM)
   438  			} else {
   439  				log.Fatalf("%s: invalid local variable type %d", s.Name, a.Name)
   440  			}
   441  			wrsym(b, a.Gotype)
   442  		}
   443  
   444  		pc := s.Pcln
   445  		wrdata(b, pc.Pcsp.P)
   446  		wrdata(b, pc.Pcfile.P)
   447  		wrdata(b, pc.Pcline.P)
   448  		wrint(b, int64(len(pc.Pcdata)))
   449  		for i := 0; i < len(pc.Pcdata); i++ {
   450  			wrdata(b, pc.Pcdata[i].P)
   451  		}
   452  		wrint(b, int64(len(pc.Funcdataoff)))
   453  		for i := 0; i < len(pc.Funcdataoff); i++ {
   454  			wrsym(b, pc.Funcdata[i])
   455  		}
   456  		for i := 0; i < len(pc.Funcdataoff); i++ {
   457  			wrint(b, pc.Funcdataoff[i])
   458  		}
   459  		wrint(b, int64(len(pc.File)))
   460  		for i := 0; i < len(pc.File); i++ {
   461  			wrpathsym(ctxt, b, pc.File[i])
   462  		}
   463  	}
   464  }
   465  
   466  func wrint(b *Biobuf, sval int64) {
   467  	var v uint64
   468  	var buf [10]uint8
   469  	uv := (uint64(sval) << 1) ^ uint64(int64(sval>>63))
   470  	p := buf[:]
   471  	for v = uv; v >= 0x80; v >>= 7 {
   472  		p[0] = uint8(v | 0x80)
   473  		p = p[1:]
   474  	}
   475  	p[0] = uint8(v)
   476  	p = p[1:]
   477  	Bwrite(b, buf[:len(buf)-len(p)])
   478  }
   479  
   480  func wrstring(b *Biobuf, s string) {
   481  	wrint(b, int64(len(s)))
   482  	b.w.WriteString(s)
   483  }
   484  
   485  // wrpath writes a path just like a string, but on windows, it
   486  // translates '\\' to '/' in the process.
   487  func wrpath(ctxt *Link, b *Biobuf, p string) {
   488  	wrstring(b, filepath.ToSlash(p))
   489  }
   490  
   491  func wrdata(b *Biobuf, v []byte) {
   492  	wrint(b, int64(len(v)))
   493  	Bwrite(b, v)
   494  }
   495  
   496  func wrpathsym(ctxt *Link, b *Biobuf, s *LSym) {
   497  	if s == nil {
   498  		wrint(b, 0)
   499  		wrint(b, 0)
   500  		return
   501  	}
   502  
   503  	wrpath(ctxt, b, s.Name)
   504  	wrint(b, int64(s.Version))
   505  }
   506  
   507  func wrsym(b *Biobuf, s *LSym) {
   508  	if s == nil {
   509  		wrint(b, 0)
   510  		wrint(b, 0)
   511  		return
   512  	}
   513  
   514  	wrstring(b, s.Name)
   515  	wrint(b, int64(s.Version))
   516  }
   517  
   518  var startmagic string = "\x00\x00go13ld"
   519  
   520  var endmagic string = "\xff\xffgo13ld"