...

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

View as plain text