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

     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  	// Blocks used only by tools (objdump, nm).
   197  
   198  	// Referenced symbol names from other packages
   199  	h.Offsets[goobj.BlkRefName] = w.Offset()
   200  	w.refNames()
   201  
   202  	h.Offsets[goobj.BlkEnd] = w.Offset()
   203  
   204  	// Fix up block offsets in the header
   205  	end := start + int64(w.Offset())
   206  	b.MustSeek(start, 0)
   207  	h.Write(w.Writer)
   208  	b.MustSeek(end, 0)
   209  }
   210  
   211  type writer struct {
   212  	*goobj.Writer
   213  	filebuf []byte
   214  	ctxt    *Link
   215  	pkgpath string   // the package import path (escaped), "" if unknown
   216  	pkglist []string // list of packages referenced, indexed by ctxt.pkgIdx
   217  }
   218  
   219  // prepare package index list
   220  func (w *writer) init() {
   221  	w.pkglist = make([]string, len(w.ctxt.pkgIdx)+1)
   222  	w.pkglist[0] = "" // dummy invalid package for index 0
   223  	for pkg, i := range w.ctxt.pkgIdx {
   224  		w.pkglist[i] = pkg
   225  	}
   226  }
   227  
   228  func (w *writer) writeFile(ctxt *Link, file *FileInfo) {
   229  	f, err := os.Open(file.Name)
   230  	if err != nil {
   231  		ctxt.Diag("%v", err)
   232  		return
   233  	}
   234  	defer f.Close()
   235  	if w.filebuf == nil {
   236  		w.filebuf = make([]byte, 1024)
   237  	}
   238  	buf := w.filebuf
   239  	written := int64(0)
   240  	for {
   241  		n, err := f.Read(buf)
   242  		w.Bytes(buf[:n])
   243  		written += int64(n)
   244  		if err == io.EOF {
   245  			break
   246  		}
   247  		if err != nil {
   248  			ctxt.Diag("%v", err)
   249  			return
   250  		}
   251  	}
   252  	if written != file.Size {
   253  		ctxt.Diag("copy %s: unexpected length %d != %d", file.Name, written, file.Size)
   254  	}
   255  }
   256  
   257  func (w *writer) StringTable() {
   258  	w.AddString("")
   259  	for _, p := range w.ctxt.Imports {
   260  		w.AddString(p.Pkg)
   261  	}
   262  	for _, pkg := range w.pkglist {
   263  		w.AddString(pkg)
   264  	}
   265  	w.ctxt.traverseSyms(traverseAll, func(s *LSym) {
   266  		// TODO: this includes references of indexed symbols from other packages,
   267  		// for which the linker doesn't need the name. Consider moving them to
   268  		// a separate block (for tools only).
   269  		if w.pkgpath != "" {
   270  			s.Name = strings.Replace(s.Name, "\"\".", w.pkgpath+".", -1)
   271  		}
   272  		// Don't put names of builtins into the string table (to save
   273  		// space).
   274  		if s.PkgIdx == goobj.PkgIdxBuiltin {
   275  			return
   276  		}
   277  		w.AddString(s.Name)
   278  	})
   279  
   280  	// All filenames are in the postable.
   281  	for _, f := range w.ctxt.PosTable.FileTable() {
   282  		w.AddString(filepath.ToSlash(f))
   283  	}
   284  }
   285  
   286  // cutoff is the maximum data section size permitted by the linker
   287  // (see issue #9862).
   288  const cutoff = int64(2e9) // 2 GB (or so; looks better in errors than 2^31)
   289  
   290  func (w *writer) Sym(s *LSym) {
   291  	abi := uint16(s.ABI())
   292  	if s.Static() {
   293  		abi = goobj.SymABIstatic
   294  	}
   295  	flag := uint8(0)
   296  	if s.DuplicateOK() {
   297  		flag |= goobj.SymFlagDupok
   298  	}
   299  	if s.Local() {
   300  		flag |= goobj.SymFlagLocal
   301  	}
   302  	if s.MakeTypelink() {
   303  		flag |= goobj.SymFlagTypelink
   304  	}
   305  	if s.Leaf() {
   306  		flag |= goobj.SymFlagLeaf
   307  	}
   308  	if s.NoSplit() {
   309  		flag |= goobj.SymFlagNoSplit
   310  	}
   311  	if s.ReflectMethod() {
   312  		flag |= goobj.SymFlagReflectMethod
   313  	}
   314  	if strings.HasPrefix(s.Name, "type.") && s.Name[5] != '.' && s.Type == objabi.SRODATA {
   315  		flag |= goobj.SymFlagGoType
   316  	}
   317  	flag2 := uint8(0)
   318  	if s.UsedInIface() {
   319  		flag2 |= goobj.SymFlagUsedInIface
   320  	}
   321  	if strings.HasPrefix(s.Name, "go.itab.") && s.Type == objabi.SRODATA {
   322  		flag2 |= goobj.SymFlagItab
   323  	}
   324  	if strings.HasPrefix(s.Name, w.ctxt.Pkgpath) && strings.HasPrefix(s.Name[len(w.ctxt.Pkgpath):], ".") && strings.HasPrefix(s.Name[len(w.ctxt.Pkgpath)+1:], objabi.GlobalDictPrefix) {
   325  		flag2 |= goobj.SymFlagDict
   326  	}
   327  	name := s.Name
   328  	if strings.HasPrefix(name, "gofile..") {
   329  		name = filepath.ToSlash(name)
   330  	}
   331  	var align uint32
   332  	if fn := s.Func(); fn != nil {
   333  		align = uint32(fn.Align)
   334  	}
   335  	if s.ContentAddressable() && s.Size != 0 {
   336  		// We generally assume data symbols are natually aligned
   337  		// (e.g. integer constants), except for strings and a few
   338  		// compiler-emitted funcdata. If we dedup a string symbol and
   339  		// a non-string symbol with the same content, we should keep
   340  		// the largest alignment.
   341  		// TODO: maybe the compiler could set the alignment for all
   342  		// data symbols more carefully.
   343  		switch {
   344  		case strings.HasPrefix(s.Name, "go.string."),
   345  			strings.HasPrefix(name, "type..namedata."),
   346  			strings.HasPrefix(name, "type..importpath."),
   347  			strings.HasPrefix(name, "runtime.gcbits."),
   348  			strings.HasSuffix(name, ".opendefer"),
   349  			strings.HasSuffix(name, ".arginfo0"),
   350  			strings.HasSuffix(name, ".arginfo1"),
   351  			strings.HasSuffix(name, ".argliveinfo"):
   352  			// These are just bytes, or varints.
   353  			align = 1
   354  		case strings.HasPrefix(name, "gclocals·"):
   355  			// It has 32-bit fields.
   356  			align = 4
   357  		default:
   358  			switch {
   359  			case w.ctxt.Arch.PtrSize == 8 && s.Size%8 == 0:
   360  				align = 8
   361  			case s.Size%4 == 0:
   362  				align = 4
   363  			case s.Size%2 == 0:
   364  				align = 2
   365  			default:
   366  				align = 1
   367  			}
   368  		}
   369  	}
   370  	if s.Size > cutoff {
   371  		w.ctxt.Diag("%s: symbol too large (%d bytes > %d bytes)", s.Name, s.Size, cutoff)
   372  	}
   373  	var o goobj.Sym
   374  	o.SetName(name, w.Writer)
   375  	o.SetABI(abi)
   376  	o.SetType(uint8(s.Type))
   377  	o.SetFlag(flag)
   378  	o.SetFlag2(flag2)
   379  	o.SetSiz(uint32(s.Size))
   380  	o.SetAlign(align)
   381  	o.Write(w.Writer)
   382  }
   383  
   384  func (w *writer) Hash64(s *LSym) {
   385  	if !s.ContentAddressable() || len(s.R) != 0 {
   386  		panic("Hash of non-content-addressable symbol")
   387  	}
   388  	b := contentHash64(s)
   389  	w.Bytes(b[:])
   390  }
   391  
   392  func (w *writer) Hash(s *LSym) {
   393  	if !s.ContentAddressable() {
   394  		panic("Hash of non-content-addressable symbol")
   395  	}
   396  	b := w.contentHash(s)
   397  	w.Bytes(b[:])
   398  }
   399  
   400  // contentHashSection returns a mnemonic for s's section.
   401  // The goal is to prevent content-addressability from moving symbols between sections.
   402  // contentHashSection only distinguishes between sets of sections for which this matters.
   403  // Allowing flexibility increases the effectiveness of content-addressibility.
   404  // But in some cases, such as doing addressing based on a base symbol,
   405  // we need to ensure that a symbol is always in a prticular section.
   406  // Some of these conditions are duplicated in cmd/link/internal/ld.(*Link).symtab.
   407  // TODO: instead of duplicating them, have the compiler decide where symbols go.
   408  func contentHashSection(s *LSym) byte {
   409  	name := s.Name
   410  	if s.IsPcdata() {
   411  		return 'P'
   412  	}
   413  	if strings.HasPrefix(name, "gcargs.") ||
   414  		strings.HasPrefix(name, "gclocals.") ||
   415  		strings.HasPrefix(name, "gclocals·") ||
   416  		strings.HasSuffix(name, ".opendefer") ||
   417  		strings.HasSuffix(name, ".arginfo0") ||
   418  		strings.HasSuffix(name, ".arginfo1") ||
   419  		strings.HasSuffix(name, ".argliveinfo") ||
   420  		strings.HasSuffix(name, ".wrapinfo") ||
   421  		strings.HasSuffix(name, ".args_stackmap") ||
   422  		strings.HasSuffix(name, ".stkobj") {
   423  		return 'F' // go.func.* or go.funcrel.*
   424  	}
   425  	if strings.HasPrefix(name, "type.") {
   426  		return 'T'
   427  	}
   428  	return 0
   429  }
   430  
   431  func contentHash64(s *LSym) goobj.Hash64Type {
   432  	if contentHashSection(s) != 0 {
   433  		panic("short hash of non-default-section sym " + s.Name)
   434  	}
   435  	var b goobj.Hash64Type
   436  	copy(b[:], s.P)
   437  	return b
   438  }
   439  
   440  // Compute the content hash for a content-addressable symbol.
   441  // We build a content hash based on its content and relocations.
   442  // Depending on the category of the referenced symbol, we choose
   443  // different hash algorithms such that the hash is globally
   444  // consistent.
   445  // - For referenced content-addressable symbol, its content hash
   446  //   is globally consistent.
   447  // - For package symbol and builtin symbol, its local index is
   448  //   globally consistent.
   449  // - For non-package symbol, its fully-expanded name is globally
   450  //   consistent. For now, we require we know the current package
   451  //   path so we can always expand symbol names. (Otherwise,
   452  //   symbols with relocations are not considered hashable.)
   453  //
   454  // For now, we assume there is no circular dependencies among
   455  // hashed symbols.
   456  func (w *writer) contentHash(s *LSym) goobj.HashType {
   457  	h := sha1.New()
   458  	var tmp [14]byte
   459  
   460  	// Include the size of the symbol in the hash.
   461  	// This preserves the length of symbols, preventing the following two symbols
   462  	// from hashing the same:
   463  	//
   464  	//    [2]int{1,2} ≠ [10]int{1,2,0,0,0...}
   465  	//
   466  	// In this case, if the smaller symbol is alive, the larger is not kept unless
   467  	// needed.
   468  	binary.LittleEndian.PutUint64(tmp[:8], uint64(s.Size))
   469  	// Some symbols require being in separate sections.
   470  	tmp[8] = contentHashSection(s)
   471  	h.Write(tmp[:9])
   472  
   473  	// The compiler trims trailing zeros _sometimes_. We just do
   474  	// it always.
   475  	h.Write(bytes.TrimRight(s.P, "\x00"))
   476  	for i := range s.R {
   477  		r := &s.R[i]
   478  		binary.LittleEndian.PutUint32(tmp[:4], uint32(r.Off))
   479  		tmp[4] = r.Siz
   480  		tmp[5] = uint8(r.Type)
   481  		binary.LittleEndian.PutUint64(tmp[6:14], uint64(r.Add))
   482  		h.Write(tmp[:])
   483  		rs := r.Sym
   484  		if rs == nil {
   485  			fmt.Printf("symbol: %s\n", s)
   486  			fmt.Printf("relocation: %#v\n", r)
   487  			panic("nil symbol target in relocation")
   488  		}
   489  		switch rs.PkgIdx {
   490  		case goobj.PkgIdxHashed64:
   491  			h.Write([]byte{0})
   492  			t := contentHash64(rs)
   493  			h.Write(t[:])
   494  		case goobj.PkgIdxHashed:
   495  			h.Write([]byte{1})
   496  			t := w.contentHash(rs)
   497  			h.Write(t[:])
   498  		case goobj.PkgIdxNone:
   499  			h.Write([]byte{2})
   500  			io.WriteString(h, rs.Name) // name is already expanded at this point
   501  		case goobj.PkgIdxBuiltin:
   502  			h.Write([]byte{3})
   503  			binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
   504  			h.Write(tmp[:4])
   505  		case goobj.PkgIdxSelf:
   506  			io.WriteString(h, w.pkgpath)
   507  			binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
   508  			h.Write(tmp[:4])
   509  		default:
   510  			io.WriteString(h, rs.Pkg)
   511  			binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
   512  			h.Write(tmp[:4])
   513  		}
   514  	}
   515  	var b goobj.HashType
   516  	copy(b[:], h.Sum(nil))
   517  	return b
   518  }
   519  
   520  func makeSymRef(s *LSym) goobj.SymRef {
   521  	if s == nil {
   522  		return goobj.SymRef{}
   523  	}
   524  	if s.PkgIdx == 0 || !s.Indexed() {
   525  		fmt.Printf("unindexed symbol reference: %v\n", s)
   526  		panic("unindexed symbol reference")
   527  	}
   528  	return goobj.SymRef{PkgIdx: uint32(s.PkgIdx), SymIdx: uint32(s.SymIdx)}
   529  }
   530  
   531  func (w *writer) Reloc(r *Reloc) {
   532  	var o goobj.Reloc
   533  	o.SetOff(r.Off)
   534  	o.SetSiz(r.Siz)
   535  	o.SetType(uint16(r.Type))
   536  	o.SetAdd(r.Add)
   537  	o.SetSym(makeSymRef(r.Sym))
   538  	o.Write(w.Writer)
   539  }
   540  
   541  func (w *writer) aux1(typ uint8, rs *LSym) {
   542  	var o goobj.Aux
   543  	o.SetType(typ)
   544  	o.SetSym(makeSymRef(rs))
   545  	o.Write(w.Writer)
   546  }
   547  
   548  func (w *writer) Aux(s *LSym) {
   549  	if s.Gotype != nil {
   550  		w.aux1(goobj.AuxGotype, s.Gotype)
   551  	}
   552  	if fn := s.Func(); fn != nil {
   553  		w.aux1(goobj.AuxFuncInfo, fn.FuncInfoSym)
   554  
   555  		for _, d := range fn.Pcln.Funcdata {
   556  			w.aux1(goobj.AuxFuncdata, d)
   557  		}
   558  
   559  		if fn.dwarfInfoSym != nil && fn.dwarfInfoSym.Size != 0 {
   560  			w.aux1(goobj.AuxDwarfInfo, fn.dwarfInfoSym)
   561  		}
   562  		if fn.dwarfLocSym != nil && fn.dwarfLocSym.Size != 0 {
   563  			w.aux1(goobj.AuxDwarfLoc, fn.dwarfLocSym)
   564  		}
   565  		if fn.dwarfRangesSym != nil && fn.dwarfRangesSym.Size != 0 {
   566  			w.aux1(goobj.AuxDwarfRanges, fn.dwarfRangesSym)
   567  		}
   568  		if fn.dwarfDebugLinesSym != nil && fn.dwarfDebugLinesSym.Size != 0 {
   569  			w.aux1(goobj.AuxDwarfLines, fn.dwarfDebugLinesSym)
   570  		}
   571  		if fn.Pcln.Pcsp != nil && fn.Pcln.Pcsp.Size != 0 {
   572  			w.aux1(goobj.AuxPcsp, fn.Pcln.Pcsp)
   573  		}
   574  		if fn.Pcln.Pcfile != nil && fn.Pcln.Pcfile.Size != 0 {
   575  			w.aux1(goobj.AuxPcfile, fn.Pcln.Pcfile)
   576  		}
   577  		if fn.Pcln.Pcline != nil && fn.Pcln.Pcline.Size != 0 {
   578  			w.aux1(goobj.AuxPcline, fn.Pcln.Pcline)
   579  		}
   580  		if fn.Pcln.Pcinline != nil && fn.Pcln.Pcinline.Size != 0 {
   581  			w.aux1(goobj.AuxPcinline, fn.Pcln.Pcinline)
   582  		}
   583  		for _, pcSym := range fn.Pcln.Pcdata {
   584  			w.aux1(goobj.AuxPcdata, pcSym)
   585  		}
   586  
   587  	}
   588  }
   589  
   590  // Emits flags of referenced indexed symbols.
   591  func (w *writer) refFlags() {
   592  	seen := make(map[*LSym]bool)
   593  	w.ctxt.traverseSyms(traverseRefs, func(rs *LSym) { // only traverse refs, not auxs, as tools don't need auxs
   594  		switch rs.PkgIdx {
   595  		case goobj.PkgIdxNone, goobj.PkgIdxHashed64, goobj.PkgIdxHashed, goobj.PkgIdxBuiltin, goobj.PkgIdxSelf: // not an external indexed reference
   596  			return
   597  		case goobj.PkgIdxInvalid:
   598  			panic("unindexed symbol reference")
   599  		}
   600  		if seen[rs] {
   601  			return
   602  		}
   603  		seen[rs] = true
   604  		symref := makeSymRef(rs)
   605  		flag2 := uint8(0)
   606  		if rs.UsedInIface() {
   607  			flag2 |= goobj.SymFlagUsedInIface
   608  		}
   609  		if flag2 == 0 {
   610  			return // no need to write zero flags
   611  		}
   612  		var o goobj.RefFlags
   613  		o.SetSym(symref)
   614  		o.SetFlag2(flag2)
   615  		o.Write(w.Writer)
   616  	})
   617  }
   618  
   619  // Emits names of referenced indexed symbols, used by tools (objdump, nm)
   620  // only.
   621  func (w *writer) refNames() {
   622  	seen := make(map[*LSym]bool)
   623  	w.ctxt.traverseSyms(traverseRefs, func(rs *LSym) { // only traverse refs, not auxs, as tools don't need auxs
   624  		switch rs.PkgIdx {
   625  		case goobj.PkgIdxNone, goobj.PkgIdxHashed64, goobj.PkgIdxHashed, goobj.PkgIdxBuiltin, goobj.PkgIdxSelf: // not an external indexed reference
   626  			return
   627  		case goobj.PkgIdxInvalid:
   628  			panic("unindexed symbol reference")
   629  		}
   630  		if seen[rs] {
   631  			return
   632  		}
   633  		seen[rs] = true
   634  		symref := makeSymRef(rs)
   635  		var o goobj.RefName
   636  		o.SetSym(symref)
   637  		o.SetName(rs.Name, w.Writer)
   638  		o.Write(w.Writer)
   639  	})
   640  	// TODO: output in sorted order?
   641  	// Currently tools (cmd/internal/goobj package) doesn't use mmap,
   642  	// and it just read it into a map in memory upfront. If it uses
   643  	// mmap, if the output is sorted, it probably could avoid reading
   644  	// into memory and just do lookups in the mmap'd object file.
   645  }
   646  
   647  // return the number of aux symbols s have.
   648  func nAuxSym(s *LSym) int {
   649  	n := 0
   650  	if s.Gotype != nil {
   651  		n++
   652  	}
   653  	if fn := s.Func(); fn != nil {
   654  		// FuncInfo is an aux symbol, each Funcdata is an aux symbol
   655  		n += 1 + len(fn.Pcln.Funcdata)
   656  		if fn.dwarfInfoSym != nil && fn.dwarfInfoSym.Size != 0 {
   657  			n++
   658  		}
   659  		if fn.dwarfLocSym != nil && fn.dwarfLocSym.Size != 0 {
   660  			n++
   661  		}
   662  		if fn.dwarfRangesSym != nil && fn.dwarfRangesSym.Size != 0 {
   663  			n++
   664  		}
   665  		if fn.dwarfDebugLinesSym != nil && fn.dwarfDebugLinesSym.Size != 0 {
   666  			n++
   667  		}
   668  		if fn.Pcln.Pcsp != nil && fn.Pcln.Pcsp.Size != 0 {
   669  			n++
   670  		}
   671  		if fn.Pcln.Pcfile != nil && fn.Pcln.Pcfile.Size != 0 {
   672  			n++
   673  		}
   674  		if fn.Pcln.Pcline != nil && fn.Pcln.Pcline.Size != 0 {
   675  			n++
   676  		}
   677  		if fn.Pcln.Pcinline != nil && fn.Pcln.Pcinline.Size != 0 {
   678  			n++
   679  		}
   680  		n += len(fn.Pcln.Pcdata)
   681  	}
   682  	return n
   683  }
   684  
   685  // generate symbols for FuncInfo.
   686  func genFuncInfoSyms(ctxt *Link) {
   687  	infosyms := make([]*LSym, 0, len(ctxt.Text))
   688  	hashedsyms := make([]*LSym, 0, 4*len(ctxt.Text))
   689  	var b bytes.Buffer
   690  	symidx := int32(len(ctxt.defs))
   691  	for _, s := range ctxt.Text {
   692  		fn := s.Func()
   693  		if fn == nil {
   694  			continue
   695  		}
   696  		o := goobj.FuncInfo{
   697  			Args:     uint32(fn.Args),
   698  			Locals:   uint32(fn.Locals),
   699  			FuncID:   fn.FuncID,
   700  			FuncFlag: fn.FuncFlag,
   701  		}
   702  		pc := &fn.Pcln
   703  		i := 0
   704  		o.File = make([]goobj.CUFileIndex, len(pc.UsedFiles))
   705  		for f := range pc.UsedFiles {
   706  			o.File[i] = f
   707  			i++
   708  		}
   709  		sort.Slice(o.File, func(i, j int) bool { return o.File[i] < o.File[j] })
   710  		o.InlTree = make([]goobj.InlTreeNode, len(pc.InlTree.nodes))
   711  		for i, inl := range pc.InlTree.nodes {
   712  			f, l := getFileIndexAndLine(ctxt, inl.Pos)
   713  			o.InlTree[i] = goobj.InlTreeNode{
   714  				Parent:   int32(inl.Parent),
   715  				File:     goobj.CUFileIndex(f),
   716  				Line:     l,
   717  				Func:     makeSymRef(inl.Func),
   718  				ParentPC: inl.ParentPC,
   719  			}
   720  		}
   721  
   722  		o.Write(&b)
   723  		isym := &LSym{
   724  			Type:   objabi.SDATA, // for now, I don't think it matters
   725  			PkgIdx: goobj.PkgIdxSelf,
   726  			SymIdx: symidx,
   727  			P:      append([]byte(nil), b.Bytes()...),
   728  		}
   729  		isym.Set(AttrIndexed, true)
   730  		symidx++
   731  		infosyms = append(infosyms, isym)
   732  		fn.FuncInfoSym = isym
   733  		b.Reset()
   734  
   735  		dwsyms := []*LSym{fn.dwarfRangesSym, fn.dwarfLocSym, fn.dwarfDebugLinesSym, fn.dwarfInfoSym}
   736  		for _, s := range dwsyms {
   737  			if s == nil || s.Size == 0 {
   738  				continue
   739  			}
   740  			s.PkgIdx = goobj.PkgIdxSelf
   741  			s.SymIdx = symidx
   742  			s.Set(AttrIndexed, true)
   743  			symidx++
   744  			infosyms = append(infosyms, s)
   745  		}
   746  	}
   747  	ctxt.defs = append(ctxt.defs, infosyms...)
   748  	ctxt.hasheddefs = append(ctxt.hasheddefs, hashedsyms...)
   749  }
   750  
   751  func writeAuxSymDebug(ctxt *Link, par *LSym, aux *LSym) {
   752  	// Most aux symbols (ex: funcdata) are not interesting--
   753  	// pick out just the DWARF ones for now.
   754  	if aux.Type != objabi.SDWARFLOC &&
   755  		aux.Type != objabi.SDWARFFCN &&
   756  		aux.Type != objabi.SDWARFABSFCN &&
   757  		aux.Type != objabi.SDWARFLINES &&
   758  		aux.Type != objabi.SDWARFRANGE {
   759  		return
   760  	}
   761  	ctxt.writeSymDebugNamed(aux, "aux for "+par.Name)
   762  }
   763  
   764  func debugAsmEmit(ctxt *Link) {
   765  	if ctxt.Debugasm > 0 {
   766  		ctxt.traverseSyms(traverseDefs, ctxt.writeSymDebug)
   767  		if ctxt.Debugasm > 1 {
   768  			fn := func(par *LSym, aux *LSym) {
   769  				writeAuxSymDebug(ctxt, par, aux)
   770  			}
   771  			ctxt.traverseAuxSyms(traverseAux, fn)
   772  		}
   773  	}
   774  }
   775  
   776  func (ctxt *Link) writeSymDebug(s *LSym) {
   777  	ctxt.writeSymDebugNamed(s, s.Name)
   778  }
   779  
   780  func (ctxt *Link) writeSymDebugNamed(s *LSym, name string) {
   781  	ver := ""
   782  	if ctxt.Debugasm > 1 {
   783  		ver = fmt.Sprintf("<%d>", s.ABI())
   784  	}
   785  	fmt.Fprintf(ctxt.Bso, "%s%s ", name, ver)
   786  	if s.Type != 0 {
   787  		fmt.Fprintf(ctxt.Bso, "%v ", s.Type)
   788  	}
   789  	if s.Static() {
   790  		fmt.Fprint(ctxt.Bso, "static ")
   791  	}
   792  	if s.DuplicateOK() {
   793  		fmt.Fprintf(ctxt.Bso, "dupok ")
   794  	}
   795  	if s.CFunc() {
   796  		fmt.Fprintf(ctxt.Bso, "cfunc ")
   797  	}
   798  	if s.NoSplit() {
   799  		fmt.Fprintf(ctxt.Bso, "nosplit ")
   800  	}
   801  	if s.Func() != nil && s.Func().FuncFlag&objabi.FuncFlag_TOPFRAME != 0 {
   802  		fmt.Fprintf(ctxt.Bso, "topframe ")
   803  	}
   804  	if s.Func() != nil && s.Func().FuncFlag&objabi.FuncFlag_ASM != 0 {
   805  		fmt.Fprintf(ctxt.Bso, "asm ")
   806  	}
   807  	fmt.Fprintf(ctxt.Bso, "size=%d", s.Size)
   808  	if s.Type == objabi.STEXT {
   809  		fn := s.Func()
   810  		fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x funcid=%#x align=%#x", uint64(fn.Args), uint64(fn.Locals), uint64(fn.FuncID), uint64(fn.Align))
   811  		if s.Leaf() {
   812  			fmt.Fprintf(ctxt.Bso, " leaf")
   813  		}
   814  	}
   815  	fmt.Fprintf(ctxt.Bso, "\n")
   816  	if s.Type == objabi.STEXT {
   817  		for p := s.Func().Text; p != nil; p = p.Link {
   818  			fmt.Fprintf(ctxt.Bso, "\t%#04x ", uint(int(p.Pc)))
   819  			if ctxt.Debugasm > 1 {
   820  				io.WriteString(ctxt.Bso, p.String())
   821  			} else {
   822  				p.InnermostString(ctxt.Bso)
   823  			}
   824  			fmt.Fprintln(ctxt.Bso)
   825  		}
   826  	}
   827  	for i := 0; i < len(s.P); i += 16 {
   828  		fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i))
   829  		j := i
   830  		for ; j < i+16 && j < len(s.P); j++ {
   831  			fmt.Fprintf(ctxt.Bso, " %02x", s.P[j])
   832  		}
   833  		for ; j < i+16; j++ {
   834  			fmt.Fprintf(ctxt.Bso, "   ")
   835  		}
   836  		fmt.Fprintf(ctxt.Bso, "  ")
   837  		for j = i; j < i+16 && j < len(s.P); j++ {
   838  			c := int(s.P[j])
   839  			b := byte('.')
   840  			if ' ' <= c && c <= 0x7e {
   841  				b = byte(c)
   842  			}
   843  			ctxt.Bso.WriteByte(b)
   844  		}
   845  
   846  		fmt.Fprintf(ctxt.Bso, "\n")
   847  	}
   848  
   849  	sort.Sort(relocByOff(s.R)) // generate stable output
   850  	for _, r := range s.R {
   851  		name := ""
   852  		ver := ""
   853  		if r.Sym != nil {
   854  			name = r.Sym.Name
   855  			if ctxt.Debugasm > 1 {
   856  				ver = fmt.Sprintf("<%d>", r.Sym.ABI())
   857  			}
   858  		} else if r.Type == objabi.R_TLS_LE {
   859  			name = "TLS"
   860  		}
   861  		if ctxt.Arch.InFamily(sys.ARM, sys.PPC64) {
   862  			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))
   863  		} else {
   864  			fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s%s+%d\n", int(r.Off), r.Siz, r.Type, name, ver, r.Add)
   865  		}
   866  	}
   867  }
   868  
   869  // relocByOff sorts relocations by their offsets.
   870  type relocByOff []Reloc
   871  
   872  func (x relocByOff) Len() int           { return len(x) }
   873  func (x relocByOff) Less(i, j int) bool { return x[i].Off < x[j].Off }
   874  func (x relocByOff) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
   875  

View as plain text