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

View as plain text