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