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

View as plain text