Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/internal/obj/objfile.go

Documentation: cmd/internal/obj

     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 Go object files.
     6  
     7  package obj
     8  
     9  import (
    10  	"bytes"
    11  	"cmd/internal/bio"
    12  	"cmd/internal/goobj"
    13  	"cmd/internal/objabi"
    14  	"cmd/internal/sys"
    15  	"crypto/sha1"
    16  	"encoding/binary"
    17  	"fmt"
    18  	"io"
    19  	"log"
    20  	"os"
    21  	"path/filepath"
    22  	"sort"
    23  	"strings"
    24  )
    25  
    26  // Entry point of writing new object file.
    27  func WriteObjFile(ctxt *Link, b *bio.Writer) {
    28  
    29  	debugAsmEmit(ctxt)
    30  
    31  	genFuncInfoSyms(ctxt)
    32  
    33  	w := writer{
    34  		Writer:  goobj.NewWriter(b),
    35  		ctxt:    ctxt,
    36  		pkgpath: objabi.PathToPrefix(ctxt.Pkgpath),
    37  	}
    38  
    39  	start := b.Offset()
    40  	w.init()
    41  
    42  	// Header
    43  	// We just reserve the space. We'll fill in the offsets later.
    44  	flags := uint32(0)
    45  	if ctxt.Flag_shared {
    46  		flags |= goobj.ObjFlagShared
    47  	}
    48  	if w.pkgpath == "" {
    49  		flags |= goobj.ObjFlagNeedNameExpansion
    50  	}
    51  	if ctxt.IsAsm {
    52  		flags |= goobj.ObjFlagFromAssembly
    53  	}
    54  	h := goobj.Header{
    55  		Magic:       goobj.Magic,
    56  		Fingerprint: ctxt.Fingerprint,
    57  		Flags:       flags,
    58  	}
    59  	h.Write(w.Writer)
    60  
    61  	// String table
    62  	w.StringTable()
    63  
    64  	// Autolib
    65  	h.Offsets[goobj.BlkAutolib] = w.Offset()
    66  	for i := range ctxt.Imports {
    67  		ctxt.Imports[i].Write(w.Writer)
    68  	}
    69  
    70  	// Package references
    71  	h.Offsets[goobj.BlkPkgIdx] = w.Offset()
    72  	for _, pkg := range w.pkglist {
    73  		w.StringRef(pkg)
    74  	}
    75  
    76  	// File table (for DWARF and pcln generation).
    77  	h.Offsets[goobj.BlkFile] = w.Offset()
    78  	for _, f := range ctxt.PosTable.FileTable() {
    79  		w.StringRef(filepath.ToSlash(f))
    80  	}
    81  
    82  	// Symbol definitions
    83  	h.Offsets[goobj.BlkSymdef] = w.Offset()
    84  	for _, s := range ctxt.defs {
    85  		w.Sym(s)
    86  	}
    87  
    88  	// Short hashed symbol definitions
    89  	h.Offsets[goobj.BlkHashed64def] = w.Offset()
    90  	for _, s := range ctxt.hashed64defs {
    91  		w.Sym(s)
    92  	}
    93  
    94  	// Hashed symbol definitions
    95  	h.Offsets[goobj.BlkHasheddef] = w.Offset()
    96  	for _, s := range ctxt.hasheddefs {
    97  		w.Sym(s)
    98  	}
    99  
   100  	// Non-pkg symbol definitions
   101  	h.Offsets[goobj.BlkNonpkgdef] = w.Offset()
   102  	for _, s := range ctxt.nonpkgdefs {
   103  		w.Sym(s)
   104  	}
   105  
   106  	// Non-pkg symbol references
   107  	h.Offsets[goobj.BlkNonpkgref] = w.Offset()
   108  	for _, s := range ctxt.nonpkgrefs {
   109  		w.Sym(s)
   110  	}
   111  
   112  	// Referenced package symbol flags
   113  	h.Offsets[goobj.BlkRefFlags] = w.Offset()
   114  	w.refFlags()
   115  
   116  	// Hashes
   117  	h.Offsets[goobj.BlkHash64] = w.Offset()
   118  	for _, s := range ctxt.hashed64defs {
   119  		w.Hash64(s)
   120  	}
   121  	h.Offsets[goobj.BlkHash] = w.Offset()
   122  	for _, s := range ctxt.hasheddefs {
   123  		w.Hash(s)
   124  	}
   125  	// TODO: hashedrefs unused/unsupported for now
   126  
   127  	// Reloc indexes
   128  	h.Offsets[goobj.BlkRelocIdx] = w.Offset()
   129  	nreloc := uint32(0)
   130  	lists := [][]*LSym{ctxt.defs, ctxt.hashed64defs, ctxt.hasheddefs, ctxt.nonpkgdefs}
   131  	for _, list := range lists {
   132  		for _, s := range list {
   133  			w.Uint32(nreloc)
   134  			nreloc += uint32(len(s.R))
   135  		}
   136  	}
   137  	w.Uint32(nreloc)
   138  
   139  	// Symbol Info indexes
   140  	h.Offsets[goobj.BlkAuxIdx] = w.Offset()
   141  	naux := uint32(0)
   142  	for _, list := range lists {
   143  		for _, s := range list {
   144  			w.Uint32(naux)
   145  			naux += uint32(nAuxSym(s))
   146  		}
   147  	}
   148  	w.Uint32(naux)
   149  
   150  	// Data indexes
   151  	h.Offsets[goobj.BlkDataIdx] = w.Offset()
   152  	dataOff := int64(0)
   153  	for _, list := range lists {
   154  		for _, s := range list {
   155  			w.Uint32(uint32(dataOff))
   156  			dataOff += int64(len(s.P))
   157  			if file := s.File(); file != nil {
   158  				dataOff += int64(file.Size)
   159  			}
   160  		}
   161  	}
   162  	if int64(uint32(dataOff)) != dataOff {
   163  		log.Fatalf("data too large")
   164  	}
   165  	w.Uint32(uint32(dataOff))
   166  
   167  	// Relocs
   168  	h.Offsets[goobj.BlkReloc] = w.Offset()
   169  	for _, list := range lists {
   170  		for _, s := range list {
   171  			for i := range s.R {
   172  				w.Reloc(&s.R[i])
   173  			}
   174  		}
   175  	}
   176  
   177  	// Aux symbol info
   178  	h.Offsets[goobj.BlkAux] = w.Offset()
   179  	for _, list := range lists {
   180  		for _, s := range list {
   181  			w.Aux(s)
   182  		}
   183  	}
   184  
   185  	// Data
   186  	h.Offsets[goobj.BlkData] = w.Offset()
   187  	for _, list := range lists {
   188  		for _, s := range list {
   189  			w.Bytes(s.P)
   190  			if file := s.File(); file != nil {
   191  				w.writeFile(ctxt, file)
   192  			}
   193  		}
   194  	}
   195  
   196  	// Pcdata
   197  	h.Offsets[goobj.BlkPcdata] = w.Offset()
   198  	for _, s := range ctxt.Text { // iteration order must match genFuncInfoSyms
   199  		// Because of the phase order, it's possible that we try to write an invalid
   200  		// object file, and the Pcln variables haven't been filled in. As such, we
   201  		// need to check that Pcsp exists, and assume the other pcln variables exist
   202  		// as well. Tests like test/fixedbugs/issue22200.go demonstrate this issue.
   203  		if fn := s.Func(); fn != nil && fn.Pcln.Pcsp != nil {
   204  			pc := &fn.Pcln
   205  			w.Bytes(pc.Pcsp.P)
   206  			w.Bytes(pc.Pcfile.P)
   207  			w.Bytes(pc.Pcline.P)
   208  			w.Bytes(pc.Pcinline.P)
   209  			for i := range pc.Pcdata {
   210  				w.Bytes(pc.Pcdata[i].P)
   211  			}
   212  		}
   213  	}
   214  
   215  	// Blocks used only by tools (objdump, nm).
   216  
   217  	// Referenced symbol names from other packages
   218  	h.Offsets[goobj.BlkRefName] = w.Offset()
   219  	w.refNames()
   220  
   221  	h.Offsets[goobj.BlkEnd] = w.Offset()
   222  
   223  	// Fix up block offsets in the header
   224  	end := start + int64(w.Offset())
   225  	b.MustSeek(start, 0)
   226  	h.Write(w.Writer)
   227  	b.MustSeek(end, 0)
   228  }
   229  
   230  type writer struct {
   231  	*goobj.Writer
   232  	filebuf []byte
   233  	ctxt    *Link
   234  	pkgpath string   // the package import path (escaped), "" if unknown
   235  	pkglist []string // list of packages referenced, indexed by ctxt.pkgIdx
   236  }
   237  
   238  // prepare package index list
   239  func (w *writer) init() {
   240  	w.pkglist = make([]string, len(w.ctxt.pkgIdx)+1)
   241  	w.pkglist[0] = "" // dummy invalid package for index 0
   242  	for pkg, i := range w.ctxt.pkgIdx {
   243  		w.pkglist[i] = pkg
   244  	}
   245  }
   246  
   247  func (w *writer) writeFile(ctxt *Link, file *FileInfo) {
   248  	f, err := os.Open(file.Name)
   249  	if err != nil {
   250  		ctxt.Diag("%v", err)
   251  		return
   252  	}
   253  	defer f.Close()
   254  	if w.filebuf == nil {
   255  		w.filebuf = make([]byte, 1024)
   256  	}
   257  	buf := w.filebuf
   258  	written := int64(0)
   259  	for {
   260  		n, err := f.Read(buf)
   261  		w.Bytes(buf[:n])
   262  		written += int64(n)
   263  		if err == io.EOF {
   264  			break
   265  		}
   266  		if err != nil {
   267  			ctxt.Diag("%v", err)
   268  			return
   269  		}
   270  	}
   271  	if written != file.Size {
   272  		ctxt.Diag("copy %s: unexpected length %d != %d", file.Name, written, file.Size)
   273  	}
   274  }
   275  
   276  func (w *writer) StringTable() {
   277  	w.AddString("")
   278  	for _, p := range w.ctxt.Imports {
   279  		w.AddString(p.Pkg)
   280  	}
   281  	for _, pkg := range w.pkglist {
   282  		w.AddString(pkg)
   283  	}
   284  	w.ctxt.traverseSyms(traverseAll, func(s *LSym) {
   285  		// TODO: this includes references of indexed symbols from other packages,
   286  		// for which the linker doesn't need the name. Consider moving them to
   287  		// a separate block (for tools only).
   288  		if w.pkgpath != "" {
   289  			s.Name = strings.Replace(s.Name, "\"\".", w.pkgpath+".", -1)
   290  		}
   291  		// Don't put names of builtins into the string table (to save
   292  		// space).
   293  		if s.PkgIdx == goobj.PkgIdxBuiltin {
   294  			return
   295  		}
   296  		w.AddString(s.Name)
   297  	})
   298  
   299  	// All filenames are in the postable.
   300  	for _, f := range w.ctxt.PosTable.FileTable() {
   301  		w.AddString(filepath.ToSlash(f))
   302  	}
   303  }
   304  
   305  // cutoff is the maximum data section size permitted by the linker
   306  // (see issue #9862).
   307  const cutoff = int64(2e9) // 2 GB (or so; looks better in errors than 2^31)
   308  
   309  func (w *writer) Sym(s *LSym) {
   310  	abi := uint16(s.ABI())
   311  	if s.Static() {
   312  		abi = goobj.SymABIstatic
   313  	}
   314  	flag := uint8(0)
   315  	if s.DuplicateOK() {
   316  		flag |= goobj.SymFlagDupok
   317  	}
   318  	if s.Local() {
   319  		flag |= goobj.SymFlagLocal
   320  	}
   321  	if s.MakeTypelink() {
   322  		flag |= goobj.SymFlagTypelink
   323  	}
   324  	if s.Leaf() {
   325  		flag |= goobj.SymFlagLeaf
   326  	}
   327  	if s.NoSplit() {
   328  		flag |= goobj.SymFlagNoSplit
   329  	}
   330  	if s.ReflectMethod() {
   331  		flag |= goobj.SymFlagReflectMethod
   332  	}
   333  	if s.TopFrame() {
   334  		flag |= goobj.SymFlagTopFrame
   335  	}
   336  	if strings.HasPrefix(s.Name, "type.") && s.Name[5] != '.' && s.Type == objabi.SRODATA {
   337  		flag |= goobj.SymFlagGoType
   338  	}
   339  	flag2 := uint8(0)
   340  	if s.UsedInIface() {
   341  		flag2 |= goobj.SymFlagUsedInIface
   342  	}
   343  	if strings.HasPrefix(s.Name, "go.itab.") && s.Type == objabi.SRODATA {
   344  		flag2 |= goobj.SymFlagItab
   345  	}
   346  	name := s.Name
   347  	if strings.HasPrefix(name, "gofile..") {
   348  		name = filepath.ToSlash(name)
   349  	}
   350  	var align uint32
   351  	if fn := s.Func(); fn != nil {
   352  		align = uint32(fn.Align)
   353  	}
   354  	if s.ContentAddressable() {
   355  		// We generally assume data symbols are natually aligned,
   356  		// except for strings. If we dedup a string symbol and a
   357  		// non-string symbol with the same content, we should keep
   358  		// the largest alignment.
   359  		// TODO: maybe the compiler could set the alignment for all
   360  		// data symbols more carefully.
   361  		if s.Size != 0 && !strings.HasPrefix(s.Name, "go.string.") {
   362  			switch {
   363  			case w.ctxt.Arch.PtrSize == 8 && s.Size%8 == 0:
   364  				align = 8
   365  			case s.Size%4 == 0:
   366  				align = 4
   367  			case s.Size%2 == 0:
   368  				align = 2
   369  			}
   370  			// don't bother setting align to 1.
   371  		}
   372  	}
   373  	if s.Size > cutoff {
   374  		w.ctxt.Diag("%s: symbol too large (%d bytes > %d bytes)", s.Name, s.Size, cutoff)
   375  	}
   376  	var o goobj.Sym
   377  	o.SetName(name, w.Writer)
   378  	o.SetABI(abi)
   379  	o.SetType(uint8(s.Type))
   380  	o.SetFlag(flag)
   381  	o.SetFlag2(flag2)
   382  	o.SetSiz(uint32(s.Size))
   383  	o.SetAlign(align)
   384  	o.Write(w.Writer)
   385  }
   386  
   387  func (w *writer) Hash64(s *LSym) {
   388  	if !s.ContentAddressable() || len(s.R) != 0 {
   389  		panic("Hash of non-content-addresable symbol")
   390  	}
   391  	b := contentHash64(s)
   392  	w.Bytes(b[:])
   393  }
   394  
   395  func (w *writer) Hash(s *LSym) {
   396  	if !s.ContentAddressable() {
   397  		panic("Hash of non-content-addresable symbol")
   398  	}
   399  	b := w.contentHash(s)
   400  	w.Bytes(b[:])
   401  }
   402  
   403  func contentHash64(s *LSym) goobj.Hash64Type {
   404  	var b goobj.Hash64Type
   405  	copy(b[:], s.P)
   406  	return b
   407  }
   408  
   409  // Compute the content hash for a content-addressable symbol.
   410  // We build a content hash based on its content and relocations.
   411  // Depending on the category of the referenced symbol, we choose
   412  // different hash algorithms such that the hash is globally
   413  // consistent.
   414  // - For referenced content-addressable symbol, its content hash
   415  //   is globally consistent.
   416  // - For package symbol and builtin symbol, its local index is
   417  //   globally consistent.
   418  // - For non-package symbol, its fully-expanded name is globally
   419  //   consistent. For now, we require we know the current package
   420  //   path so we can always expand symbol names. (Otherwise,
   421  //   symbols with relocations are not considered hashable.)
   422  //
   423  // For now, we assume there is no circular dependencies among
   424  // hashed symbols.
   425  func (w *writer) contentHash(s *LSym) goobj.HashType {
   426  	h := sha1.New()
   427  	var tmp [14]byte
   428  
   429  	// Include the size of the symbol in the hash.
   430  	// This preserves the length of symbols, preventing the following two symbols
   431  	// from hashing the same:
   432  	//
   433  	//    [2]int{1,2} ≠ [10]int{1,2,0,0,0...}
   434  	//
   435  	// In this case, if the smaller symbol is alive, the larger is not kept unless
   436  	// needed.
   437  	binary.LittleEndian.PutUint64(tmp[:8], uint64(s.Size))
   438  	h.Write(tmp[:8])
   439  
   440  	// Don't dedup type symbols with others, as they are in a different
   441  	// section.
   442  	if strings.HasPrefix(s.Name, "type.") {
   443  		h.Write([]byte{'T'})
   444  	} else {
   445  		h.Write([]byte{0})
   446  	}
   447  	// The compiler trims trailing zeros _sometimes_. We just do
   448  	// it always.
   449  	h.Write(bytes.TrimRight(s.P, "\x00"))
   450  	for i := range s.R {
   451  		r := &s.R[i]
   452  		binary.LittleEndian.PutUint32(tmp[:4], uint32(r.Off))
   453  		tmp[4] = r.Siz
   454  		tmp[5] = uint8(r.Type)
   455  		binary.LittleEndian.PutUint64(tmp[6:14], uint64(r.Add))
   456  		h.Write(tmp[:])
   457  		rs := r.Sym
   458  		switch rs.PkgIdx {
   459  		case goobj.PkgIdxHashed64:
   460  			h.Write([]byte{0})
   461  			t := contentHash64(rs)
   462  			h.Write(t[:])
   463  		case goobj.PkgIdxHashed:
   464  			h.Write([]byte{1})
   465  			t := w.contentHash(rs)
   466  			h.Write(t[:])
   467  		case goobj.PkgIdxNone:
   468  			h.Write([]byte{2})
   469  			io.WriteString(h, rs.Name) // name is already expanded at this point
   470  		case goobj.PkgIdxBuiltin:
   471  			h.Write([]byte{3})
   472  			binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
   473  			h.Write(tmp[:4])
   474  		case goobj.PkgIdxSelf:
   475  			io.WriteString(h, w.pkgpath)
   476  			binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
   477  			h.Write(tmp[:4])
   478  		default:
   479  			io.WriteString(h, rs.Pkg)
   480  			binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
   481  			h.Write(tmp[:4])
   482  		}
   483  	}
   484  	var b goobj.HashType
   485  	copy(b[:], h.Sum(nil))
   486  	return b
   487  }
   488  
   489  func makeSymRef(s *LSym) goobj.SymRef {
   490  	if s == nil {
   491  		return goobj.SymRef{}
   492  	}
   493  	if s.PkgIdx == 0 || !s.Indexed() {
   494  		fmt.Printf("unindexed symbol reference: %v\n", s)
   495  		panic("unindexed symbol reference")
   496  	}
   497  	return goobj.SymRef{PkgIdx: uint32(s.PkgIdx), SymIdx: uint32(s.SymIdx)}
   498  }
   499  
   500  func (w *writer) Reloc(r *Reloc) {
   501  	var o goobj.Reloc
   502  	o.SetOff(r.Off)
   503  	o.SetSiz(r.Siz)
   504  	o.SetType(uint8(r.Type))
   505  	o.SetAdd(r.Add)
   506  	o.SetSym(makeSymRef(r.Sym))
   507  	o.Write(w.Writer)
   508  }
   509  
   510  func (w *writer) aux1(typ uint8, rs *LSym) {
   511  	var o goobj.Aux
   512  	o.SetType(typ)
   513  	o.SetSym(makeSymRef(rs))
   514  	o.Write(w.Writer)
   515  }
   516  
   517  func (w *writer) Aux(s *LSym) {
   518  	if s.Gotype != nil {
   519  		w.aux1(goobj.AuxGotype, s.Gotype)
   520  	}
   521  	if fn := s.Func(); fn != nil {
   522  		w.aux1(goobj.AuxFuncInfo, fn.FuncInfoSym)
   523  
   524  		for _, d := range fn.Pcln.Funcdata {
   525  			w.aux1(goobj.AuxFuncdata, d)
   526  		}
   527  
   528  		if fn.dwarfInfoSym != nil && fn.dwarfInfoSym.Size != 0 {
   529  			w.aux1(goobj.AuxDwarfInfo, fn.dwarfInfoSym)
   530  		}
   531  		if fn.dwarfLocSym != nil && fn.dwarfLocSym.Size != 0 {
   532  			w.aux1(goobj.AuxDwarfLoc, fn.dwarfLocSym)
   533  		}
   534  		if fn.dwarfRangesSym != nil && fn.dwarfRangesSym.Size != 0 {
   535  			w.aux1(goobj.AuxDwarfRanges, fn.dwarfRangesSym)
   536  		}
   537  		if fn.dwarfDebugLinesSym != nil && fn.dwarfDebugLinesSym.Size != 0 {
   538  			w.aux1(goobj.AuxDwarfLines, fn.dwarfDebugLinesSym)
   539  		}
   540  		if fn.Pcln.Pcsp != nil && fn.Pcln.Pcsp.Size != 0 {
   541  			w.aux1(goobj.AuxPcsp, fn.Pcln.Pcsp)
   542  		}
   543  		if fn.Pcln.Pcfile != nil && fn.Pcln.Pcfile.Size != 0 {
   544  			w.aux1(goobj.AuxPcfile, fn.Pcln.Pcfile)
   545  		}
   546  		if fn.Pcln.Pcline != nil && fn.Pcln.Pcline.Size != 0 {
   547  			w.aux1(goobj.AuxPcline, fn.Pcln.Pcline)
   548  		}
   549  		if fn.Pcln.Pcinline != nil && fn.Pcln.Pcinline.Size != 0 {
   550  			w.aux1(goobj.AuxPcinline, fn.Pcln.Pcinline)
   551  		}
   552  		for _, pcSym := range fn.Pcln.Pcdata {
   553  			w.aux1(goobj.AuxPcdata, pcSym)
   554  		}
   555  
   556  	}
   557  }
   558  
   559  // Emits flags of referenced indexed symbols.
   560  func (w *writer) refFlags() {
   561  	seen := make(map[*LSym]bool)
   562  	w.ctxt.traverseSyms(traverseRefs, func(rs *LSym) { // only traverse refs, not auxs, as tools don't need auxs
   563  		switch rs.PkgIdx {
   564  		case goobj.PkgIdxNone, goobj.PkgIdxHashed64, goobj.PkgIdxHashed, goobj.PkgIdxBuiltin, goobj.PkgIdxSelf: // not an external indexed reference
   565  			return
   566  		case goobj.PkgIdxInvalid:
   567  			panic("unindexed symbol reference")
   568  		}
   569  		if seen[rs] {
   570  			return
   571  		}
   572  		seen[rs] = true
   573  		symref := makeSymRef(rs)
   574  		flag2 := uint8(0)
   575  		if rs.UsedInIface() {
   576  			flag2 |= goobj.SymFlagUsedInIface
   577  		}
   578  		if flag2 == 0 {
   579  			return // no need to write zero flags
   580  		}
   581  		var o goobj.RefFlags
   582  		o.SetSym(symref)
   583  		o.SetFlag2(flag2)
   584  		o.Write(w.Writer)
   585  	})
   586  }
   587  
   588  // Emits names of referenced indexed symbols, used by tools (objdump, nm)
   589  // only.
   590  func (w *writer) refNames() {
   591  	seen := make(map[*LSym]bool)
   592  	w.ctxt.traverseSyms(traverseRefs, func(rs *LSym) { // only traverse refs, not auxs, as tools don't need auxs
   593  		switch rs.PkgIdx {
   594  		case goobj.PkgIdxNone, goobj.PkgIdxHashed64, goobj.PkgIdxHashed, goobj.PkgIdxBuiltin, goobj.PkgIdxSelf: // not an external indexed reference
   595  			return
   596  		case goobj.PkgIdxInvalid:
   597  			panic("unindexed symbol reference")
   598  		}
   599  		if seen[rs] {
   600  			return
   601  		}
   602  		seen[rs] = true
   603  		symref := makeSymRef(rs)
   604  		var o goobj.RefName
   605  		o.SetSym(symref)
   606  		o.SetName(rs.Name, w.Writer)
   607  		o.Write(w.Writer)
   608  	})
   609  	// TODO: output in sorted order?
   610  	// Currently tools (cmd/internal/goobj package) doesn't use mmap,
   611  	// and it just read it into a map in memory upfront. If it uses
   612  	// mmap, if the output is sorted, it probably could avoid reading
   613  	// into memory and just do lookups in the mmap'd object file.
   614  }
   615  
   616  // return the number of aux symbols s have.
   617  func nAuxSym(s *LSym) int {
   618  	n := 0
   619  	if s.Gotype != nil {
   620  		n++
   621  	}
   622  	if fn := s.Func(); fn != nil {
   623  		// FuncInfo is an aux symbol, each Funcdata is an aux symbol
   624  		n += 1 + len(fn.Pcln.Funcdata)
   625  		if fn.dwarfInfoSym != nil && fn.dwarfInfoSym.Size != 0 {
   626  			n++
   627  		}
   628  		if fn.dwarfLocSym != nil && fn.dwarfLocSym.Size != 0 {
   629  			n++
   630  		}
   631  		if fn.dwarfRangesSym != nil && fn.dwarfRangesSym.Size != 0 {
   632  			n++
   633  		}
   634  		if fn.dwarfDebugLinesSym != nil && fn.dwarfDebugLinesSym.Size != 0 {
   635  			n++
   636  		}
   637  		if fn.Pcln.Pcsp != nil && fn.Pcln.Pcsp.Size != 0 {
   638  			n++
   639  		}
   640  		if fn.Pcln.Pcfile != nil && fn.Pcln.Pcfile.Size != 0 {
   641  			n++
   642  		}
   643  		if fn.Pcln.Pcline != nil && fn.Pcln.Pcline.Size != 0 {
   644  			n++
   645  		}
   646  		if fn.Pcln.Pcinline != nil && fn.Pcln.Pcinline.Size != 0 {
   647  			n++
   648  		}
   649  		n += len(fn.Pcln.Pcdata)
   650  	}
   651  	return n
   652  }
   653  
   654  // generate symbols for FuncInfo.
   655  func genFuncInfoSyms(ctxt *Link) {
   656  	infosyms := make([]*LSym, 0, len(ctxt.Text))
   657  	hashedsyms := make([]*LSym, 0, 4*len(ctxt.Text))
   658  	preparePcSym := func(s *LSym) *LSym {
   659  		if s == nil {
   660  			return s
   661  		}
   662  		s.PkgIdx = goobj.PkgIdxHashed
   663  		s.SymIdx = int32(len(hashedsyms) + len(ctxt.hasheddefs))
   664  		s.Set(AttrIndexed, true)
   665  		hashedsyms = append(hashedsyms, s)
   666  		return s
   667  	}
   668  	var b bytes.Buffer
   669  	symidx := int32(len(ctxt.defs))
   670  	for _, s := range ctxt.Text {
   671  		fn := s.Func()
   672  		if fn == nil {
   673  			continue
   674  		}
   675  		o := goobj.FuncInfo{
   676  			Args:   uint32(fn.Args),
   677  			Locals: uint32(fn.Locals),
   678  			FuncID: objabi.FuncID(fn.FuncID),
   679  		}
   680  		pc := &fn.Pcln
   681  		o.Pcsp = makeSymRef(preparePcSym(pc.Pcsp))
   682  		o.Pcfile = makeSymRef(preparePcSym(pc.Pcfile))
   683  		o.Pcline = makeSymRef(preparePcSym(pc.Pcline))
   684  		o.Pcinline = makeSymRef(preparePcSym(pc.Pcinline))
   685  		o.Pcdata = make([]goobj.SymRef, len(pc.Pcdata))
   686  		for i, pcSym := range pc.Pcdata {
   687  			o.Pcdata[i] = makeSymRef(preparePcSym(pcSym))
   688  		}
   689  		o.Funcdataoff = make([]uint32, len(pc.Funcdataoff))
   690  		for i, x := range pc.Funcdataoff {
   691  			o.Funcdataoff[i] = uint32(x)
   692  		}
   693  		i := 0
   694  		o.File = make([]goobj.CUFileIndex, len(pc.UsedFiles))
   695  		for f := range pc.UsedFiles {
   696  			o.File[i] = f
   697  			i++
   698  		}
   699  		sort.Slice(o.File, func(i, j int) bool { return o.File[i] < o.File[j] })
   700  		o.InlTree = make([]goobj.InlTreeNode, len(pc.InlTree.nodes))
   701  		for i, inl := range pc.InlTree.nodes {
   702  			f, l := getFileIndexAndLine(ctxt, inl.Pos)
   703  			o.InlTree[i] = goobj.InlTreeNode{
   704  				Parent:   int32(inl.Parent),
   705  				File:     goobj.CUFileIndex(f),
   706  				Line:     l,
   707  				Func:     makeSymRef(inl.Func),
   708  				ParentPC: inl.ParentPC,
   709  			}
   710  		}
   711  
   712  		o.Write(&b)
   713  		isym := &LSym{
   714  			Type:   objabi.SDATA, // for now, I don't think it matters
   715  			PkgIdx: goobj.PkgIdxSelf,
   716  			SymIdx: symidx,
   717  			P:      append([]byte(nil), b.Bytes()...),
   718  		}
   719  		isym.Set(AttrIndexed, true)
   720  		symidx++
   721  		infosyms = append(infosyms, isym)
   722  		fn.FuncInfoSym = isym
   723  		b.Reset()
   724  
   725  		dwsyms := []*LSym{fn.dwarfRangesSym, fn.dwarfLocSym, fn.dwarfDebugLinesSym, fn.dwarfInfoSym}
   726  		for _, s := range dwsyms {
   727  			if s == nil || s.Size == 0 {
   728  				continue
   729  			}
   730  			s.PkgIdx = goobj.PkgIdxSelf
   731  			s.SymIdx = symidx
   732  			s.Set(AttrIndexed, true)
   733  			symidx++
   734  			infosyms = append(infosyms, s)
   735  		}
   736  	}
   737  	ctxt.defs = append(ctxt.defs, infosyms...)
   738  	ctxt.hasheddefs = append(ctxt.hasheddefs, hashedsyms...)
   739  }
   740  
   741  func writeAuxSymDebug(ctxt *Link, par *LSym, aux *LSym) {
   742  	// Most aux symbols (ex: funcdata) are not interesting--
   743  	// pick out just the DWARF ones for now.
   744  	if aux.Type != objabi.SDWARFLOC &&
   745  		aux.Type != objabi.SDWARFFCN &&
   746  		aux.Type != objabi.SDWARFABSFCN &&
   747  		aux.Type != objabi.SDWARFLINES &&
   748  		aux.Type != objabi.SDWARFRANGE {
   749  		return
   750  	}
   751  	ctxt.writeSymDebugNamed(aux, "aux for "+par.Name)
   752  }
   753  
   754  func debugAsmEmit(ctxt *Link) {
   755  	if ctxt.Debugasm > 0 {
   756  		ctxt.traverseSyms(traverseDefs, ctxt.writeSymDebug)
   757  		if ctxt.Debugasm > 1 {
   758  			fn := func(par *LSym, aux *LSym) {
   759  				writeAuxSymDebug(ctxt, par, aux)
   760  			}
   761  			ctxt.traverseAuxSyms(traverseAux, fn)
   762  		}
   763  	}
   764  }
   765  
   766  func (ctxt *Link) writeSymDebug(s *LSym) {
   767  	ctxt.writeSymDebugNamed(s, s.Name)
   768  }
   769  
   770  func (ctxt *Link) writeSymDebugNamed(s *LSym, name string) {
   771  	ver := ""
   772  	if ctxt.Debugasm > 1 {
   773  		ver = fmt.Sprintf("<%d>", s.ABI())
   774  	}
   775  	fmt.Fprintf(ctxt.Bso, "%s%s ", name, ver)
   776  	if s.Type != 0 {
   777  		fmt.Fprintf(ctxt.Bso, "%v ", s.Type)
   778  	}
   779  	if s.Static() {
   780  		fmt.Fprint(ctxt.Bso, "static ")
   781  	}
   782  	if s.DuplicateOK() {
   783  		fmt.Fprintf(ctxt.Bso, "dupok ")
   784  	}
   785  	if s.CFunc() {
   786  		fmt.Fprintf(ctxt.Bso, "cfunc ")
   787  	}
   788  	if s.NoSplit() {
   789  		fmt.Fprintf(ctxt.Bso, "nosplit ")
   790  	}
   791  	if s.TopFrame() {
   792  		fmt.Fprintf(ctxt.Bso, "topframe ")
   793  	}
   794  	fmt.Fprintf(ctxt.Bso, "size=%d", s.Size)
   795  	if s.Type == objabi.STEXT {
   796  		fn := s.Func()
   797  		fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x funcid=%#x", uint64(fn.Args), uint64(fn.Locals), uint64(fn.FuncID))
   798  		if s.Leaf() {
   799  			fmt.Fprintf(ctxt.Bso, " leaf")
   800  		}
   801  	}
   802  	fmt.Fprintf(ctxt.Bso, "\n")
   803  	if s.Type == objabi.STEXT {
   804  		for p := s.Func().Text; p != nil; p = p.Link {
   805  			fmt.Fprintf(ctxt.Bso, "\t%#04x ", uint(int(p.Pc)))
   806  			if ctxt.Debugasm > 1 {
   807  				io.WriteString(ctxt.Bso, p.String())
   808  			} else {
   809  				p.InnermostString(ctxt.Bso)
   810  			}
   811  			fmt.Fprintln(ctxt.Bso)
   812  		}
   813  	}
   814  	for i := 0; i < len(s.P); i += 16 {
   815  		fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i))
   816  		j := i
   817  		for ; j < i+16 && j < len(s.P); j++ {
   818  			fmt.Fprintf(ctxt.Bso, " %02x", s.P[j])
   819  		}
   820  		for ; j < i+16; j++ {
   821  			fmt.Fprintf(ctxt.Bso, "   ")
   822  		}
   823  		fmt.Fprintf(ctxt.Bso, "  ")
   824  		for j = i; j < i+16 && j < len(s.P); j++ {
   825  			c := int(s.P[j])
   826  			b := byte('.')
   827  			if ' ' <= c && c <= 0x7e {
   828  				b = byte(c)
   829  			}
   830  			ctxt.Bso.WriteByte(b)
   831  		}
   832  
   833  		fmt.Fprintf(ctxt.Bso, "\n")
   834  	}
   835  
   836  	sort.Sort(relocByOff(s.R)) // generate stable output
   837  	for _, r := range s.R {
   838  		name := ""
   839  		ver := ""
   840  		if r.Sym != nil {
   841  			name = r.Sym.Name
   842  			if ctxt.Debugasm > 1 {
   843  				ver = fmt.Sprintf("<%d>", r.Sym.ABI())
   844  			}
   845  		} else if r.Type == objabi.R_TLS_LE {
   846  			name = "TLS"
   847  		}
   848  		if ctxt.Arch.InFamily(sys.ARM, sys.PPC64) {
   849  			fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s%s+%x\n", int(r.Off), r.Siz, r.Type, name, ver, uint64(r.Add))
   850  		} else {
   851  			fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s%s+%d\n", int(r.Off), r.Siz, r.Type, name, ver, r.Add)
   852  		}
   853  	}
   854  }
   855  
   856  // relocByOff sorts relocations by their offsets.
   857  type relocByOff []Reloc
   858  
   859  func (x relocByOff) Len() int           { return len(x) }
   860  func (x relocByOff) Less(i, j int) bool { return x[i].Off < x[j].Off }
   861  func (x relocByOff) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
   862  

View as plain text