github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/link/ld/lib.go (about)

     1  // Inferno utils/8l/asm.c
     2  // https://bitbucket.org/inferno-os/inferno-os/src/master/utils/8l/asm.c
     3  //
     4  //	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
     5  //	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
     6  //	Portions Copyright © 1997-1999 Vita Nuova Limited
     7  //	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
     8  //	Portions Copyright © 2004,2006 Bruce Ellis
     9  //	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
    10  //	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
    11  //	Portions Copyright © 2009 The Go Authors. All rights reserved.
    12  //
    13  // Permission is hereby granted, free of charge, to any person obtaining a copy
    14  // of this software and associated documentation files (the "Software"), to deal
    15  // in the Software without restriction, including without limitation the rights
    16  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    17  // copies of the Software, and to permit persons to whom the Software is
    18  // furnished to do so, subject to the following conditions:
    19  //
    20  // The above copyright notice and this permission notice shall be included in
    21  // all copies or substantial portions of the Software.
    22  //
    23  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    24  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    25  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    26  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    27  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    28  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    29  // THE SOFTWARE.
    30  
    31  package ld
    32  
    33  import (
    34  	"bytes"
    35  	"debug/elf"
    36  	"debug/macho"
    37  	"encoding/base64"
    38  	"encoding/binary"
    39  	"fmt"
    40  	"io"
    41  	"log"
    42  	"os"
    43  	"os/exec"
    44  	"path/filepath"
    45  	"runtime"
    46  	"sort"
    47  	"strings"
    48  	"sync"
    49  
    50  	"github.com/go-asm/go/buildcfg"
    51  
    52  	"github.com/go-asm/go/cmd/bio"
    53  	"github.com/go-asm/go/cmd/goobj"
    54  	"github.com/go-asm/go/cmd/link/loadelf"
    55  	"github.com/go-asm/go/cmd/link/loader"
    56  	"github.com/go-asm/go/cmd/link/loadmacho"
    57  	"github.com/go-asm/go/cmd/link/loadpe"
    58  	"github.com/go-asm/go/cmd/link/loadxcoff"
    59  	"github.com/go-asm/go/cmd/link/sym"
    60  	"github.com/go-asm/go/cmd/notsha256"
    61  	"github.com/go-asm/go/cmd/objabi"
    62  	"github.com/go-asm/go/cmd/sys"
    63  )
    64  
    65  // Data layout and relocation.
    66  
    67  // Derived from Inferno utils/6l/l.h
    68  // https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h
    69  //
    70  //	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
    71  //	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
    72  //	Portions Copyright © 1997-1999 Vita Nuova Limited
    73  //	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
    74  //	Portions Copyright © 2004,2006 Bruce Ellis
    75  //	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
    76  //	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
    77  //	Portions Copyright © 2009 The Go Authors. All rights reserved.
    78  //
    79  // Permission is hereby granted, free of charge, to any person obtaining a copy
    80  // of this software and associated documentation files (the "Software"), to deal
    81  // in the Software without restriction, including without limitation the rights
    82  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    83  // copies of the Software, and to permit persons to whom the Software is
    84  // furnished to do so, subject to the following conditions:
    85  //
    86  // The above copyright notice and this permission notice shall be included in
    87  // all copies or substantial portions of the Software.
    88  //
    89  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    90  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    91  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    92  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    93  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    94  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    95  // THE SOFTWARE.
    96  
    97  // ArchSyms holds a number of architecture specific symbols used during
    98  // relocation.  Rather than allowing them universal access to all symbols,
    99  // we keep a subset for relocation application.
   100  type ArchSyms struct {
   101  	Rel     loader.Sym
   102  	Rela    loader.Sym
   103  	RelPLT  loader.Sym
   104  	RelaPLT loader.Sym
   105  
   106  	LinkEditGOT loader.Sym
   107  	LinkEditPLT loader.Sym
   108  
   109  	TOC    loader.Sym
   110  	DotTOC []loader.Sym // for each version
   111  
   112  	GOT    loader.Sym
   113  	PLT    loader.Sym
   114  	GOTPLT loader.Sym
   115  
   116  	Tlsg      loader.Sym
   117  	Tlsoffset int
   118  
   119  	Dynamic loader.Sym
   120  	DynSym  loader.Sym
   121  	DynStr  loader.Sym
   122  
   123  	unreachableMethod loader.Sym
   124  
   125  	// Symbol containing a list of all the inittasks that need
   126  	// to be run at startup.
   127  	mainInittasks loader.Sym
   128  }
   129  
   130  // mkArchSym is a helper for setArchSyms, to set up a special symbol.
   131  func (ctxt *Link) mkArchSym(name string, ver int, ls *loader.Sym) {
   132  	*ls = ctxt.loader.LookupOrCreateSym(name, ver)
   133  	ctxt.loader.SetAttrReachable(*ls, true)
   134  }
   135  
   136  // mkArchSymVec is similar to  setArchSyms, but operates on elements within
   137  // a slice, where each element corresponds to some symbol version.
   138  func (ctxt *Link) mkArchSymVec(name string, ver int, ls []loader.Sym) {
   139  	ls[ver] = ctxt.loader.LookupOrCreateSym(name, ver)
   140  	ctxt.loader.SetAttrReachable(ls[ver], true)
   141  }
   142  
   143  // setArchSyms sets up the ArchSyms structure, and must be called before
   144  // relocations are applied.
   145  func (ctxt *Link) setArchSyms() {
   146  	ctxt.mkArchSym(".got", 0, &ctxt.GOT)
   147  	ctxt.mkArchSym(".plt", 0, &ctxt.PLT)
   148  	ctxt.mkArchSym(".got.plt", 0, &ctxt.GOTPLT)
   149  	ctxt.mkArchSym(".dynamic", 0, &ctxt.Dynamic)
   150  	ctxt.mkArchSym(".dynsym", 0, &ctxt.DynSym)
   151  	ctxt.mkArchSym(".dynstr", 0, &ctxt.DynStr)
   152  	ctxt.mkArchSym("runtime.unreachableMethod", abiInternalVer, &ctxt.unreachableMethod)
   153  
   154  	if ctxt.IsPPC64() {
   155  		ctxt.mkArchSym("TOC", 0, &ctxt.TOC)
   156  
   157  		ctxt.DotTOC = make([]loader.Sym, ctxt.MaxVersion()+1)
   158  		for i := 0; i <= ctxt.MaxVersion(); i++ {
   159  			if i >= sym.SymVerABICount && i < sym.SymVerStatic { // these versions are not used currently
   160  				continue
   161  			}
   162  			ctxt.mkArchSymVec(".TOC.", i, ctxt.DotTOC)
   163  		}
   164  	}
   165  	if ctxt.IsElf() {
   166  		ctxt.mkArchSym(".rel", 0, &ctxt.Rel)
   167  		ctxt.mkArchSym(".rela", 0, &ctxt.Rela)
   168  		ctxt.mkArchSym(".rel.plt", 0, &ctxt.RelPLT)
   169  		ctxt.mkArchSym(".rela.plt", 0, &ctxt.RelaPLT)
   170  	}
   171  	if ctxt.IsDarwin() {
   172  		ctxt.mkArchSym(".linkedit.got", 0, &ctxt.LinkEditGOT)
   173  		ctxt.mkArchSym(".linkedit.plt", 0, &ctxt.LinkEditPLT)
   174  	}
   175  }
   176  
   177  type Arch struct {
   178  	Funcalign  int
   179  	Maxalign   int
   180  	Minalign   int
   181  	Dwarfregsp int
   182  	Dwarfreglr int
   183  
   184  	// Threshold of total text size, used for trampoline insertion. If the total
   185  	// text size is smaller than TrampLimit, we won't need to insert trampolines.
   186  	// It is pretty close to the offset range of a direct CALL machine instruction.
   187  	// We leave some room for extra stuff like PLT stubs.
   188  	TrampLimit uint64
   189  
   190  	// Empty spaces between codeblocks will be padded with this value.
   191  	// For example an architecture might want to pad with a trap instruction to
   192  	// catch wayward programs. Architectures that do not define a padding value
   193  	// are padded with zeros.
   194  	CodePad []byte
   195  
   196  	// Plan 9 variables.
   197  	Plan9Magic  uint32
   198  	Plan9_64Bit bool
   199  
   200  	Adddynrel func(*Target, *loader.Loader, *ArchSyms, loader.Sym, loader.Reloc, int) bool
   201  	Archinit  func(*Link)
   202  	// Archreloc is an arch-specific hook that assists in relocation processing
   203  	// (invoked by 'relocsym'); it handles target-specific relocation tasks.
   204  	// Here "rel" is the current relocation being examined, "sym" is the symbol
   205  	// containing the chunk of data to which the relocation applies, and "off"
   206  	// is the contents of the to-be-relocated data item (from sym.P). Return
   207  	// value is the appropriately relocated value (to be written back to the
   208  	// same spot in sym.P), number of external _host_ relocations needed (i.e.
   209  	// ELF/Mach-O/etc. relocations, not Go relocations, this must match ELF.Reloc1,
   210  	// etc.), and a boolean indicating success/failure (a failing value indicates
   211  	// a fatal error).
   212  	Archreloc func(*Target, *loader.Loader, *ArchSyms, loader.Reloc, loader.Sym,
   213  		int64) (relocatedOffset int64, nExtReloc int, ok bool)
   214  	// Archrelocvariant is a second arch-specific hook used for
   215  	// relocation processing; it handles relocations where r.Type is
   216  	// insufficient to describe the relocation (r.Variant !=
   217  	// sym.RV_NONE). Here "rel" is the relocation being applied, "sym"
   218  	// is the symbol containing the chunk of data to which the
   219  	// relocation applies, and "off" is the contents of the
   220  	// to-be-relocated data item (from sym.P). Return is an updated
   221  	// offset value.
   222  	Archrelocvariant func(target *Target, ldr *loader.Loader, rel loader.Reloc,
   223  		rv sym.RelocVariant, sym loader.Sym, offset int64, data []byte) (relocatedOffset int64)
   224  
   225  	// Generate a trampoline for a call from s to rs if necessary. ri is
   226  	// index of the relocation.
   227  	Trampoline func(ctxt *Link, ldr *loader.Loader, ri int, rs, s loader.Sym)
   228  
   229  	// Assembling the binary breaks into two phases, writing the code/data/
   230  	// dwarf information (which is rather generic), and some more architecture
   231  	// specific work like setting up the elf headers/dynamic relocations, etc.
   232  	// The phases are called "Asmb" and "Asmb2". Asmb2 needs to be defined for
   233  	// every architecture, but only if architecture has an Asmb function will
   234  	// it be used for assembly.  Otherwise a generic assembly Asmb function is
   235  	// used.
   236  	Asmb  func(*Link, *loader.Loader)
   237  	Asmb2 func(*Link, *loader.Loader)
   238  
   239  	// Extreloc is an arch-specific hook that converts a Go relocation to an
   240  	// external relocation. Return the external relocation and whether it is
   241  	// needed.
   242  	Extreloc func(*Target, *loader.Loader, loader.Reloc, loader.Sym) (loader.ExtReloc, bool)
   243  
   244  	Gentext        func(*Link, *loader.Loader) // Generate text before addressing has been performed.
   245  	Machoreloc1    func(*sys.Arch, *OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool
   246  	MachorelocSize uint32 // size of an Mach-O relocation record, must match Machoreloc1.
   247  	PEreloc1       func(*sys.Arch, *OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool
   248  	Xcoffreloc1    func(*sys.Arch, *OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool
   249  
   250  	// Generate additional symbols for the native symbol table just prior to
   251  	// code generation.
   252  	GenSymsLate func(*Link, *loader.Loader)
   253  
   254  	// TLSIEtoLE converts a TLS Initial Executable relocation to
   255  	// a TLS Local Executable relocation.
   256  	//
   257  	// This is possible when a TLS IE relocation refers to a local
   258  	// symbol in an executable, which is typical when internally
   259  	// linking PIE binaries.
   260  	TLSIEtoLE func(P []byte, off, size int)
   261  
   262  	// optional override for assignAddress
   263  	AssignAddress func(ldr *loader.Loader, sect *sym.Section, n int, s loader.Sym, va uint64, isTramp bool) (*sym.Section, int, uint64)
   264  
   265  	// ELF specific information.
   266  	ELF ELFArch
   267  }
   268  
   269  var (
   270  	thearch Arch
   271  	lcSize  int32
   272  	rpath   Rpath
   273  	spSize  int32
   274  	symSize int32
   275  )
   276  
   277  const (
   278  	MINFUNC = 16 // minimum size for a function
   279  )
   280  
   281  // Symbol version of ABIInternal symbols. It is sym.SymVerABIInternal if ABI wrappers
   282  // are used, 0 otherwise.
   283  var abiInternalVer = sym.SymVerABIInternal
   284  
   285  // DynlinkingGo reports whether we are producing Go code that can live
   286  // in separate shared libraries linked together at runtime.
   287  func (ctxt *Link) DynlinkingGo() bool {
   288  	if !ctxt.Loaded {
   289  		panic("DynlinkingGo called before all symbols loaded")
   290  	}
   291  	return ctxt.BuildMode == BuildModeShared || ctxt.linkShared || ctxt.BuildMode == BuildModePlugin || ctxt.canUsePlugins
   292  }
   293  
   294  // CanUsePlugins reports whether a plugins can be used
   295  func (ctxt *Link) CanUsePlugins() bool {
   296  	if !ctxt.Loaded {
   297  		panic("CanUsePlugins called before all symbols loaded")
   298  	}
   299  	return ctxt.canUsePlugins
   300  }
   301  
   302  // NeedCodeSign reports whether we need to code-sign the output binary.
   303  func (ctxt *Link) NeedCodeSign() bool {
   304  	return ctxt.IsDarwin() && ctxt.IsARM64()
   305  }
   306  
   307  var (
   308  	dynlib          []string
   309  	ldflag          []string
   310  	havedynamic     int
   311  	Funcalign       int
   312  	iscgo           bool
   313  	elfglobalsymndx int
   314  	interpreter     string
   315  
   316  	debug_s bool // backup old value of debug['s']
   317  	HEADR   int32
   318  
   319  	nerrors  int
   320  	liveness int64 // size of liveness data (funcdata), printed if -v
   321  
   322  	// See -strictdups command line flag.
   323  	checkStrictDups   int // 0=off 1=warning 2=error
   324  	strictDupMsgCount int
   325  )
   326  
   327  var (
   328  	Segtext      sym.Segment
   329  	Segrodata    sym.Segment
   330  	Segrelrodata sym.Segment
   331  	Segdata      sym.Segment
   332  	Segdwarf     sym.Segment
   333  	Segpdata     sym.Segment // windows-only
   334  	Segxdata     sym.Segment // windows-only
   335  
   336  	Segments = []*sym.Segment{&Segtext, &Segrodata, &Segrelrodata, &Segdata, &Segdwarf, &Segpdata, &Segxdata}
   337  )
   338  
   339  const pkgdef = "__.PKGDEF"
   340  
   341  var (
   342  	// externalobj is set to true if we see an object compiled by
   343  	// the host compiler that is not from a package that is known
   344  	// to support internal linking mode.
   345  	externalobj = false
   346  
   347  	// dynimportfail is a list of packages for which generating
   348  	// the dynimport file, _cgo_import.go, failed. If there are
   349  	// any of these objects, we must link externally. Issue 52863.
   350  	dynimportfail []string
   351  
   352  	// preferlinkext is a list of packages for which the Go command
   353  	// noticed use of peculiar C flags. If we see any of these,
   354  	// default to linking externally unless overridden by the
   355  	// user. See issues #58619, #58620, and #58848.
   356  	preferlinkext []string
   357  
   358  	// unknownObjFormat is set to true if we see an object whose
   359  	// format we don't recognize.
   360  	unknownObjFormat = false
   361  
   362  	theline string
   363  )
   364  
   365  func Lflag(ctxt *Link, arg string) {
   366  	ctxt.Libdir = append(ctxt.Libdir, arg)
   367  }
   368  
   369  /*
   370   * Unix doesn't like it when we write to a running (or, sometimes,
   371   * recently run) binary, so remove the output file before writing it.
   372   * On Windows 7, remove() can force a subsequent create() to fail.
   373   * S_ISREG() does not exist on Plan 9.
   374   */
   375  func mayberemoveoutfile() {
   376  	if fi, err := os.Lstat(*flagOutfile); err == nil && !fi.Mode().IsRegular() {
   377  		return
   378  	}
   379  	os.Remove(*flagOutfile)
   380  }
   381  
   382  func libinit(ctxt *Link) {
   383  	Funcalign = thearch.Funcalign
   384  
   385  	// add goroot to the end of the libdir list.
   386  	suffix := ""
   387  
   388  	suffixsep := ""
   389  	if *flagInstallSuffix != "" {
   390  		suffixsep = "_"
   391  		suffix = *flagInstallSuffix
   392  	} else if *flagRace {
   393  		suffixsep = "_"
   394  		suffix = "race"
   395  	} else if *flagMsan {
   396  		suffixsep = "_"
   397  		suffix = "msan"
   398  	} else if *flagAsan {
   399  		suffixsep = "_"
   400  		suffix = "asan"
   401  	}
   402  
   403  	if buildcfg.GOROOT != "" {
   404  		Lflag(ctxt, filepath.Join(buildcfg.GOROOT, "pkg", fmt.Sprintf("%s_%s%s%s", buildcfg.GOOS, buildcfg.GOARCH, suffixsep, suffix)))
   405  	}
   406  
   407  	mayberemoveoutfile()
   408  
   409  	if err := ctxt.Out.Open(*flagOutfile); err != nil {
   410  		Exitf("cannot create %s: %v", *flagOutfile, err)
   411  	}
   412  
   413  	if *flagEntrySymbol == "" {
   414  		switch ctxt.BuildMode {
   415  		case BuildModeCShared, BuildModeCArchive:
   416  			*flagEntrySymbol = fmt.Sprintf("_rt0_%s_%s_lib", buildcfg.GOARCH, buildcfg.GOOS)
   417  		case BuildModeExe, BuildModePIE:
   418  			*flagEntrySymbol = fmt.Sprintf("_rt0_%s_%s", buildcfg.GOARCH, buildcfg.GOOS)
   419  		case BuildModeShared, BuildModePlugin:
   420  			// No *flagEntrySymbol for -buildmode=shared and plugin
   421  		default:
   422  			Errorf(nil, "unknown *flagEntrySymbol for buildmode %v", ctxt.BuildMode)
   423  		}
   424  	}
   425  }
   426  
   427  func exitIfErrors() {
   428  	if nerrors != 0 || checkStrictDups > 1 && strictDupMsgCount > 0 {
   429  		mayberemoveoutfile()
   430  		Exit(2)
   431  	}
   432  
   433  }
   434  
   435  func errorexit() {
   436  	exitIfErrors()
   437  	Exit(0)
   438  }
   439  
   440  func loadinternal(ctxt *Link, name string) *sym.Library {
   441  	zerofp := goobj.FingerprintType{}
   442  	if ctxt.linkShared && ctxt.PackageShlib != nil {
   443  		if shlib := ctxt.PackageShlib[name]; shlib != "" {
   444  			return addlibpath(ctxt, "internal", "internal", "", name, shlib, zerofp)
   445  		}
   446  	}
   447  	if ctxt.PackageFile != nil {
   448  		if pname := ctxt.PackageFile[name]; pname != "" {
   449  			return addlibpath(ctxt, "internal", "internal", pname, name, "", zerofp)
   450  		}
   451  		ctxt.Logf("loadinternal: cannot find %s\n", name)
   452  		return nil
   453  	}
   454  
   455  	for _, libdir := range ctxt.Libdir {
   456  		if ctxt.linkShared {
   457  			shlibname := filepath.Join(libdir, name+".shlibname")
   458  			if ctxt.Debugvlog != 0 {
   459  				ctxt.Logf("searching for %s.a in %s\n", name, shlibname)
   460  			}
   461  			if _, err := os.Stat(shlibname); err == nil {
   462  				return addlibpath(ctxt, "internal", "internal", "", name, shlibname, zerofp)
   463  			}
   464  		}
   465  		pname := filepath.Join(libdir, name+".a")
   466  		if ctxt.Debugvlog != 0 {
   467  			ctxt.Logf("searching for %s.a in %s\n", name, pname)
   468  		}
   469  		if _, err := os.Stat(pname); err == nil {
   470  			return addlibpath(ctxt, "internal", "internal", pname, name, "", zerofp)
   471  		}
   472  	}
   473  
   474  	if name == "runtime" {
   475  		Exitf("error: unable to find runtime.a")
   476  	}
   477  	ctxt.Logf("warning: unable to find %s.a\n", name)
   478  	return nil
   479  }
   480  
   481  // extld returns the current external linker.
   482  func (ctxt *Link) extld() []string {
   483  	if len(flagExtld) == 0 {
   484  		// Return the default external linker for the platform.
   485  		// This only matters when link tool is called directly without explicit -extld,
   486  		// go tool already passes the correct linker in other cases.
   487  		switch buildcfg.GOOS {
   488  		case "darwin", "freebsd", "openbsd":
   489  			flagExtld = []string{"clang"}
   490  		default:
   491  			flagExtld = []string{"gcc"}
   492  		}
   493  	}
   494  	return flagExtld
   495  }
   496  
   497  // findLibPathCmd uses cmd command to find gcc library libname.
   498  // It returns library full path if found, or "none" if not found.
   499  func (ctxt *Link) findLibPathCmd(cmd, libname string) string {
   500  	extld := ctxt.extld()
   501  	name, args := extld[0], extld[1:]
   502  	args = append(args, hostlinkArchArgs(ctxt.Arch)...)
   503  	args = append(args, cmd)
   504  	if ctxt.Debugvlog != 0 {
   505  		ctxt.Logf("%s %v\n", extld, args)
   506  	}
   507  	out, err := exec.Command(name, args...).Output()
   508  	if err != nil {
   509  		if ctxt.Debugvlog != 0 {
   510  			ctxt.Logf("not using a %s file because compiler failed\n%v\n%s\n", libname, err, out)
   511  		}
   512  		return "none"
   513  	}
   514  	return strings.TrimSpace(string(out))
   515  }
   516  
   517  // findLibPath searches for library libname.
   518  // It returns library full path if found, or "none" if not found.
   519  func (ctxt *Link) findLibPath(libname string) string {
   520  	return ctxt.findLibPathCmd("--print-file-name="+libname, libname)
   521  }
   522  
   523  func (ctxt *Link) loadlib() {
   524  	var flags uint32
   525  	switch *FlagStrictDups {
   526  	case 0:
   527  		// nothing to do
   528  	case 1, 2:
   529  		flags |= loader.FlagStrictDups
   530  	default:
   531  		log.Fatalf("invalid -strictdups flag value %d", *FlagStrictDups)
   532  	}
   533  	ctxt.loader = loader.NewLoader(flags, &ctxt.ErrorReporter.ErrorReporter)
   534  	ctxt.ErrorReporter.SymName = func(s loader.Sym) string {
   535  		return ctxt.loader.SymName(s)
   536  	}
   537  
   538  	// ctxt.Library grows during the loop, so not a range loop.
   539  	i := 0
   540  	for ; i < len(ctxt.Library); i++ {
   541  		lib := ctxt.Library[i]
   542  		if lib.Shlib == "" {
   543  			if ctxt.Debugvlog > 1 {
   544  				ctxt.Logf("autolib: %s (from %s)\n", lib.File, lib.Objref)
   545  			}
   546  			loadobjfile(ctxt, lib)
   547  		}
   548  	}
   549  
   550  	// load internal packages, if not already
   551  	if *flagRace {
   552  		loadinternal(ctxt, "runtime/race")
   553  	}
   554  	if *flagMsan {
   555  		loadinternal(ctxt, "runtime/msan")
   556  	}
   557  	if *flagAsan {
   558  		loadinternal(ctxt, "runtime/asan")
   559  	}
   560  	loadinternal(ctxt, "runtime")
   561  	for ; i < len(ctxt.Library); i++ {
   562  		lib := ctxt.Library[i]
   563  		if lib.Shlib == "" {
   564  			loadobjfile(ctxt, lib)
   565  		}
   566  	}
   567  	// At this point, the Go objects are "preloaded". Not all the symbols are
   568  	// added to the symbol table (only defined package symbols are). Looking
   569  	// up symbol by name may not get expected result.
   570  
   571  	iscgo = ctxt.LibraryByPkg["runtime/cgo"] != nil
   572  
   573  	// Plugins a require cgo support to function. Similarly, plugins may require additional
   574  	// internal linker support on some platforms which may not be implemented.
   575  	ctxt.canUsePlugins = ctxt.LibraryByPkg["plugin"] != nil && iscgo
   576  
   577  	// We now have enough information to determine the link mode.
   578  	determineLinkMode(ctxt)
   579  
   580  	if ctxt.LinkMode == LinkExternal && !iscgo && !(buildcfg.GOOS == "darwin" && ctxt.BuildMode != BuildModePlugin && ctxt.Arch.Family == sys.AMD64) {
   581  		// This indicates a user requested -linkmode=external.
   582  		// The startup code uses an import of runtime/cgo to decide
   583  		// whether to initialize the TLS.  So give it one. This could
   584  		// be handled differently but it's an unusual case.
   585  		if lib := loadinternal(ctxt, "runtime/cgo"); lib != nil && lib.Shlib == "" {
   586  			if ctxt.BuildMode == BuildModeShared || ctxt.linkShared {
   587  				Exitf("cannot implicitly include runtime/cgo in a shared library")
   588  			}
   589  			for ; i < len(ctxt.Library); i++ {
   590  				lib := ctxt.Library[i]
   591  				if lib.Shlib == "" {
   592  					loadobjfile(ctxt, lib)
   593  				}
   594  			}
   595  		}
   596  	}
   597  
   598  	// Add non-package symbols and references of externally defined symbols.
   599  	ctxt.loader.LoadSyms(ctxt.Arch)
   600  
   601  	// Load symbols from shared libraries, after all Go object symbols are loaded.
   602  	for _, lib := range ctxt.Library {
   603  		if lib.Shlib != "" {
   604  			if ctxt.Debugvlog > 1 {
   605  				ctxt.Logf("autolib: %s (from %s)\n", lib.Shlib, lib.Objref)
   606  			}
   607  			ldshlibsyms(ctxt, lib.Shlib)
   608  		}
   609  	}
   610  
   611  	// Process cgo directives (has to be done before host object loading).
   612  	ctxt.loadcgodirectives()
   613  
   614  	// Conditionally load host objects, or setup for external linking.
   615  	hostobjs(ctxt)
   616  	hostlinksetup(ctxt)
   617  
   618  	if ctxt.LinkMode == LinkInternal && len(hostobj) != 0 {
   619  		// If we have any undefined symbols in external
   620  		// objects, try to read them from the libgcc file.
   621  		any := false
   622  		undefs, froms := ctxt.loader.UndefinedRelocTargets(1)
   623  		if len(undefs) > 0 {
   624  			any = true
   625  			if ctxt.Debugvlog > 1 {
   626  				ctxt.Logf("loadlib: first unresolved is %s [%d] from %s [%d]\n",
   627  					ctxt.loader.SymName(undefs[0]), undefs[0],
   628  					ctxt.loader.SymName(froms[0]), froms[0])
   629  			}
   630  		}
   631  		if any {
   632  			if *flagLibGCC == "" {
   633  				*flagLibGCC = ctxt.findLibPathCmd("--print-libgcc-file-name", "libgcc")
   634  			}
   635  			if runtime.GOOS == "openbsd" && *flagLibGCC == "libgcc.a" {
   636  				// On OpenBSD `clang --print-libgcc-file-name` returns "libgcc.a".
   637  				// In this case we fail to load libgcc.a and can encounter link
   638  				// errors - see if we can find libcompiler_rt.a instead.
   639  				*flagLibGCC = ctxt.findLibPathCmd("--print-file-name=libcompiler_rt.a", "libcompiler_rt")
   640  			}
   641  			if ctxt.HeadType == objabi.Hwindows {
   642  				loadWindowsHostArchives(ctxt)
   643  			}
   644  			if *flagLibGCC != "none" {
   645  				hostArchive(ctxt, *flagLibGCC)
   646  			}
   647  			// For glibc systems, the linker setup used by GCC
   648  			// looks like
   649  			//
   650  			//  GROUP ( /lib/x86_64-linux-gnu/libc.so.6
   651  			//      /usr/lib/x86_64-linux-gnu/libc_nonshared.a
   652  			//      AS_NEEDED ( /lib64/ld-linux-x86-64.so.2 ) )
   653  			//
   654  			// where libc_nonshared.a contains a small set of
   655  			// symbols including "__stack_chk_fail_local" and a
   656  			// few others. Thus if we are doing internal linking
   657  			// and "__stack_chk_fail_local" is unresolved (most
   658  			// likely due to the use of -fstack-protector), try
   659  			// loading libc_nonshared.a to resolve it.
   660  			//
   661  			// On Alpine Linux (musl-based), the library providing
   662  			// this symbol is called libssp_nonshared.a.
   663  			isunresolved := symbolsAreUnresolved(ctxt, []string{"__stack_chk_fail_local"})
   664  			if isunresolved[0] {
   665  				if p := ctxt.findLibPath("libc_nonshared.a"); p != "none" {
   666  					hostArchive(ctxt, p)
   667  				}
   668  				if p := ctxt.findLibPath("libssp_nonshared.a"); p != "none" {
   669  					hostArchive(ctxt, p)
   670  				}
   671  			}
   672  		}
   673  	}
   674  
   675  	// We've loaded all the code now.
   676  	ctxt.Loaded = true
   677  
   678  	strictDupMsgCount = ctxt.loader.NStrictDupMsgs()
   679  }
   680  
   681  // loadWindowsHostArchives loads in host archives and objects when
   682  // doing internal linking on windows. Older toolchains seem to require
   683  // just a single pass through the various archives, but some modern
   684  // toolchains when linking a C program with mingw pass library paths
   685  // multiple times to the linker, e.g. "... -lmingwex -lmingw32 ...
   686  // -lmingwex -lmingw32 ...". To accommodate this behavior, we make two
   687  // passes over the host archives below.
   688  func loadWindowsHostArchives(ctxt *Link) {
   689  	any := true
   690  	for i := 0; any && i < 2; i++ {
   691  		// Link crt2.o (if present) to resolve "atexit" when
   692  		// using LLVM-based compilers.
   693  		isunresolved := symbolsAreUnresolved(ctxt, []string{"atexit"})
   694  		if isunresolved[0] {
   695  			if p := ctxt.findLibPath("crt2.o"); p != "none" {
   696  				hostObject(ctxt, "crt2", p)
   697  			}
   698  		}
   699  		if *flagRace {
   700  			if p := ctxt.findLibPath("libsynchronization.a"); p != "none" {
   701  				hostArchive(ctxt, p)
   702  			}
   703  		}
   704  		if p := ctxt.findLibPath("libmingwex.a"); p != "none" {
   705  			hostArchive(ctxt, p)
   706  		}
   707  		if p := ctxt.findLibPath("libmingw32.a"); p != "none" {
   708  			hostArchive(ctxt, p)
   709  		}
   710  		// Link libmsvcrt.a to resolve '__acrt_iob_func' symbol
   711  		// (see https://golang.org/issue/23649 for details).
   712  		if p := ctxt.findLibPath("libmsvcrt.a"); p != "none" {
   713  			hostArchive(ctxt, p)
   714  		}
   715  		any = false
   716  		undefs, froms := ctxt.loader.UndefinedRelocTargets(1)
   717  		if len(undefs) > 0 {
   718  			any = true
   719  			if ctxt.Debugvlog > 1 {
   720  				ctxt.Logf("loadWindowsHostArchives: remaining unresolved is %s [%d] from %s [%d]\n",
   721  					ctxt.loader.SymName(undefs[0]), undefs[0],
   722  					ctxt.loader.SymName(froms[0]), froms[0])
   723  			}
   724  		}
   725  	}
   726  	// If needed, create the __CTOR_LIST__ and __DTOR_LIST__
   727  	// symbols (referenced by some of the mingw support library
   728  	// routines). Creation of these symbols is normally done by the
   729  	// linker if not already present.
   730  	want := []string{"__CTOR_LIST__", "__DTOR_LIST__"}
   731  	isunresolved := symbolsAreUnresolved(ctxt, want)
   732  	for k, w := range want {
   733  		if isunresolved[k] {
   734  			sb := ctxt.loader.CreateSymForUpdate(w, 0)
   735  			sb.SetType(sym.SDATA)
   736  			sb.AddUint64(ctxt.Arch, 0)
   737  			sb.SetReachable(true)
   738  			ctxt.loader.SetAttrSpecial(sb.Sym(), true)
   739  		}
   740  	}
   741  
   742  	// Fix up references to DLL import symbols now that we're done
   743  	// pulling in new objects.
   744  	if err := loadpe.PostProcessImports(); err != nil {
   745  		Errorf(nil, "%v", err)
   746  	}
   747  
   748  	// TODO: maybe do something similar to peimporteddlls to collect
   749  	// all lib names and try link them all to final exe just like
   750  	// libmingwex.a and libmingw32.a:
   751  	/*
   752  		for:
   753  		#cgo windows LDFLAGS: -lmsvcrt -lm
   754  		import:
   755  		libmsvcrt.a libm.a
   756  	*/
   757  }
   758  
   759  // loadcgodirectives reads the previously discovered cgo directives, creating
   760  // symbols in preparation for host object loading or use later in the link.
   761  func (ctxt *Link) loadcgodirectives() {
   762  	l := ctxt.loader
   763  	hostObjSyms := make(map[loader.Sym]struct{})
   764  	for _, d := range ctxt.cgodata {
   765  		setCgoAttr(ctxt, d.file, d.pkg, d.directives, hostObjSyms)
   766  	}
   767  	ctxt.cgodata = nil
   768  
   769  	if ctxt.LinkMode == LinkInternal {
   770  		// Drop all the cgo_import_static declarations.
   771  		// Turns out we won't be needing them.
   772  		for symIdx := range hostObjSyms {
   773  			if l.SymType(symIdx) == sym.SHOSTOBJ {
   774  				// If a symbol was marked both
   775  				// cgo_import_static and cgo_import_dynamic,
   776  				// then we want to make it cgo_import_dynamic
   777  				// now.
   778  				su := l.MakeSymbolUpdater(symIdx)
   779  				if l.SymExtname(symIdx) != "" && l.SymDynimplib(symIdx) != "" && !(l.AttrCgoExportStatic(symIdx) || l.AttrCgoExportDynamic(symIdx)) {
   780  					su.SetType(sym.SDYNIMPORT)
   781  				} else {
   782  					su.SetType(0)
   783  				}
   784  			}
   785  		}
   786  	}
   787  }
   788  
   789  // Set up flags and special symbols depending on the platform build mode.
   790  // This version works with loader.Loader.
   791  func (ctxt *Link) linksetup() {
   792  	switch ctxt.BuildMode {
   793  	case BuildModeCShared, BuildModePlugin:
   794  		symIdx := ctxt.loader.LookupOrCreateSym("runtime.islibrary", 0)
   795  		sb := ctxt.loader.MakeSymbolUpdater(symIdx)
   796  		sb.SetType(sym.SNOPTRDATA)
   797  		sb.AddUint8(1)
   798  	case BuildModeCArchive:
   799  		symIdx := ctxt.loader.LookupOrCreateSym("runtime.isarchive", 0)
   800  		sb := ctxt.loader.MakeSymbolUpdater(symIdx)
   801  		sb.SetType(sym.SNOPTRDATA)
   802  		sb.AddUint8(1)
   803  	}
   804  
   805  	// Recalculate pe parameters now that we have ctxt.LinkMode set.
   806  	if ctxt.HeadType == objabi.Hwindows {
   807  		Peinit(ctxt)
   808  	}
   809  
   810  	if ctxt.LinkMode == LinkExternal {
   811  		// When external linking, we are creating an object file. The
   812  		// absolute address is irrelevant.
   813  		*FlagTextAddr = 0
   814  	}
   815  
   816  	// If there are no dynamic libraries needed, gcc disables dynamic linking.
   817  	// Because of this, glibc's dynamic ELF loader occasionally (like in version 2.13)
   818  	// assumes that a dynamic binary always refers to at least one dynamic library.
   819  	// Rather than be a source of test cases for glibc, disable dynamic linking
   820  	// the same way that gcc would.
   821  	//
   822  	// Exception: on OS X, programs such as Shark only work with dynamic
   823  	// binaries, so leave it enabled on OS X (Mach-O) binaries.
   824  	// Also leave it enabled on Solaris which doesn't support
   825  	// statically linked binaries.
   826  	if ctxt.BuildMode == BuildModeExe {
   827  		if havedynamic == 0 && ctxt.HeadType != objabi.Hdarwin && ctxt.HeadType != objabi.Hsolaris {
   828  			*FlagD = true
   829  		}
   830  	}
   831  
   832  	if ctxt.LinkMode == LinkExternal && ctxt.Arch.Family == sys.PPC64 && buildcfg.GOOS != "aix" {
   833  		toc := ctxt.loader.LookupOrCreateSym(".TOC.", 0)
   834  		sb := ctxt.loader.MakeSymbolUpdater(toc)
   835  		sb.SetType(sym.SDYNIMPORT)
   836  	}
   837  
   838  	// The Android Q linker started to complain about underalignment of the our TLS
   839  	// section. We don't actually use the section on android, so don't
   840  	// generate it.
   841  	if buildcfg.GOOS != "android" {
   842  		tlsg := ctxt.loader.LookupOrCreateSym("runtime.tlsg", 0)
   843  		sb := ctxt.loader.MakeSymbolUpdater(tlsg)
   844  
   845  		// runtime.tlsg is used for external linking on platforms that do not define
   846  		// a variable to hold g in assembly (currently only intel).
   847  		if sb.Type() == 0 {
   848  			sb.SetType(sym.STLSBSS)
   849  			sb.SetSize(int64(ctxt.Arch.PtrSize))
   850  		} else if sb.Type() != sym.SDYNIMPORT {
   851  			Errorf(nil, "runtime declared tlsg variable %v", sb.Type())
   852  		}
   853  		ctxt.loader.SetAttrReachable(tlsg, true)
   854  		ctxt.Tlsg = tlsg
   855  	}
   856  
   857  	var moduledata loader.Sym
   858  	var mdsb *loader.SymbolBuilder
   859  	if ctxt.BuildMode == BuildModePlugin {
   860  		moduledata = ctxt.loader.LookupOrCreateSym("local.pluginmoduledata", 0)
   861  		mdsb = ctxt.loader.MakeSymbolUpdater(moduledata)
   862  		ctxt.loader.SetAttrLocal(moduledata, true)
   863  	} else {
   864  		moduledata = ctxt.loader.LookupOrCreateSym("runtime.firstmoduledata", 0)
   865  		mdsb = ctxt.loader.MakeSymbolUpdater(moduledata)
   866  	}
   867  	if mdsb.Type() != 0 && mdsb.Type() != sym.SDYNIMPORT {
   868  		// If the module (toolchain-speak for "executable or shared
   869  		// library") we are linking contains the runtime package, it
   870  		// will define the runtime.firstmoduledata symbol and we
   871  		// truncate it back to 0 bytes so we can define its entire
   872  		// contents in symtab.go:symtab().
   873  		mdsb.SetSize(0)
   874  
   875  		// In addition, on ARM, the runtime depends on the linker
   876  		// recording the value of GOARM.
   877  		if ctxt.Arch.Family == sys.ARM {
   878  			goarm := ctxt.loader.LookupOrCreateSym("runtime.goarm", 0)
   879  			sb := ctxt.loader.MakeSymbolUpdater(goarm)
   880  			sb.SetType(sym.SDATA)
   881  			sb.SetSize(0)
   882  			sb.AddUint8(uint8(buildcfg.GOARM.Version))
   883  
   884  			goarmsoftfp := ctxt.loader.LookupOrCreateSym("runtime.goarmsoftfp", 0)
   885  			sb2 := ctxt.loader.MakeSymbolUpdater(goarmsoftfp)
   886  			sb2.SetType(sym.SDATA)
   887  			sb2.SetSize(0)
   888  			if buildcfg.GOARM.SoftFloat {
   889  				sb2.AddUint8(1)
   890  			} else {
   891  				sb2.AddUint8(0)
   892  			}
   893  		}
   894  
   895  		// Set runtime.disableMemoryProfiling bool if
   896  		// runtime.MemProfile is not retained in the binary after
   897  		// deadcode (and we're not dynamically linking).
   898  		memProfile := ctxt.loader.Lookup("runtime.MemProfile", abiInternalVer)
   899  		if memProfile != 0 && !ctxt.loader.AttrReachable(memProfile) && !ctxt.DynlinkingGo() {
   900  			memProfSym := ctxt.loader.LookupOrCreateSym("runtime.disableMemoryProfiling", 0)
   901  			sb := ctxt.loader.MakeSymbolUpdater(memProfSym)
   902  			sb.SetType(sym.SDATA)
   903  			sb.SetSize(0)
   904  			sb.AddUint8(1) // true bool
   905  		}
   906  	} else {
   907  		// If OTOH the module does not contain the runtime package,
   908  		// create a local symbol for the moduledata.
   909  		moduledata = ctxt.loader.LookupOrCreateSym("local.moduledata", 0)
   910  		mdsb = ctxt.loader.MakeSymbolUpdater(moduledata)
   911  		ctxt.loader.SetAttrLocal(moduledata, true)
   912  	}
   913  	// In all cases way we mark the moduledata as noptrdata to hide it from
   914  	// the GC.
   915  	mdsb.SetType(sym.SNOPTRDATA)
   916  	ctxt.loader.SetAttrReachable(moduledata, true)
   917  	ctxt.Moduledata = moduledata
   918  
   919  	if ctxt.Arch == sys.Arch386 && ctxt.HeadType != objabi.Hwindows {
   920  		if (ctxt.BuildMode == BuildModeCArchive && ctxt.IsELF) || ctxt.BuildMode == BuildModeCShared || ctxt.BuildMode == BuildModePIE || ctxt.DynlinkingGo() {
   921  			got := ctxt.loader.LookupOrCreateSym("_GLOBAL_OFFSET_TABLE_", 0)
   922  			sb := ctxt.loader.MakeSymbolUpdater(got)
   923  			sb.SetType(sym.SDYNIMPORT)
   924  			ctxt.loader.SetAttrReachable(got, true)
   925  		}
   926  	}
   927  
   928  	// DWARF-gen and other phases require that the unit Textp slices
   929  	// be populated, so that it can walk the functions in each unit.
   930  	// Call into the loader to do this (requires that we collect the
   931  	// set of internal libraries first). NB: might be simpler if we
   932  	// moved isRuntimeDepPkg to cmd/internal and then did the test in
   933  	// loader.AssignTextSymbolOrder.
   934  	ctxt.Library = postorder(ctxt.Library)
   935  	intlibs := []bool{}
   936  	for _, lib := range ctxt.Library {
   937  		intlibs = append(intlibs, isRuntimeDepPkg(lib.Pkg))
   938  	}
   939  	ctxt.Textp = ctxt.loader.AssignTextSymbolOrder(ctxt.Library, intlibs, ctxt.Textp)
   940  }
   941  
   942  // mangleTypeSym shortens the names of symbols that represent Go types
   943  // if they are visible in the symbol table.
   944  //
   945  // As the names of these symbols are derived from the string of
   946  // the type, they can run to many kilobytes long. So we shorten
   947  // them using a SHA-1 when the name appears in the final binary.
   948  // This also removes characters that upset external linkers.
   949  //
   950  // These are the symbols that begin with the prefix 'type.' and
   951  // contain run-time type information used by the runtime and reflect
   952  // packages. All Go binaries contain these symbols, but only
   953  // those programs loaded dynamically in multiple parts need these
   954  // symbols to have entries in the symbol table.
   955  func (ctxt *Link) mangleTypeSym() {
   956  	if ctxt.BuildMode != BuildModeShared && !ctxt.linkShared && ctxt.BuildMode != BuildModePlugin && !ctxt.CanUsePlugins() {
   957  		return
   958  	}
   959  
   960  	ldr := ctxt.loader
   961  	for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
   962  		if !ldr.AttrReachable(s) && !ctxt.linkShared {
   963  			// If -linkshared, the GCProg generation code may need to reach
   964  			// out to the shared library for the type descriptor's data, even
   965  			// the type descriptor itself is not actually needed at run time
   966  			// (therefore not reachable). We still need to mangle its name,
   967  			// so it is consistent with the one stored in the shared library.
   968  			continue
   969  		}
   970  		name := ldr.SymName(s)
   971  		newName := typeSymbolMangle(name)
   972  		if newName != name {
   973  			ldr.SetSymExtname(s, newName)
   974  
   975  			// When linking against a shared library, the Go object file may
   976  			// have reference to the original symbol name whereas the shared
   977  			// library provides a symbol with the mangled name. We need to
   978  			// copy the payload of mangled to original.
   979  			// XXX maybe there is a better way to do this.
   980  			dup := ldr.Lookup(newName, ldr.SymVersion(s))
   981  			if dup != 0 {
   982  				st := ldr.SymType(s)
   983  				dt := ldr.SymType(dup)
   984  				if st == sym.Sxxx && dt != sym.Sxxx {
   985  					ldr.CopySym(dup, s)
   986  				}
   987  			}
   988  		}
   989  	}
   990  }
   991  
   992  // typeSymbolMangle mangles the given symbol name into something shorter.
   993  //
   994  // Keep the type:. prefix, which parts of the linker (like the
   995  // DWARF generator) know means the symbol is not decodable.
   996  // Leave type:runtime. symbols alone, because other parts of
   997  // the linker manipulates them.
   998  func typeSymbolMangle(name string) string {
   999  	isType := strings.HasPrefix(name, "type:")
  1000  	if !isType && !strings.Contains(name, "@") {
  1001  		// Issue 58800: instantiated symbols may include a type name, which may contain "@"
  1002  		return name
  1003  	}
  1004  	if strings.HasPrefix(name, "type:runtime.") {
  1005  		return name
  1006  	}
  1007  	if strings.HasPrefix(name, "go:string.") {
  1008  		// String symbols will be grouped to a single go:string.* symbol.
  1009  		// No need to mangle individual symbol names.
  1010  		return name
  1011  	}
  1012  	if len(name) <= 14 && !strings.Contains(name, "@") { // Issue 19529
  1013  		return name
  1014  	}
  1015  	if isType {
  1016  		hash := notsha256.Sum256([]byte(name[5:]))
  1017  		prefix := "type:"
  1018  		if name[5] == '.' {
  1019  			prefix = "type:."
  1020  		}
  1021  		return prefix + base64.StdEncoding.EncodeToString(hash[:6])
  1022  	}
  1023  	// instantiated symbol, replace type name in []
  1024  	i := strings.IndexByte(name, '[')
  1025  	j := strings.LastIndexByte(name, ']')
  1026  	if j == -1 || j <= i {
  1027  		j = len(name)
  1028  	}
  1029  	hash := notsha256.Sum256([]byte(name[i+1 : j]))
  1030  	return name[:i+1] + base64.StdEncoding.EncodeToString(hash[:6]) + name[j:]
  1031  }
  1032  
  1033  /*
  1034   * look for the next file in an archive.
  1035   * adapted from libmach.
  1036   */
  1037  func nextar(bp *bio.Reader, off int64, a *ArHdr) int64 {
  1038  	if off&1 != 0 {
  1039  		off++
  1040  	}
  1041  	bp.MustSeek(off, 0)
  1042  	var buf [SAR_HDR]byte
  1043  	if n, err := io.ReadFull(bp, buf[:]); err != nil {
  1044  		if n == 0 && err != io.EOF {
  1045  			return -1
  1046  		}
  1047  		return 0
  1048  	}
  1049  
  1050  	a.name = artrim(buf[0:16])
  1051  	a.date = artrim(buf[16:28])
  1052  	a.uid = artrim(buf[28:34])
  1053  	a.gid = artrim(buf[34:40])
  1054  	a.mode = artrim(buf[40:48])
  1055  	a.size = artrim(buf[48:58])
  1056  	a.fmag = artrim(buf[58:60])
  1057  
  1058  	arsize := atolwhex(a.size)
  1059  	if arsize&1 != 0 {
  1060  		arsize++
  1061  	}
  1062  	return arsize + SAR_HDR
  1063  }
  1064  
  1065  func loadobjfile(ctxt *Link, lib *sym.Library) {
  1066  	pkg := objabi.PathToPrefix(lib.Pkg)
  1067  
  1068  	if ctxt.Debugvlog > 1 {
  1069  		ctxt.Logf("ldobj: %s (%s)\n", lib.File, pkg)
  1070  	}
  1071  	f, err := bio.Open(lib.File)
  1072  	if err != nil {
  1073  		Exitf("cannot open file %s: %v", lib.File, err)
  1074  	}
  1075  	defer f.Close()
  1076  	defer func() {
  1077  		if pkg == "main" && !lib.Main {
  1078  			Exitf("%s: not package main", lib.File)
  1079  		}
  1080  	}()
  1081  
  1082  	for i := 0; i < len(ARMAG); i++ {
  1083  		if c, err := f.ReadByte(); err == nil && c == ARMAG[i] {
  1084  			continue
  1085  		}
  1086  
  1087  		/* load it as a regular file */
  1088  		l := f.MustSeek(0, 2)
  1089  		f.MustSeek(0, 0)
  1090  		ldobj(ctxt, f, lib, l, lib.File, lib.File)
  1091  		return
  1092  	}
  1093  
  1094  	/*
  1095  	 * load all the object files from the archive now.
  1096  	 * this gives us sequential file access and keeps us
  1097  	 * from needing to come back later to pick up more
  1098  	 * objects.  it breaks the usual C archive model, but
  1099  	 * this is Go, not C.  the common case in Go is that
  1100  	 * we need to load all the objects, and then we throw away
  1101  	 * the individual symbols that are unused.
  1102  	 *
  1103  	 * loading every object will also make it possible to
  1104  	 * load foreign objects not referenced by __.PKGDEF.
  1105  	 */
  1106  	var arhdr ArHdr
  1107  	off := f.Offset()
  1108  	for {
  1109  		l := nextar(f, off, &arhdr)
  1110  		if l == 0 {
  1111  			break
  1112  		}
  1113  		if l < 0 {
  1114  			Exitf("%s: malformed archive", lib.File)
  1115  		}
  1116  		off += l
  1117  
  1118  		// __.PKGDEF isn't a real Go object file, and it's
  1119  		// absent in -linkobj builds anyway. Skipping it
  1120  		// ensures consistency between -linkobj and normal
  1121  		// build modes.
  1122  		if arhdr.name == pkgdef {
  1123  			continue
  1124  		}
  1125  
  1126  		if arhdr.name == "dynimportfail" {
  1127  			dynimportfail = append(dynimportfail, lib.Pkg)
  1128  		}
  1129  		if arhdr.name == "preferlinkext" {
  1130  			// Ignore this directive if -linkmode has been
  1131  			// set explicitly.
  1132  			if ctxt.LinkMode == LinkAuto {
  1133  				preferlinkext = append(preferlinkext, lib.Pkg)
  1134  			}
  1135  		}
  1136  
  1137  		// Skip other special (non-object-file) sections that
  1138  		// build tools may have added. Such sections must have
  1139  		// short names so that the suffix is not truncated.
  1140  		if len(arhdr.name) < 16 {
  1141  			if ext := filepath.Ext(arhdr.name); ext != ".o" && ext != ".syso" {
  1142  				continue
  1143  			}
  1144  		}
  1145  
  1146  		pname := fmt.Sprintf("%s(%s)", lib.File, arhdr.name)
  1147  		l = atolwhex(arhdr.size)
  1148  		ldobj(ctxt, f, lib, l, pname, lib.File)
  1149  	}
  1150  }
  1151  
  1152  type Hostobj struct {
  1153  	ld     func(*Link, *bio.Reader, string, int64, string)
  1154  	pkg    string
  1155  	pn     string
  1156  	file   string
  1157  	off    int64
  1158  	length int64
  1159  }
  1160  
  1161  var hostobj []Hostobj
  1162  
  1163  // These packages can use internal linking mode.
  1164  // Others trigger external mode.
  1165  var internalpkg = []string{
  1166  	"crypto/github.com/go-asm/go/boring",
  1167  	"crypto/github.com/go-asm/go/boring/syso",
  1168  	"crypto/x509",
  1169  	"net",
  1170  	"os/user",
  1171  	"runtime/cgo",
  1172  	"runtime/race",
  1173  	"runtime/race/github.com/go-asm/go/amd64v1",
  1174  	"runtime/race/github.com/go-asm/go/amd64v3",
  1175  	"runtime/msan",
  1176  	"runtime/asan",
  1177  }
  1178  
  1179  func ldhostobj(ld func(*Link, *bio.Reader, string, int64, string), headType objabi.HeadType, f *bio.Reader, pkg string, length int64, pn string, file string) *Hostobj {
  1180  	isinternal := false
  1181  	for _, intpkg := range internalpkg {
  1182  		if pkg == intpkg {
  1183  			isinternal = true
  1184  			break
  1185  		}
  1186  	}
  1187  
  1188  	// DragonFly declares errno with __thread, which results in a symbol
  1189  	// type of R_386_TLS_GD or R_X86_64_TLSGD. The Go linker does not
  1190  	// currently know how to handle TLS relocations, hence we have to
  1191  	// force external linking for any libraries that link in code that
  1192  	// uses errno. This can be removed if the Go linker ever supports
  1193  	// these relocation types.
  1194  	if headType == objabi.Hdragonfly {
  1195  		if pkg == "net" || pkg == "os/user" {
  1196  			isinternal = false
  1197  		}
  1198  	}
  1199  
  1200  	if !isinternal {
  1201  		externalobj = true
  1202  	}
  1203  
  1204  	hostobj = append(hostobj, Hostobj{})
  1205  	h := &hostobj[len(hostobj)-1]
  1206  	h.ld = ld
  1207  	h.pkg = pkg
  1208  	h.pn = pn
  1209  	h.file = file
  1210  	h.off = f.Offset()
  1211  	h.length = length
  1212  	return h
  1213  }
  1214  
  1215  func hostobjs(ctxt *Link) {
  1216  	if ctxt.LinkMode != LinkInternal {
  1217  		return
  1218  	}
  1219  	var h *Hostobj
  1220  
  1221  	for i := 0; i < len(hostobj); i++ {
  1222  		h = &hostobj[i]
  1223  		f, err := bio.Open(h.file)
  1224  		if err != nil {
  1225  			Exitf("cannot reopen %s: %v", h.pn, err)
  1226  		}
  1227  		f.MustSeek(h.off, 0)
  1228  		if h.ld == nil {
  1229  			Errorf(nil, "%s: unrecognized object file format", h.pn)
  1230  			continue
  1231  		}
  1232  		h.ld(ctxt, f, h.pkg, h.length, h.pn)
  1233  		if *flagCaptureHostObjs != "" {
  1234  			captureHostObj(h)
  1235  		}
  1236  		f.Close()
  1237  	}
  1238  }
  1239  
  1240  func hostlinksetup(ctxt *Link) {
  1241  	if ctxt.LinkMode != LinkExternal {
  1242  		return
  1243  	}
  1244  
  1245  	// For external link, record that we need to tell the external linker -s,
  1246  	// and turn off -s internally: the external linker needs the symbol
  1247  	// information for its final link.
  1248  	debug_s = *FlagS
  1249  	*FlagS = false
  1250  
  1251  	// create temporary directory and arrange cleanup
  1252  	if *flagTmpdir == "" {
  1253  		dir, err := os.MkdirTemp("", "go-link-")
  1254  		if err != nil {
  1255  			log.Fatal(err)
  1256  		}
  1257  		*flagTmpdir = dir
  1258  		ownTmpDir = true
  1259  		AtExit(func() {
  1260  			os.RemoveAll(*flagTmpdir)
  1261  		})
  1262  	}
  1263  
  1264  	// change our output to temporary object file
  1265  	if err := ctxt.Out.Close(); err != nil {
  1266  		Exitf("error closing output file")
  1267  	}
  1268  	mayberemoveoutfile()
  1269  
  1270  	p := filepath.Join(*flagTmpdir, "go.o")
  1271  	if err := ctxt.Out.Open(p); err != nil {
  1272  		Exitf("cannot create %s: %v", p, err)
  1273  	}
  1274  }
  1275  
  1276  // hostobjCopy creates a copy of the object files in hostobj in a
  1277  // temporary directory.
  1278  func (ctxt *Link) hostobjCopy() (paths []string) {
  1279  	var wg sync.WaitGroup
  1280  	sema := make(chan struct{}, runtime.NumCPU()) // limit open file descriptors
  1281  	for i, h := range hostobj {
  1282  		h := h
  1283  		dst := filepath.Join(*flagTmpdir, fmt.Sprintf("%06d.o", i))
  1284  		paths = append(paths, dst)
  1285  		if ctxt.Debugvlog != 0 {
  1286  			ctxt.Logf("host obj copy: %s from pkg %s -> %s\n", h.pn, h.pkg, dst)
  1287  		}
  1288  
  1289  		wg.Add(1)
  1290  		go func() {
  1291  			sema <- struct{}{}
  1292  			defer func() {
  1293  				<-sema
  1294  				wg.Done()
  1295  			}()
  1296  			f, err := os.Open(h.file)
  1297  			if err != nil {
  1298  				Exitf("cannot reopen %s: %v", h.pn, err)
  1299  			}
  1300  			defer f.Close()
  1301  			if _, err := f.Seek(h.off, 0); err != nil {
  1302  				Exitf("cannot seek %s: %v", h.pn, err)
  1303  			}
  1304  
  1305  			w, err := os.Create(dst)
  1306  			if err != nil {
  1307  				Exitf("cannot create %s: %v", dst, err)
  1308  			}
  1309  			if _, err := io.CopyN(w, f, h.length); err != nil {
  1310  				Exitf("cannot write %s: %v", dst, err)
  1311  			}
  1312  			if err := w.Close(); err != nil {
  1313  				Exitf("cannot close %s: %v", dst, err)
  1314  			}
  1315  		}()
  1316  	}
  1317  	wg.Wait()
  1318  	return paths
  1319  }
  1320  
  1321  // writeGDBLinkerScript creates gcc linker script file in temp
  1322  // directory. writeGDBLinkerScript returns created file path.
  1323  // The script is used to work around gcc bug
  1324  // (see https://golang.org/issue/20183 for details).
  1325  func writeGDBLinkerScript() string {
  1326  	name := "fix_debug_gdb_scripts.ld"
  1327  	path := filepath.Join(*flagTmpdir, name)
  1328  	src := `SECTIONS
  1329  {
  1330    .debug_gdb_scripts BLOCK(__section_alignment__) (NOLOAD) :
  1331    {
  1332      *(.debug_gdb_scripts)
  1333    }
  1334  }
  1335  INSERT AFTER .debug_types;
  1336  `
  1337  	err := os.WriteFile(path, []byte(src), 0666)
  1338  	if err != nil {
  1339  		Errorf(nil, "WriteFile %s failed: %v", name, err)
  1340  	}
  1341  	return path
  1342  }
  1343  
  1344  // archive builds a .a archive from the hostobj object files.
  1345  func (ctxt *Link) archive() {
  1346  	if ctxt.BuildMode != BuildModeCArchive {
  1347  		return
  1348  	}
  1349  
  1350  	exitIfErrors()
  1351  
  1352  	if *flagExtar == "" {
  1353  		*flagExtar = "ar"
  1354  	}
  1355  
  1356  	mayberemoveoutfile()
  1357  
  1358  	// Force the buffer to flush here so that external
  1359  	// tools will see a complete file.
  1360  	if err := ctxt.Out.Close(); err != nil {
  1361  		Exitf("error closing %v", *flagOutfile)
  1362  	}
  1363  
  1364  	argv := []string{*flagExtar, "-q", "-c", "-s"}
  1365  	if ctxt.HeadType == objabi.Haix {
  1366  		argv = append(argv, "-X64")
  1367  	}
  1368  	argv = append(argv, *flagOutfile)
  1369  	argv = append(argv, filepath.Join(*flagTmpdir, "go.o"))
  1370  	argv = append(argv, ctxt.hostobjCopy()...)
  1371  
  1372  	if ctxt.Debugvlog != 0 {
  1373  		ctxt.Logf("archive: %s\n", strings.Join(argv, " "))
  1374  	}
  1375  
  1376  	// If supported, use syscall.Exec() to invoke the archive command,
  1377  	// which should be the final remaining step needed for the link.
  1378  	// This will reduce peak RSS for the link (and speed up linking of
  1379  	// large applications), since when the archive command runs we
  1380  	// won't be holding onto all of the linker's live memory.
  1381  	if syscallExecSupported && !ownTmpDir {
  1382  		runAtExitFuncs()
  1383  		ctxt.execArchive(argv)
  1384  		panic("should not get here")
  1385  	}
  1386  
  1387  	// Otherwise invoke 'ar' in the usual way (fork + exec).
  1388  	if out, err := exec.Command(argv[0], argv[1:]...).CombinedOutput(); err != nil {
  1389  		Exitf("running %s failed: %v\n%s", argv[0], err, out)
  1390  	}
  1391  }
  1392  
  1393  func (ctxt *Link) hostlink() {
  1394  	if ctxt.LinkMode != LinkExternal || nerrors > 0 {
  1395  		return
  1396  	}
  1397  	if ctxt.BuildMode == BuildModeCArchive {
  1398  		return
  1399  	}
  1400  
  1401  	var argv []string
  1402  	argv = append(argv, ctxt.extld()...)
  1403  	argv = append(argv, hostlinkArchArgs(ctxt.Arch)...)
  1404  
  1405  	if *FlagS || debug_s {
  1406  		if ctxt.HeadType == objabi.Hdarwin {
  1407  			// Recent versions of macOS print
  1408  			//	ld: warning: option -s is obsolete and being ignored
  1409  			// so do not pass any arguments (but we strip symbols below).
  1410  		} else {
  1411  			argv = append(argv, "-s")
  1412  		}
  1413  	}
  1414  
  1415  	// On darwin, whether to combine DWARF into executable.
  1416  	// Only macOS supports unmapped segments such as our __DWARF segment.
  1417  	combineDwarf := ctxt.IsDarwin() && !*FlagW && machoPlatform == PLATFORM_MACOS
  1418  
  1419  	switch ctxt.HeadType {
  1420  	case objabi.Hdarwin:
  1421  		if combineDwarf {
  1422  			// Leave room for DWARF combining.
  1423  			// -headerpad is incompatible with -fembed-bitcode.
  1424  			argv = append(argv, "-Wl,-headerpad,1144")
  1425  		}
  1426  		if ctxt.DynlinkingGo() && buildcfg.GOOS != "ios" {
  1427  			// -flat_namespace is deprecated on iOS.
  1428  			// It is useful for supporting plugins. We don't support plugins on iOS.
  1429  			// -flat_namespace may cause the dynamic linker to hang at forkExec when
  1430  			// resolving a lazy binding. See issue 38824.
  1431  			// Force eager resolution to work around.
  1432  			argv = append(argv, "-Wl,-flat_namespace", "-Wl,-bind_at_load")
  1433  		}
  1434  		if !combineDwarf {
  1435  			argv = append(argv, "-Wl,-S") // suppress STAB (symbolic debugging) symbols
  1436  			if debug_s {
  1437  				// We are generating a binary with symbol table suppressed.
  1438  				// Suppress local symbols. We need to keep dynamically exported
  1439  				// and referenced symbols so the dynamic linker can resolve them.
  1440  				argv = append(argv, "-Wl,-x")
  1441  			}
  1442  		}
  1443  	case objabi.Hopenbsd:
  1444  		argv = append(argv, "-Wl,-nopie")
  1445  		argv = append(argv, "-pthread")
  1446  		if ctxt.Arch.InFamily(sys.ARM64) {
  1447  			// Disable execute-only on openbsd/arm64 - the Go arm64 assembler
  1448  			// currently stores constants in the text section rather than in rodata.
  1449  			// See issue #59615.
  1450  			argv = append(argv, "-Wl,--no-execute-only")
  1451  		}
  1452  	case objabi.Hwindows:
  1453  		if windowsgui {
  1454  			argv = append(argv, "-mwindows")
  1455  		} else {
  1456  			argv = append(argv, "-mconsole")
  1457  		}
  1458  		// Mark as having awareness of terminal services, to avoid
  1459  		// ancient compatibility hacks.
  1460  		argv = append(argv, "-Wl,--tsaware")
  1461  
  1462  		// Enable DEP
  1463  		argv = append(argv, "-Wl,--nxcompat")
  1464  
  1465  		argv = append(argv, fmt.Sprintf("-Wl,--major-os-version=%d", PeMinimumTargetMajorVersion))
  1466  		argv = append(argv, fmt.Sprintf("-Wl,--minor-os-version=%d", PeMinimumTargetMinorVersion))
  1467  		argv = append(argv, fmt.Sprintf("-Wl,--major-subsystem-version=%d", PeMinimumTargetMajorVersion))
  1468  		argv = append(argv, fmt.Sprintf("-Wl,--minor-subsystem-version=%d", PeMinimumTargetMinorVersion))
  1469  	case objabi.Haix:
  1470  		argv = append(argv, "-pthread")
  1471  		// prevent ld to reorder .text functions to keep the same
  1472  		// first/last functions for moduledata.
  1473  		argv = append(argv, "-Wl,-bnoobjreorder")
  1474  		// mcmodel=large is needed for every gcc generated files, but
  1475  		// ld still need -bbigtoc in order to allow larger TOC.
  1476  		argv = append(argv, "-mcmodel=large")
  1477  		argv = append(argv, "-Wl,-bbigtoc")
  1478  	}
  1479  
  1480  	// On PPC64, verify the external toolchain supports Power10. This is needed when
  1481  	// PC relative relocations might be generated by Go. Only targets compiling ELF
  1482  	// binaries might generate these relocations.
  1483  	if ctxt.IsPPC64() && ctxt.IsElf() && buildcfg.GOPPC64 >= 10 {
  1484  		if !linkerFlagSupported(ctxt.Arch, argv[0], "", "-mcpu=power10") {
  1485  			Exitf("The external toolchain does not support -mcpu=power10. " +
  1486  				" This is required to externally link GOPPC64 >= power10")
  1487  		}
  1488  	}
  1489  
  1490  	// Enable/disable ASLR on Windows.
  1491  	addASLRargs := func(argv []string, val bool) []string {
  1492  		// Old/ancient versions of GCC support "--dynamicbase" and
  1493  		// "--high-entropy-va" but don't enable it by default. In
  1494  		// addition, they don't accept "--disable-dynamicbase" or
  1495  		// "--no-dynamicbase", so the only way to disable ASLR is to
  1496  		// not pass any flags at all.
  1497  		//
  1498  		// More modern versions of GCC (and also clang) enable ASLR
  1499  		// by default. With these compilers, however you can turn it
  1500  		// off if you want using "--disable-dynamicbase" or
  1501  		// "--no-dynamicbase".
  1502  		//
  1503  		// The strategy below is to try using "--disable-dynamicbase";
  1504  		// if this succeeds, then assume we're working with more
  1505  		// modern compilers and act accordingly. If it fails, assume
  1506  		// an ancient compiler with ancient defaults.
  1507  		var dbopt string
  1508  		var heopt string
  1509  		dbon := "--dynamicbase"
  1510  		heon := "--high-entropy-va"
  1511  		dboff := "--disable-dynamicbase"
  1512  		heoff := "--disable-high-entropy-va"
  1513  		if val {
  1514  			dbopt = dbon
  1515  			heopt = heon
  1516  		} else {
  1517  			// Test to see whether "--disable-dynamicbase" works.
  1518  			newer := linkerFlagSupported(ctxt.Arch, argv[0], "", "-Wl,"+dboff)
  1519  			if newer {
  1520  				// Newer compiler, which supports both on/off options.
  1521  				dbopt = dboff
  1522  				heopt = heoff
  1523  			} else {
  1524  				// older toolchain: we have to say nothing in order to
  1525  				// get a no-ASLR binary.
  1526  				dbopt = ""
  1527  				heopt = ""
  1528  			}
  1529  		}
  1530  		if dbopt != "" {
  1531  			argv = append(argv, "-Wl,"+dbopt)
  1532  		}
  1533  		// enable high-entropy ASLR on 64-bit.
  1534  		if ctxt.Arch.PtrSize >= 8 && heopt != "" {
  1535  			argv = append(argv, "-Wl,"+heopt)
  1536  		}
  1537  		return argv
  1538  	}
  1539  
  1540  	switch ctxt.BuildMode {
  1541  	case BuildModeExe:
  1542  		if ctxt.HeadType == objabi.Hdarwin {
  1543  			if machoPlatform == PLATFORM_MACOS && ctxt.IsAMD64() {
  1544  				argv = append(argv, "-Wl,-no_pie")
  1545  			}
  1546  		}
  1547  		if *flagRace && ctxt.HeadType == objabi.Hwindows {
  1548  			// Current windows/amd64 race detector tsan support
  1549  			// library can't handle PIE mode (see #53539 for more details).
  1550  			// For now, explicitly disable PIE (since some compilers
  1551  			// default to it) if -race is in effect.
  1552  			argv = addASLRargs(argv, false)
  1553  		}
  1554  	case BuildModePIE:
  1555  		switch ctxt.HeadType {
  1556  		case objabi.Hdarwin, objabi.Haix:
  1557  		case objabi.Hwindows:
  1558  			if *flagAslr && *flagRace {
  1559  				// Current windows/amd64 race detector tsan support
  1560  				// library can't handle PIE mode (see #53539 for more details).
  1561  				// Disable alsr if -race in effect.
  1562  				*flagAslr = false
  1563  			}
  1564  			argv = addASLRargs(argv, *flagAslr)
  1565  		default:
  1566  			// ELF.
  1567  			if ctxt.UseRelro() {
  1568  				argv = append(argv, "-Wl,-z,relro")
  1569  			}
  1570  			argv = append(argv, "-pie")
  1571  		}
  1572  	case BuildModeCShared:
  1573  		if ctxt.HeadType == objabi.Hdarwin {
  1574  			argv = append(argv, "-dynamiclib")
  1575  		} else {
  1576  			if ctxt.UseRelro() {
  1577  				argv = append(argv, "-Wl,-z,relro")
  1578  			}
  1579  			argv = append(argv, "-shared")
  1580  			if ctxt.HeadType == objabi.Hwindows {
  1581  				argv = addASLRargs(argv, *flagAslr)
  1582  			} else {
  1583  				// Pass -z nodelete to mark the shared library as
  1584  				// non-closeable: a dlclose will do nothing.
  1585  				argv = append(argv, "-Wl,-z,nodelete")
  1586  				// Only pass Bsymbolic on non-Windows.
  1587  				argv = append(argv, "-Wl,-Bsymbolic")
  1588  			}
  1589  		}
  1590  	case BuildModeShared:
  1591  		if ctxt.UseRelro() {
  1592  			argv = append(argv, "-Wl,-z,relro")
  1593  		}
  1594  		argv = append(argv, "-shared")
  1595  	case BuildModePlugin:
  1596  		if ctxt.HeadType == objabi.Hdarwin {
  1597  			argv = append(argv, "-dynamiclib")
  1598  		} else {
  1599  			if ctxt.UseRelro() {
  1600  				argv = append(argv, "-Wl,-z,relro")
  1601  			}
  1602  			argv = append(argv, "-shared")
  1603  		}
  1604  	}
  1605  
  1606  	var altLinker string
  1607  	if ctxt.IsELF && ctxt.DynlinkingGo() {
  1608  		// We force all symbol resolution to be done at program startup
  1609  		// because lazy PLT resolution can use large amounts of stack at
  1610  		// times we cannot allow it to do so.
  1611  		argv = append(argv, "-Wl,-z,now")
  1612  
  1613  		// Do not let the host linker generate COPY relocations. These
  1614  		// can move symbols out of sections that rely on stable offsets
  1615  		// from the beginning of the section (like sym.STYPE).
  1616  		argv = append(argv, "-Wl,-z,nocopyreloc")
  1617  
  1618  		if buildcfg.GOOS == "android" {
  1619  			// Use lld to avoid errors from default linker (issue #38838)
  1620  			altLinker = "lld"
  1621  		}
  1622  
  1623  		if ctxt.Arch.InFamily(sys.ARM64) && buildcfg.GOOS == "linux" {
  1624  			// On ARM64, the GNU linker will fail with
  1625  			// -znocopyreloc if it thinks a COPY relocation is
  1626  			// required. Switch to gold.
  1627  			// https://sourceware.org/bugzilla/show_bug.cgi?id=19962
  1628  			// https://go.dev/issue/22040
  1629  			altLinker = "gold"
  1630  
  1631  			// If gold is not installed, gcc will silently switch
  1632  			// back to ld.bfd. So we parse the version information
  1633  			// and provide a useful error if gold is missing.
  1634  			name, args := flagExtld[0], flagExtld[1:]
  1635  			args = append(args, "-fuse-ld=gold", "-Wl,--version")
  1636  			cmd := exec.Command(name, args...)
  1637  			if out, err := cmd.CombinedOutput(); err == nil {
  1638  				if !bytes.Contains(out, []byte("GNU gold")) {
  1639  					log.Fatalf("ARM64 external linker must be gold (issue #15696, 22040), but is not: %s", out)
  1640  				}
  1641  			}
  1642  		}
  1643  	}
  1644  	if ctxt.Arch.Family == sys.ARM64 && buildcfg.GOOS == "freebsd" {
  1645  		// Switch to ld.bfd on freebsd/arm64.
  1646  		altLinker = "bfd"
  1647  
  1648  		// Provide a useful error if ld.bfd is missing.
  1649  		name, args := flagExtld[0], flagExtld[1:]
  1650  		args = append(args, "-fuse-ld=bfd", "-Wl,--version")
  1651  		cmd := exec.Command(name, args...)
  1652  		if out, err := cmd.CombinedOutput(); err == nil {
  1653  			if !bytes.Contains(out, []byte("GNU ld")) {
  1654  				log.Fatalf("ARM64 external linker must be ld.bfd (issue #35197), please install devel/binutils")
  1655  			}
  1656  		}
  1657  	}
  1658  	if altLinker != "" {
  1659  		argv = append(argv, "-fuse-ld="+altLinker)
  1660  	}
  1661  
  1662  	if ctxt.IsELF && len(buildinfo) > 0 {
  1663  		argv = append(argv, fmt.Sprintf("-Wl,--build-id=0x%x", buildinfo))
  1664  	}
  1665  
  1666  	// On Windows, given -o foo, GCC will append ".exe" to produce
  1667  	// "foo.exe".  We have decided that we want to honor the -o
  1668  	// option. To make this work, we append a '.' so that GCC
  1669  	// will decide that the file already has an extension. We
  1670  	// only want to do this when producing a Windows output file
  1671  	// on a Windows host.
  1672  	outopt := *flagOutfile
  1673  	if buildcfg.GOOS == "windows" && runtime.GOOS == "windows" && filepath.Ext(outopt) == "" {
  1674  		outopt += "."
  1675  	}
  1676  	argv = append(argv, "-o")
  1677  	argv = append(argv, outopt)
  1678  
  1679  	if rpath.val != "" {
  1680  		argv = append(argv, fmt.Sprintf("-Wl,-rpath,%s", rpath.val))
  1681  	}
  1682  
  1683  	if *flagInterpreter != "" {
  1684  		// Many linkers support both -I and the --dynamic-linker flags
  1685  		// to set the ELF interpreter, but lld only supports
  1686  		// --dynamic-linker so prefer that (ld on very old Solaris only
  1687  		// supports -I but that seems less important).
  1688  		argv = append(argv, fmt.Sprintf("-Wl,--dynamic-linker,%s", *flagInterpreter))
  1689  	}
  1690  
  1691  	// Force global symbols to be exported for dlopen, etc.
  1692  	if ctxt.IsELF {
  1693  		if ctxt.DynlinkingGo() || ctxt.BuildMode == BuildModeCShared || !linkerFlagSupported(ctxt.Arch, argv[0], altLinker, "-Wl,--export-dynamic-symbol=main") {
  1694  			argv = append(argv, "-rdynamic")
  1695  		} else {
  1696  			var exports []string
  1697  			ctxt.loader.ForAllCgoExportDynamic(func(s loader.Sym) {
  1698  				exports = append(exports, "-Wl,--export-dynamic-symbol="+ctxt.loader.SymExtname(s))
  1699  			})
  1700  			sort.Strings(exports)
  1701  			argv = append(argv, exports...)
  1702  		}
  1703  	}
  1704  	if ctxt.HeadType == objabi.Haix {
  1705  		fileName := xcoffCreateExportFile(ctxt)
  1706  		argv = append(argv, "-Wl,-bE:"+fileName)
  1707  	}
  1708  
  1709  	const unusedArguments = "-Qunused-arguments"
  1710  	if linkerFlagSupported(ctxt.Arch, argv[0], altLinker, unusedArguments) {
  1711  		argv = append(argv, unusedArguments)
  1712  	}
  1713  
  1714  	if ctxt.IsWindows() {
  1715  		// Suppress generation of the PE file header timestamp,
  1716  		// so as to avoid spurious build ID differences between
  1717  		// linked binaries that are otherwise identical other than
  1718  		// the date/time they were linked.
  1719  		const noTimeStamp = "-Wl,--no-insert-timestamp"
  1720  		if linkerFlagSupported(ctxt.Arch, argv[0], altLinker, noTimeStamp) {
  1721  			argv = append(argv, noTimeStamp)
  1722  		}
  1723  	}
  1724  
  1725  	const compressDWARF = "-Wl,--compress-debug-sections=zlib"
  1726  	if ctxt.compressDWARF && linkerFlagSupported(ctxt.Arch, argv[0], altLinker, compressDWARF) {
  1727  		argv = append(argv, compressDWARF)
  1728  	}
  1729  
  1730  	argv = append(argv, filepath.Join(*flagTmpdir, "go.o"))
  1731  	argv = append(argv, ctxt.hostobjCopy()...)
  1732  	if ctxt.HeadType == objabi.Haix {
  1733  		// We want to have C files after Go files to remove
  1734  		// trampolines csects made by ld.
  1735  		argv = append(argv, "-nostartfiles")
  1736  		argv = append(argv, "/lib/crt0_64.o")
  1737  
  1738  		extld := ctxt.extld()
  1739  		name, args := extld[0], extld[1:]
  1740  		// Get starting files.
  1741  		getPathFile := func(file string) string {
  1742  			args := append(args, "-maix64", "--print-file-name="+file)
  1743  			out, err := exec.Command(name, args...).CombinedOutput()
  1744  			if err != nil {
  1745  				log.Fatalf("running %s failed: %v\n%s", extld, err, out)
  1746  			}
  1747  			return strings.Trim(string(out), "\n")
  1748  		}
  1749  		// Since GCC version 11, the 64-bit version of GCC starting files
  1750  		// are now suffixed by "_64". Even under "-maix64" multilib directory
  1751  		// "crtcxa.o" is 32-bit.
  1752  		crtcxa := getPathFile("crtcxa_64.o")
  1753  		if !filepath.IsAbs(crtcxa) {
  1754  			crtcxa = getPathFile("crtcxa.o")
  1755  		}
  1756  		crtdbase := getPathFile("crtdbase_64.o")
  1757  		if !filepath.IsAbs(crtdbase) {
  1758  			crtdbase = getPathFile("crtdbase.o")
  1759  		}
  1760  		argv = append(argv, crtcxa)
  1761  		argv = append(argv, crtdbase)
  1762  	}
  1763  
  1764  	if ctxt.linkShared {
  1765  		seenDirs := make(map[string]bool)
  1766  		seenLibs := make(map[string]bool)
  1767  		addshlib := func(path string) {
  1768  			dir, base := filepath.Split(path)
  1769  			if !seenDirs[dir] {
  1770  				argv = append(argv, "-L"+dir)
  1771  				if !rpath.set {
  1772  					argv = append(argv, "-Wl,-rpath="+dir)
  1773  				}
  1774  				seenDirs[dir] = true
  1775  			}
  1776  			base = strings.TrimSuffix(base, ".so")
  1777  			base = strings.TrimPrefix(base, "lib")
  1778  			if !seenLibs[base] {
  1779  				argv = append(argv, "-l"+base)
  1780  				seenLibs[base] = true
  1781  			}
  1782  		}
  1783  		for _, shlib := range ctxt.Shlibs {
  1784  			addshlib(shlib.Path)
  1785  			for _, dep := range shlib.Deps {
  1786  				if dep == "" {
  1787  					continue
  1788  				}
  1789  				libpath := findshlib(ctxt, dep)
  1790  				if libpath != "" {
  1791  					addshlib(libpath)
  1792  				}
  1793  			}
  1794  		}
  1795  	}
  1796  
  1797  	// clang, unlike GCC, passes -rdynamic to the linker
  1798  	// even when linking with -static, causing a linker
  1799  	// error when using GNU ld. So take out -rdynamic if
  1800  	// we added it. We do it in this order, rather than
  1801  	// only adding -rdynamic later, so that -extldflags
  1802  	// can override -rdynamic without using -static.
  1803  	// Similarly for -Wl,--dynamic-linker.
  1804  	checkStatic := func(arg string) {
  1805  		if ctxt.IsELF && arg == "-static" {
  1806  			for i := range argv {
  1807  				if argv[i] == "-rdynamic" || strings.HasPrefix(argv[i], "-Wl,--dynamic-linker,") {
  1808  					argv[i] = "-static"
  1809  				}
  1810  			}
  1811  		}
  1812  	}
  1813  
  1814  	for _, p := range ldflag {
  1815  		argv = append(argv, p)
  1816  		checkStatic(p)
  1817  	}
  1818  
  1819  	// When building a program with the default -buildmode=exe the
  1820  	// gc compiler generates code requires DT_TEXTREL in a
  1821  	// position independent executable (PIE). On systems where the
  1822  	// toolchain creates PIEs by default, and where DT_TEXTREL
  1823  	// does not work, the resulting programs will not run. See
  1824  	// issue #17847. To avoid this problem pass -no-pie to the
  1825  	// toolchain if it is supported.
  1826  	if ctxt.BuildMode == BuildModeExe && !ctxt.linkShared && !(ctxt.IsDarwin() && ctxt.IsARM64()) {
  1827  		// GCC uses -no-pie, clang uses -nopie.
  1828  		for _, nopie := range []string{"-no-pie", "-nopie"} {
  1829  			if linkerFlagSupported(ctxt.Arch, argv[0], altLinker, nopie) {
  1830  				argv = append(argv, nopie)
  1831  				break
  1832  			}
  1833  		}
  1834  	}
  1835  
  1836  	for _, p := range flagExtldflags {
  1837  		argv = append(argv, p)
  1838  		checkStatic(p)
  1839  	}
  1840  	if ctxt.HeadType == objabi.Hwindows {
  1841  		// Determine which linker we're using. Add in the extldflags in
  1842  		// case used has specified "-fuse-ld=...".
  1843  		extld := ctxt.extld()
  1844  		name, args := extld[0], extld[1:]
  1845  		args = append(args, trimLinkerArgv(flagExtldflags)...)
  1846  		args = append(args, "-Wl,--version")
  1847  		cmd := exec.Command(name, args...)
  1848  		usingLLD := false
  1849  		if out, err := cmd.CombinedOutput(); err == nil {
  1850  			if bytes.Contains(out, []byte("LLD ")) {
  1851  				usingLLD = true
  1852  			}
  1853  		}
  1854  
  1855  		// use gcc linker script to work around gcc bug
  1856  		// (see https://golang.org/issue/20183 for details).
  1857  		if !usingLLD {
  1858  			p := writeGDBLinkerScript()
  1859  			argv = append(argv, "-Wl,-T,"+p)
  1860  		}
  1861  		if *flagRace {
  1862  			if p := ctxt.findLibPath("libsynchronization.a"); p != "libsynchronization.a" {
  1863  				argv = append(argv, "-lsynchronization")
  1864  			}
  1865  		}
  1866  		// libmingw32 and libmingwex have some inter-dependencies,
  1867  		// so must use linker groups.
  1868  		argv = append(argv, "-Wl,--start-group", "-lmingwex", "-lmingw32", "-Wl,--end-group")
  1869  		argv = append(argv, peimporteddlls()...)
  1870  	}
  1871  
  1872  	argv = ctxt.passLongArgsInResponseFile(argv, altLinker)
  1873  
  1874  	if ctxt.Debugvlog != 0 {
  1875  		ctxt.Logf("host link:")
  1876  		for _, v := range argv {
  1877  			ctxt.Logf(" %q", v)
  1878  		}
  1879  		ctxt.Logf("\n")
  1880  	}
  1881  
  1882  	out, err := exec.Command(argv[0], argv[1:]...).CombinedOutput()
  1883  	if err != nil {
  1884  		Exitf("running %s failed: %v\n%s", argv[0], err, out)
  1885  	}
  1886  
  1887  	// Filter out useless linker warnings caused by bugs outside Go.
  1888  	// See also github.com/go-asm/go/cmd/go/work/exec.go's gccld method.
  1889  	var save [][]byte
  1890  	var skipLines int
  1891  	for _, line := range bytes.SplitAfter(out, []byte("\n")) {
  1892  		// golang.org/issue/26073 - Apple Xcode bug
  1893  		if bytes.Contains(line, []byte("ld: warning: text-based stub file")) {
  1894  			continue
  1895  		}
  1896  
  1897  		if skipLines > 0 {
  1898  			skipLines--
  1899  			continue
  1900  		}
  1901  
  1902  		// Remove TOC overflow warning on AIX.
  1903  		if bytes.Contains(line, []byte("ld: 0711-783")) {
  1904  			skipLines = 2
  1905  			continue
  1906  		}
  1907  
  1908  		save = append(save, line)
  1909  	}
  1910  	out = bytes.Join(save, nil)
  1911  
  1912  	if len(out) > 0 {
  1913  		// always print external output even if the command is successful, so that we don't
  1914  		// swallow linker warnings (see https://golang.org/issue/17935).
  1915  		if ctxt.IsDarwin() && ctxt.IsAMD64() {
  1916  			const noPieWarning = "ld: warning: -no_pie is deprecated when targeting new OS versions\n"
  1917  			if i := bytes.Index(out, []byte(noPieWarning)); i >= 0 {
  1918  				// swallow -no_pie deprecation warning, issue 54482
  1919  				out = append(out[:i], out[i+len(noPieWarning):]...)
  1920  			}
  1921  		}
  1922  		if ctxt.IsDarwin() {
  1923  			const bindAtLoadWarning = "ld: warning: -bind_at_load is deprecated on macOS\n"
  1924  			if i := bytes.Index(out, []byte(bindAtLoadWarning)); i >= 0 {
  1925  				// -bind_at_load is deprecated with ld-prime, but needed for
  1926  				// correctness with older versions of ld64. Swallow the warning.
  1927  				// TODO: maybe pass -bind_at_load conditionally based on C
  1928  				// linker version.
  1929  				out = append(out[:i], out[i+len(bindAtLoadWarning):]...)
  1930  			}
  1931  		}
  1932  		ctxt.Logf("%s", out)
  1933  	}
  1934  
  1935  	if combineDwarf {
  1936  		// Find "dsymutils" and "strip" tools using CC --print-prog-name.
  1937  		var cc []string
  1938  		cc = append(cc, ctxt.extld()...)
  1939  		cc = append(cc, hostlinkArchArgs(ctxt.Arch)...)
  1940  		cc = append(cc, "--print-prog-name", "dsymutil")
  1941  		out, err := exec.Command(cc[0], cc[1:]...).CombinedOutput()
  1942  		if err != nil {
  1943  			Exitf("%s: finding dsymutil failed: %v\n%s", os.Args[0], err, out)
  1944  		}
  1945  		dsymutilCmd := strings.TrimSuffix(string(out), "\n")
  1946  
  1947  		cc[len(cc)-1] = "strip"
  1948  		out, err = exec.Command(cc[0], cc[1:]...).CombinedOutput()
  1949  		if err != nil {
  1950  			Exitf("%s: finding strip failed: %v\n%s", os.Args[0], err, out)
  1951  		}
  1952  		stripCmd := strings.TrimSuffix(string(out), "\n")
  1953  
  1954  		dsym := filepath.Join(*flagTmpdir, "go.dwarf")
  1955  		cmd := exec.Command(dsymutilCmd, "-f", *flagOutfile, "-o", dsym)
  1956  		// dsymutil may not clean up its temp directory at exit.
  1957  		// Set DSYMUTIL_REPRODUCER_PATH to work around. see issue 59026.
  1958  		cmd.Env = append(os.Environ(), "DSYMUTIL_REPRODUCER_PATH="+*flagTmpdir)
  1959  		if ctxt.Debugvlog != 0 {
  1960  			ctxt.Logf("host link dsymutil:")
  1961  			for _, v := range cmd.Args {
  1962  				ctxt.Logf(" %q", v)
  1963  			}
  1964  			ctxt.Logf("\n")
  1965  		}
  1966  		if out, err := cmd.CombinedOutput(); err != nil {
  1967  			Exitf("%s: running dsymutil failed: %v\n%s", os.Args[0], err, out)
  1968  		}
  1969  		// Remove STAB (symbolic debugging) symbols after we are done with them (by dsymutil).
  1970  		// They contain temporary file paths and make the build not reproducible.
  1971  		var stripArgs = []string{"-S"}
  1972  		if debug_s {
  1973  			// We are generating a binary with symbol table suppressed.
  1974  			// Suppress local symbols. We need to keep dynamically exported
  1975  			// and referenced symbols so the dynamic linker can resolve them.
  1976  			stripArgs = append(stripArgs, "-x")
  1977  		}
  1978  		stripArgs = append(stripArgs, *flagOutfile)
  1979  		if ctxt.Debugvlog != 0 {
  1980  			ctxt.Logf("host link strip: %q", stripCmd)
  1981  			for _, v := range stripArgs {
  1982  				ctxt.Logf(" %q", v)
  1983  			}
  1984  			ctxt.Logf("\n")
  1985  		}
  1986  		if out, err := exec.Command(stripCmd, stripArgs...).CombinedOutput(); err != nil {
  1987  			Exitf("%s: running strip failed: %v\n%s", os.Args[0], err, out)
  1988  		}
  1989  		// Skip combining if `dsymutil` didn't generate a file. See #11994.
  1990  		if _, err := os.Stat(dsym); os.IsNotExist(err) {
  1991  			return
  1992  		}
  1993  		// For os.Rename to work reliably, must be in same directory as outfile.
  1994  		combinedOutput := *flagOutfile + "~"
  1995  		exef, err := os.Open(*flagOutfile)
  1996  		if err != nil {
  1997  			Exitf("%s: combining dwarf failed: %v", os.Args[0], err)
  1998  		}
  1999  		defer exef.Close()
  2000  		exem, err := macho.NewFile(exef)
  2001  		if err != nil {
  2002  			Exitf("%s: parsing Mach-O header failed: %v", os.Args[0], err)
  2003  		}
  2004  		if err := machoCombineDwarf(ctxt, exef, exem, dsym, combinedOutput); err != nil {
  2005  			Exitf("%s: combining dwarf failed: %v", os.Args[0], err)
  2006  		}
  2007  		os.Remove(*flagOutfile)
  2008  		if err := os.Rename(combinedOutput, *flagOutfile); err != nil {
  2009  			Exitf("%s: %v", os.Args[0], err)
  2010  		}
  2011  	}
  2012  	if ctxt.NeedCodeSign() {
  2013  		err := machoCodeSign(ctxt, *flagOutfile)
  2014  		if err != nil {
  2015  			Exitf("%s: code signing failed: %v", os.Args[0], err)
  2016  		}
  2017  	}
  2018  }
  2019  
  2020  // passLongArgsInResponseFile writes the arguments into a file if they
  2021  // are very long.
  2022  func (ctxt *Link) passLongArgsInResponseFile(argv []string, altLinker string) []string {
  2023  	c := 0
  2024  	for _, arg := range argv {
  2025  		c += len(arg)
  2026  	}
  2027  
  2028  	if c < sys.ExecArgLengthLimit {
  2029  		return argv
  2030  	}
  2031  
  2032  	// Only use response files if they are supported.
  2033  	response := filepath.Join(*flagTmpdir, "response")
  2034  	if err := os.WriteFile(response, nil, 0644); err != nil {
  2035  		log.Fatalf("failed while testing response file: %v", err)
  2036  	}
  2037  	if !linkerFlagSupported(ctxt.Arch, argv[0], altLinker, "@"+response) {
  2038  		if ctxt.Debugvlog != 0 {
  2039  			ctxt.Logf("not using response file because linker does not support one")
  2040  		}
  2041  		return argv
  2042  	}
  2043  
  2044  	var buf bytes.Buffer
  2045  	for _, arg := range argv[1:] {
  2046  		// The external linker response file supports quoted strings.
  2047  		fmt.Fprintf(&buf, "%q\n", arg)
  2048  	}
  2049  	if err := os.WriteFile(response, buf.Bytes(), 0644); err != nil {
  2050  		log.Fatalf("failed while writing response file: %v", err)
  2051  	}
  2052  	if ctxt.Debugvlog != 0 {
  2053  		ctxt.Logf("response file %s contents:\n%s", response, buf.Bytes())
  2054  	}
  2055  	return []string{
  2056  		argv[0],
  2057  		"@" + response,
  2058  	}
  2059  }
  2060  
  2061  var createTrivialCOnce sync.Once
  2062  
  2063  func linkerFlagSupported(arch *sys.Arch, linker, altLinker, flag string) bool {
  2064  	createTrivialCOnce.Do(func() {
  2065  		src := filepath.Join(*flagTmpdir, "trivial.c")
  2066  		if err := os.WriteFile(src, []byte("int main() { return 0; }"), 0666); err != nil {
  2067  			Errorf(nil, "WriteFile trivial.c failed: %v", err)
  2068  		}
  2069  	})
  2070  
  2071  	flags := hostlinkArchArgs(arch)
  2072  
  2073  	moreFlags := trimLinkerArgv(append(flagExtldflags, ldflag...))
  2074  	flags = append(flags, moreFlags...)
  2075  
  2076  	if altLinker != "" {
  2077  		flags = append(flags, "-fuse-ld="+altLinker)
  2078  	}
  2079  	trivialPath := filepath.Join(*flagTmpdir, "trivial.c")
  2080  	outPath := filepath.Join(*flagTmpdir, "a.out")
  2081  	flags = append(flags, "-o", outPath, flag, trivialPath)
  2082  
  2083  	cmd := exec.Command(linker, flags...)
  2084  	cmd.Env = append([]string{"LC_ALL=C"}, os.Environ()...)
  2085  	out, err := cmd.CombinedOutput()
  2086  	// GCC says "unrecognized command line option ‘-no-pie’"
  2087  	// clang says "unknown argument: '-no-pie'"
  2088  	return err == nil && !bytes.Contains(out, []byte("unrecognized")) && !bytes.Contains(out, []byte("unknown"))
  2089  }
  2090  
  2091  // trimLinkerArgv returns a new copy of argv that does not include flags
  2092  // that are not relevant for testing whether some linker option works.
  2093  func trimLinkerArgv(argv []string) []string {
  2094  	flagsWithNextArgSkip := []string{
  2095  		"-F",
  2096  		"-l",
  2097  		"-L",
  2098  		"-framework",
  2099  		"-Wl,-framework",
  2100  		"-Wl,-rpath",
  2101  		"-Wl,-undefined",
  2102  	}
  2103  	flagsWithNextArgKeep := []string{
  2104  		"-arch",
  2105  		"-isysroot",
  2106  		"--sysroot",
  2107  		"-target",
  2108  	}
  2109  	prefixesToKeep := []string{
  2110  		"-f",
  2111  		"-m",
  2112  		"-p",
  2113  		"-Wl,",
  2114  		"-arch",
  2115  		"-isysroot",
  2116  		"--sysroot",
  2117  		"-target",
  2118  	}
  2119  
  2120  	var flags []string
  2121  	keep := false
  2122  	skip := false
  2123  	for _, f := range argv {
  2124  		if keep {
  2125  			flags = append(flags, f)
  2126  			keep = false
  2127  		} else if skip {
  2128  			skip = false
  2129  		} else if f == "" || f[0] != '-' {
  2130  		} else if contains(flagsWithNextArgSkip, f) {
  2131  			skip = true
  2132  		} else if contains(flagsWithNextArgKeep, f) {
  2133  			flags = append(flags, f)
  2134  			keep = true
  2135  		} else {
  2136  			for _, p := range prefixesToKeep {
  2137  				if strings.HasPrefix(f, p) {
  2138  					flags = append(flags, f)
  2139  					break
  2140  				}
  2141  			}
  2142  		}
  2143  	}
  2144  	return flags
  2145  }
  2146  
  2147  // hostlinkArchArgs returns arguments to pass to the external linker
  2148  // based on the architecture.
  2149  func hostlinkArchArgs(arch *sys.Arch) []string {
  2150  	switch arch.Family {
  2151  	case sys.I386:
  2152  		return []string{"-m32"}
  2153  	case sys.AMD64:
  2154  		if buildcfg.GOOS == "darwin" {
  2155  			return []string{"-arch", "x86_64", "-m64"}
  2156  		}
  2157  		return []string{"-m64"}
  2158  	case sys.S390X:
  2159  		return []string{"-m64"}
  2160  	case sys.ARM:
  2161  		return []string{"-marm"}
  2162  	case sys.ARM64:
  2163  		if buildcfg.GOOS == "darwin" {
  2164  			return []string{"-arch", "arm64"}
  2165  		}
  2166  	case sys.Loong64:
  2167  		return []string{"-mabi=lp64d"}
  2168  	case sys.MIPS64:
  2169  		return []string{"-mabi=64"}
  2170  	case sys.MIPS:
  2171  		return []string{"-mabi=32"}
  2172  	case sys.PPC64:
  2173  		if buildcfg.GOOS == "aix" {
  2174  			return []string{"-maix64"}
  2175  		} else {
  2176  			return []string{"-m64"}
  2177  		}
  2178  
  2179  	}
  2180  	return nil
  2181  }
  2182  
  2183  var wantHdr = objabi.HeaderString()
  2184  
  2185  // ldobj loads an input object. If it is a host object (an object
  2186  // compiled by a non-Go compiler) it returns the Hostobj pointer. If
  2187  // it is a Go object, it returns nil.
  2188  func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string, file string) *Hostobj {
  2189  	pkg := objabi.PathToPrefix(lib.Pkg)
  2190  
  2191  	eof := f.Offset() + length
  2192  	start := f.Offset()
  2193  	c1 := bgetc(f)
  2194  	c2 := bgetc(f)
  2195  	c3 := bgetc(f)
  2196  	c4 := bgetc(f)
  2197  	f.MustSeek(start, 0)
  2198  
  2199  	unit := &sym.CompilationUnit{Lib: lib}
  2200  	lib.Units = append(lib.Units, unit)
  2201  
  2202  	magic := uint32(c1)<<24 | uint32(c2)<<16 | uint32(c3)<<8 | uint32(c4)
  2203  	if magic == 0x7f454c46 { // \x7F E L F
  2204  		ldelf := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
  2205  			textp, flags, err := loadelf.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn, ehdr.Flags)
  2206  			if err != nil {
  2207  				Errorf(nil, "%v", err)
  2208  				return
  2209  			}
  2210  			ehdr.Flags = flags
  2211  			ctxt.Textp = append(ctxt.Textp, textp...)
  2212  		}
  2213  		return ldhostobj(ldelf, ctxt.HeadType, f, pkg, length, pn, file)
  2214  	}
  2215  
  2216  	if magic&^1 == 0xfeedface || magic&^0x01000000 == 0xcefaedfe {
  2217  		ldmacho := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
  2218  			textp, err := loadmacho.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn)
  2219  			if err != nil {
  2220  				Errorf(nil, "%v", err)
  2221  				return
  2222  			}
  2223  			ctxt.Textp = append(ctxt.Textp, textp...)
  2224  		}
  2225  		return ldhostobj(ldmacho, ctxt.HeadType, f, pkg, length, pn, file)
  2226  	}
  2227  
  2228  	switch c1<<8 | c2 {
  2229  	case 0x4c01, // 386
  2230  		0x6486, // amd64
  2231  		0xc401, // arm
  2232  		0x64aa: // arm64
  2233  		ldpe := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
  2234  			ls, err := loadpe.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn)
  2235  			if err != nil {
  2236  				Errorf(nil, "%v", err)
  2237  				return
  2238  			}
  2239  			if len(ls.Resources) != 0 {
  2240  				setpersrc(ctxt, ls.Resources)
  2241  			}
  2242  			if ls.PData != 0 {
  2243  				sehp.pdata = append(sehp.pdata, ls.PData)
  2244  			}
  2245  			if ls.XData != 0 {
  2246  				sehp.xdata = append(sehp.xdata, ls.XData)
  2247  			}
  2248  			ctxt.Textp = append(ctxt.Textp, ls.Textp...)
  2249  		}
  2250  		return ldhostobj(ldpe, ctxt.HeadType, f, pkg, length, pn, file)
  2251  	}
  2252  
  2253  	if c1 == 0x01 && (c2 == 0xD7 || c2 == 0xF7) {
  2254  		ldxcoff := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
  2255  			textp, err := loadxcoff.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn)
  2256  			if err != nil {
  2257  				Errorf(nil, "%v", err)
  2258  				return
  2259  			}
  2260  			ctxt.Textp = append(ctxt.Textp, textp...)
  2261  		}
  2262  		return ldhostobj(ldxcoff, ctxt.HeadType, f, pkg, length, pn, file)
  2263  	}
  2264  
  2265  	if c1 != 'g' || c2 != 'o' || c3 != ' ' || c4 != 'o' {
  2266  		// An unrecognized object is just passed to the external linker.
  2267  		// If we try to read symbols from this object, we will
  2268  		// report an error at that time.
  2269  		unknownObjFormat = true
  2270  		return ldhostobj(nil, ctxt.HeadType, f, pkg, length, pn, file)
  2271  	}
  2272  
  2273  	/* check the header */
  2274  	line, err := f.ReadString('\n')
  2275  	if err != nil {
  2276  		Errorf(nil, "truncated object file: %s: %v", pn, err)
  2277  		return nil
  2278  	}
  2279  
  2280  	if !strings.HasPrefix(line, "go object ") {
  2281  		if strings.HasSuffix(pn, ".go") {
  2282  			Exitf("%s: uncompiled .go source file", pn)
  2283  			return nil
  2284  		}
  2285  
  2286  		if line == ctxt.Arch.Name {
  2287  			// old header format: just $GOOS
  2288  			Errorf(nil, "%s: stale object file", pn)
  2289  			return nil
  2290  		}
  2291  
  2292  		Errorf(nil, "%s: not an object file: @%d %q", pn, start, line)
  2293  		return nil
  2294  	}
  2295  
  2296  	// First, check that the basic GOOS, GOARCH, and Version match.
  2297  	if line != wantHdr {
  2298  		Errorf(nil, "%s: linked object header mismatch:\nhave %q\nwant %q\n", pn, line, wantHdr)
  2299  	}
  2300  
  2301  	// Skip over exports and other info -- ends with \n!\n.
  2302  	//
  2303  	// Note: It's possible for "\n!\n" to appear within the binary
  2304  	// package export data format. To avoid truncating the package
  2305  	// definition prematurely (issue 21703), we keep track of
  2306  	// how many "$$" delimiters we've seen.
  2307  
  2308  	import0 := f.Offset()
  2309  
  2310  	c1 = '\n' // the last line ended in \n
  2311  	c2 = bgetc(f)
  2312  	c3 = bgetc(f)
  2313  	markers := 0
  2314  	for {
  2315  		if c1 == '\n' {
  2316  			if markers%2 == 0 && c2 == '!' && c3 == '\n' {
  2317  				break
  2318  			}
  2319  			if c2 == '$' && c3 == '$' {
  2320  				markers++
  2321  			}
  2322  		}
  2323  
  2324  		c1 = c2
  2325  		c2 = c3
  2326  		c3 = bgetc(f)
  2327  		if c3 == -1 {
  2328  			Errorf(nil, "truncated object file: %s", pn)
  2329  			return nil
  2330  		}
  2331  	}
  2332  
  2333  	import1 := f.Offset()
  2334  
  2335  	f.MustSeek(import0, 0)
  2336  	ldpkg(ctxt, f, lib, import1-import0-2, pn) // -2 for !\n
  2337  	f.MustSeek(import1, 0)
  2338  
  2339  	fingerprint := ctxt.loader.Preload(ctxt.IncVersion(), f, lib, unit, eof-f.Offset())
  2340  	if !fingerprint.IsZero() { // Assembly objects don't have fingerprints. Ignore them.
  2341  		// Check fingerprint, to ensure the importing and imported packages
  2342  		// have consistent view of symbol indices.
  2343  		// Normally the go command should ensure this. But in case something
  2344  		// goes wrong, it could lead to obscure bugs like run-time crash.
  2345  		// Check it here to be sure.
  2346  		if lib.Fingerprint.IsZero() { // Not yet imported. Update its fingerprint.
  2347  			lib.Fingerprint = fingerprint
  2348  		}
  2349  		checkFingerprint(lib, fingerprint, lib.Srcref, lib.Fingerprint)
  2350  	}
  2351  
  2352  	addImports(ctxt, lib, pn)
  2353  	return nil
  2354  }
  2355  
  2356  // symbolsAreUnresolved scans through the loader's list of unresolved
  2357  // symbols and checks to see whether any of them match the names of the
  2358  // symbols in 'want'. Return value is a list of bools, with list[K] set
  2359  // to true if there is an unresolved reference to the symbol in want[K].
  2360  func symbolsAreUnresolved(ctxt *Link, want []string) []bool {
  2361  	returnAllUndefs := -1
  2362  	undefs, _ := ctxt.loader.UndefinedRelocTargets(returnAllUndefs)
  2363  	seen := make(map[loader.Sym]struct{})
  2364  	rval := make([]bool, len(want))
  2365  	wantm := make(map[string]int)
  2366  	for k, w := range want {
  2367  		wantm[w] = k
  2368  	}
  2369  	count := 0
  2370  	for _, s := range undefs {
  2371  		if _, ok := seen[s]; ok {
  2372  			continue
  2373  		}
  2374  		seen[s] = struct{}{}
  2375  		if k, ok := wantm[ctxt.loader.SymName(s)]; ok {
  2376  			rval[k] = true
  2377  			count++
  2378  			if count == len(want) {
  2379  				return rval
  2380  			}
  2381  		}
  2382  	}
  2383  	return rval
  2384  }
  2385  
  2386  // hostObject reads a single host object file (compare to "hostArchive").
  2387  // This is used as part of internal linking when we need to pull in
  2388  // files such as "crt?.o".
  2389  func hostObject(ctxt *Link, objname string, path string) {
  2390  	if ctxt.Debugvlog > 1 {
  2391  		ctxt.Logf("hostObject(%s)\n", path)
  2392  	}
  2393  	objlib := sym.Library{
  2394  		Pkg: objname,
  2395  	}
  2396  	f, err := bio.Open(path)
  2397  	if err != nil {
  2398  		Exitf("cannot open host object %q file %s: %v", objname, path, err)
  2399  	}
  2400  	defer f.Close()
  2401  	h := ldobj(ctxt, f, &objlib, 0, path, path)
  2402  	if h.ld == nil {
  2403  		Exitf("unrecognized object file format in %s", path)
  2404  	}
  2405  	h.file = path
  2406  	h.length = f.MustSeek(0, 2)
  2407  	f.MustSeek(h.off, 0)
  2408  	h.ld(ctxt, f, h.pkg, h.length, h.pn)
  2409  	if *flagCaptureHostObjs != "" {
  2410  		captureHostObj(h)
  2411  	}
  2412  }
  2413  
  2414  func checkFingerprint(lib *sym.Library, libfp goobj.FingerprintType, src string, srcfp goobj.FingerprintType) {
  2415  	if libfp != srcfp {
  2416  		Exitf("fingerprint mismatch: %s has %x, import from %s expecting %x", lib, libfp, src, srcfp)
  2417  	}
  2418  }
  2419  
  2420  func readelfsymboldata(ctxt *Link, f *elf.File, sym *elf.Symbol) []byte {
  2421  	data := make([]byte, sym.Size)
  2422  	sect := f.Sections[sym.Section]
  2423  	if sect.Type != elf.SHT_PROGBITS && sect.Type != elf.SHT_NOTE {
  2424  		Errorf(nil, "reading %s from non-data section", sym.Name)
  2425  	}
  2426  	n, err := sect.ReadAt(data, int64(sym.Value-sect.Addr))
  2427  	if uint64(n) != sym.Size {
  2428  		Errorf(nil, "reading contents of %s: %v", sym.Name, err)
  2429  	}
  2430  	return data
  2431  }
  2432  
  2433  func readwithpad(r io.Reader, sz int32) ([]byte, error) {
  2434  	data := make([]byte, Rnd(int64(sz), 4))
  2435  	_, err := io.ReadFull(r, data)
  2436  	if err != nil {
  2437  		return nil, err
  2438  	}
  2439  	data = data[:sz]
  2440  	return data, nil
  2441  }
  2442  
  2443  func readnote(f *elf.File, name []byte, typ int32) ([]byte, error) {
  2444  	for _, sect := range f.Sections {
  2445  		if sect.Type != elf.SHT_NOTE {
  2446  			continue
  2447  		}
  2448  		r := sect.Open()
  2449  		for {
  2450  			var namesize, descsize, noteType int32
  2451  			err := binary.Read(r, f.ByteOrder, &namesize)
  2452  			if err != nil {
  2453  				if err == io.EOF {
  2454  					break
  2455  				}
  2456  				return nil, fmt.Errorf("read namesize failed: %v", err)
  2457  			}
  2458  			err = binary.Read(r, f.ByteOrder, &descsize)
  2459  			if err != nil {
  2460  				return nil, fmt.Errorf("read descsize failed: %v", err)
  2461  			}
  2462  			err = binary.Read(r, f.ByteOrder, &noteType)
  2463  			if err != nil {
  2464  				return nil, fmt.Errorf("read type failed: %v", err)
  2465  			}
  2466  			noteName, err := readwithpad(r, namesize)
  2467  			if err != nil {
  2468  				return nil, fmt.Errorf("read name failed: %v", err)
  2469  			}
  2470  			desc, err := readwithpad(r, descsize)
  2471  			if err != nil {
  2472  				return nil, fmt.Errorf("read desc failed: %v", err)
  2473  			}
  2474  			if string(name) == string(noteName) && typ == noteType {
  2475  				return desc, nil
  2476  			}
  2477  		}
  2478  	}
  2479  	return nil, nil
  2480  }
  2481  
  2482  func findshlib(ctxt *Link, shlib string) string {
  2483  	if filepath.IsAbs(shlib) {
  2484  		return shlib
  2485  	}
  2486  	for _, libdir := range ctxt.Libdir {
  2487  		libpath := filepath.Join(libdir, shlib)
  2488  		if _, err := os.Stat(libpath); err == nil {
  2489  			return libpath
  2490  		}
  2491  	}
  2492  	Errorf(nil, "cannot find shared library: %s", shlib)
  2493  	return ""
  2494  }
  2495  
  2496  func ldshlibsyms(ctxt *Link, shlib string) {
  2497  	var libpath string
  2498  	if filepath.IsAbs(shlib) {
  2499  		libpath = shlib
  2500  		shlib = filepath.Base(shlib)
  2501  	} else {
  2502  		libpath = findshlib(ctxt, shlib)
  2503  		if libpath == "" {
  2504  			return
  2505  		}
  2506  	}
  2507  	for _, processedlib := range ctxt.Shlibs {
  2508  		if processedlib.Path == libpath {
  2509  			return
  2510  		}
  2511  	}
  2512  	if ctxt.Debugvlog > 1 {
  2513  		ctxt.Logf("ldshlibsyms: found library with name %s at %s\n", shlib, libpath)
  2514  	}
  2515  
  2516  	f, err := elf.Open(libpath)
  2517  	if err != nil {
  2518  		Errorf(nil, "cannot open shared library: %s", libpath)
  2519  		return
  2520  	}
  2521  	// Keep the file open as decodetypeGcprog needs to read from it.
  2522  	// TODO: fix. Maybe mmap the file.
  2523  	//defer f.Close()
  2524  
  2525  	hash, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GOABIHASH_TAG)
  2526  	if err != nil {
  2527  		Errorf(nil, "cannot read ABI hash from shared library %s: %v", libpath, err)
  2528  		return
  2529  	}
  2530  
  2531  	depsbytes, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GODEPS_TAG)
  2532  	if err != nil {
  2533  		Errorf(nil, "cannot read dep list from shared library %s: %v", libpath, err)
  2534  		return
  2535  	}
  2536  	var deps []string
  2537  	for _, dep := range strings.Split(string(depsbytes), "\n") {
  2538  		if dep == "" {
  2539  			continue
  2540  		}
  2541  		if !filepath.IsAbs(dep) {
  2542  			// If the dep can be interpreted as a path relative to the shlib
  2543  			// in which it was found, do that. Otherwise, we will leave it
  2544  			// to be resolved by libdir lookup.
  2545  			abs := filepath.Join(filepath.Dir(libpath), dep)
  2546  			if _, err := os.Stat(abs); err == nil {
  2547  				dep = abs
  2548  			}
  2549  		}
  2550  		deps = append(deps, dep)
  2551  	}
  2552  
  2553  	syms, err := f.DynamicSymbols()
  2554  	if err != nil {
  2555  		Errorf(nil, "cannot read symbols from shared library: %s", libpath)
  2556  		return
  2557  	}
  2558  
  2559  	for _, elfsym := range syms {
  2560  		if elf.ST_TYPE(elfsym.Info) == elf.STT_NOTYPE || elf.ST_TYPE(elfsym.Info) == elf.STT_SECTION {
  2561  			continue
  2562  		}
  2563  
  2564  		// Symbols whose names start with "type:" are compiler generated,
  2565  		// so make functions with that prefix internal.
  2566  		ver := 0
  2567  		symname := elfsym.Name // (unmangled) symbol name
  2568  		if elf.ST_TYPE(elfsym.Info) == elf.STT_FUNC && strings.HasPrefix(elfsym.Name, "type:") {
  2569  			ver = abiInternalVer
  2570  		} else if buildcfg.Experiment.RegabiWrappers && elf.ST_TYPE(elfsym.Info) == elf.STT_FUNC {
  2571  			// Demangle the ABI name. Keep in sync with symtab.go:mangleABIName.
  2572  			if strings.HasSuffix(elfsym.Name, ".abiinternal") {
  2573  				ver = sym.SymVerABIInternal
  2574  				symname = strings.TrimSuffix(elfsym.Name, ".abiinternal")
  2575  			} else if strings.HasSuffix(elfsym.Name, ".abi0") {
  2576  				ver = 0
  2577  				symname = strings.TrimSuffix(elfsym.Name, ".abi0")
  2578  			}
  2579  		}
  2580  
  2581  		l := ctxt.loader
  2582  		s := l.LookupOrCreateSym(symname, ver)
  2583  
  2584  		// Because loadlib above loads all .a files before loading
  2585  		// any shared libraries, any non-dynimport symbols we find
  2586  		// that duplicate symbols already loaded should be ignored
  2587  		// (the symbols from the .a files "win").
  2588  		if l.SymType(s) != 0 && l.SymType(s) != sym.SDYNIMPORT {
  2589  			continue
  2590  		}
  2591  		su := l.MakeSymbolUpdater(s)
  2592  		su.SetType(sym.SDYNIMPORT)
  2593  		l.SetSymElfType(s, elf.ST_TYPE(elfsym.Info))
  2594  		su.SetSize(int64(elfsym.Size))
  2595  		if elfsym.Section != elf.SHN_UNDEF {
  2596  			// Set .File for the library that actually defines the symbol.
  2597  			l.SetSymPkg(s, libpath)
  2598  
  2599  			// The decodetype_* functions in decodetype.go need access to
  2600  			// the type data.
  2601  			sname := l.SymName(s)
  2602  			if strings.HasPrefix(sname, "type:") && !strings.HasPrefix(sname, "type:.") {
  2603  				su.SetData(readelfsymboldata(ctxt, f, &elfsym))
  2604  			}
  2605  		}
  2606  
  2607  		if symname != elfsym.Name {
  2608  			l.SetSymExtname(s, elfsym.Name)
  2609  		}
  2610  	}
  2611  	ctxt.Shlibs = append(ctxt.Shlibs, Shlib{Path: libpath, Hash: hash, Deps: deps, File: f})
  2612  }
  2613  
  2614  func addsection(ldr *loader.Loader, arch *sys.Arch, seg *sym.Segment, name string, rwx int) *sym.Section {
  2615  	sect := ldr.NewSection()
  2616  	sect.Rwx = uint8(rwx)
  2617  	sect.Name = name
  2618  	sect.Seg = seg
  2619  	sect.Align = int32(arch.PtrSize) // everything is at least pointer-aligned
  2620  	seg.Sections = append(seg.Sections, sect)
  2621  	return sect
  2622  }
  2623  
  2624  func usage() {
  2625  	fmt.Fprintf(os.Stderr, "usage: link [options] main.o\n")
  2626  	objabi.Flagprint(os.Stderr)
  2627  	Exit(2)
  2628  }
  2629  
  2630  type SymbolType int8 // TODO: after genasmsym is gone, maybe rename to plan9typeChar or something
  2631  
  2632  const (
  2633  	// see also https://9p.io/magic/man2html/1/nm
  2634  	TextSym      SymbolType = 'T'
  2635  	DataSym      SymbolType = 'D'
  2636  	BSSSym       SymbolType = 'B'
  2637  	UndefinedSym SymbolType = 'U'
  2638  	TLSSym       SymbolType = 't'
  2639  	FrameSym     SymbolType = 'm'
  2640  	ParamSym     SymbolType = 'p'
  2641  	AutoSym      SymbolType = 'a'
  2642  
  2643  	// Deleted auto (not a real sym, just placeholder for type)
  2644  	DeletedAutoSym = 'x'
  2645  )
  2646  
  2647  // defineInternal defines a symbol used internally by the go runtime.
  2648  func (ctxt *Link) defineInternal(p string, t sym.SymKind) loader.Sym {
  2649  	s := ctxt.loader.CreateSymForUpdate(p, 0)
  2650  	s.SetType(t)
  2651  	s.SetSpecial(true)
  2652  	s.SetLocal(true)
  2653  	return s.Sym()
  2654  }
  2655  
  2656  func (ctxt *Link) xdefine(p string, t sym.SymKind, v int64) loader.Sym {
  2657  	s := ctxt.defineInternal(p, t)
  2658  	ctxt.loader.SetSymValue(s, v)
  2659  	return s
  2660  }
  2661  
  2662  func datoff(ldr *loader.Loader, s loader.Sym, addr int64) int64 {
  2663  	if uint64(addr) >= Segdata.Vaddr {
  2664  		return int64(uint64(addr) - Segdata.Vaddr + Segdata.Fileoff)
  2665  	}
  2666  	if uint64(addr) >= Segtext.Vaddr {
  2667  		return int64(uint64(addr) - Segtext.Vaddr + Segtext.Fileoff)
  2668  	}
  2669  	ldr.Errorf(s, "invalid datoff %#x", addr)
  2670  	return 0
  2671  }
  2672  
  2673  func Entryvalue(ctxt *Link) int64 {
  2674  	a := *flagEntrySymbol
  2675  	if a[0] >= '0' && a[0] <= '9' {
  2676  		return atolwhex(a)
  2677  	}
  2678  	ldr := ctxt.loader
  2679  	s := ldr.Lookup(a, 0)
  2680  	if s == 0 {
  2681  		Errorf(nil, "missing entry symbol %q", a)
  2682  		return 0
  2683  	}
  2684  	st := ldr.SymType(s)
  2685  	if st == 0 {
  2686  		return *FlagTextAddr
  2687  	}
  2688  	if !ctxt.IsAIX() && st != sym.STEXT {
  2689  		ldr.Errorf(s, "entry not text")
  2690  	}
  2691  	return ldr.SymValue(s)
  2692  }
  2693  
  2694  func (ctxt *Link) callgraph() {
  2695  	if !*FlagC {
  2696  		return
  2697  	}
  2698  
  2699  	ldr := ctxt.loader
  2700  	for _, s := range ctxt.Textp {
  2701  		relocs := ldr.Relocs(s)
  2702  		for i := 0; i < relocs.Count(); i++ {
  2703  			r := relocs.At(i)
  2704  			rs := r.Sym()
  2705  			if rs == 0 {
  2706  				continue
  2707  			}
  2708  			if r.Type().IsDirectCall() && ldr.SymType(rs) == sym.STEXT {
  2709  				ctxt.Logf("%s calls %s\n", ldr.SymName(s), ldr.SymName(rs))
  2710  			}
  2711  		}
  2712  	}
  2713  }
  2714  
  2715  func Rnd(v int64, r int64) int64 {
  2716  	if r <= 0 {
  2717  		return v
  2718  	}
  2719  	v += r - 1
  2720  	c := v % r
  2721  	if c < 0 {
  2722  		c += r
  2723  	}
  2724  	v -= c
  2725  	return v
  2726  }
  2727  
  2728  func bgetc(r *bio.Reader) int {
  2729  	c, err := r.ReadByte()
  2730  	if err != nil {
  2731  		if err != io.EOF {
  2732  			log.Fatalf("reading input: %v", err)
  2733  		}
  2734  		return -1
  2735  	}
  2736  	return int(c)
  2737  }
  2738  
  2739  type markKind uint8 // for postorder traversal
  2740  const (
  2741  	_ markKind = iota
  2742  	visiting
  2743  	visited
  2744  )
  2745  
  2746  func postorder(libs []*sym.Library) []*sym.Library {
  2747  	order := make([]*sym.Library, 0, len(libs)) // hold the result
  2748  	mark := make(map[*sym.Library]markKind, len(libs))
  2749  	for _, lib := range libs {
  2750  		dfs(lib, mark, &order)
  2751  	}
  2752  	return order
  2753  }
  2754  
  2755  func dfs(lib *sym.Library, mark map[*sym.Library]markKind, order *[]*sym.Library) {
  2756  	if mark[lib] == visited {
  2757  		return
  2758  	}
  2759  	if mark[lib] == visiting {
  2760  		panic("found import cycle while visiting " + lib.Pkg)
  2761  	}
  2762  	mark[lib] = visiting
  2763  	for _, i := range lib.Imports {
  2764  		dfs(i, mark, order)
  2765  	}
  2766  	mark[lib] = visited
  2767  	*order = append(*order, lib)
  2768  }
  2769  
  2770  func ElfSymForReloc(ctxt *Link, s loader.Sym) int32 {
  2771  	// If putelfsym created a local version of this symbol, use that in all
  2772  	// relocations.
  2773  	les := ctxt.loader.SymLocalElfSym(s)
  2774  	if les != 0 {
  2775  		return les
  2776  	} else {
  2777  		return ctxt.loader.SymElfSym(s)
  2778  	}
  2779  }
  2780  
  2781  func AddGotSym(target *Target, ldr *loader.Loader, syms *ArchSyms, s loader.Sym, elfRelocTyp uint32) {
  2782  	if ldr.SymGot(s) >= 0 {
  2783  		return
  2784  	}
  2785  
  2786  	Adddynsym(ldr, target, syms, s)
  2787  	got := ldr.MakeSymbolUpdater(syms.GOT)
  2788  	ldr.SetGot(s, int32(got.Size()))
  2789  	got.AddUint(target.Arch, 0)
  2790  
  2791  	if target.IsElf() {
  2792  		if target.Arch.PtrSize == 8 {
  2793  			rela := ldr.MakeSymbolUpdater(syms.Rela)
  2794  			rela.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
  2795  			rela.AddUint64(target.Arch, elf.R_INFO(uint32(ldr.SymDynid(s)), elfRelocTyp))
  2796  			rela.AddUint64(target.Arch, 0)
  2797  		} else {
  2798  			rel := ldr.MakeSymbolUpdater(syms.Rel)
  2799  			rel.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
  2800  			rel.AddUint32(target.Arch, elf.R_INFO32(uint32(ldr.SymDynid(s)), elfRelocTyp))
  2801  		}
  2802  	} else if target.IsDarwin() {
  2803  		leg := ldr.MakeSymbolUpdater(syms.LinkEditGOT)
  2804  		leg.AddUint32(target.Arch, uint32(ldr.SymDynid(s)))
  2805  		if target.IsPIE() && target.IsInternal() {
  2806  			// Mach-O relocations are a royal pain to lay out.
  2807  			// They use a compact stateful bytecode representation.
  2808  			// Here we record what are needed and encode them later.
  2809  			MachoAddBind(int64(ldr.SymGot(s)), s)
  2810  		}
  2811  	} else {
  2812  		ldr.Errorf(s, "addgotsym: unsupported binary format")
  2813  	}
  2814  }
  2815  
  2816  var hostobjcounter int
  2817  
  2818  // captureHostObj writes out the content of a host object (pulled from
  2819  // an archive or loaded from a *.o file directly) to a directory
  2820  // specified via the linker's "-capturehostobjs" debugging flag. This
  2821  // is intended to make it easier for a developer to inspect the actual
  2822  // object feeding into "CGO internal" link step.
  2823  func captureHostObj(h *Hostobj) {
  2824  	// Form paths for info file and obj file.
  2825  	ofile := fmt.Sprintf("captured-obj-%d.o", hostobjcounter)
  2826  	ifile := fmt.Sprintf("captured-obj-%d.txt", hostobjcounter)
  2827  	hostobjcounter++
  2828  	opath := filepath.Join(*flagCaptureHostObjs, ofile)
  2829  	ipath := filepath.Join(*flagCaptureHostObjs, ifile)
  2830  
  2831  	// Write the info file.
  2832  	info := fmt.Sprintf("pkg: %s\npn: %s\nfile: %s\noff: %d\nlen: %d\n",
  2833  		h.pkg, h.pn, h.file, h.off, h.length)
  2834  	if err := os.WriteFile(ipath, []byte(info), 0666); err != nil {
  2835  		log.Fatalf("error writing captured host obj info %s: %v", ipath, err)
  2836  	}
  2837  
  2838  	readObjData := func() []byte {
  2839  		inf, err := os.Open(h.file)
  2840  		if err != nil {
  2841  			log.Fatalf("capturing host obj: open failed on %s: %v", h.pn, err)
  2842  		}
  2843  		res := make([]byte, h.length)
  2844  		if n, err := inf.ReadAt(res, h.off); err != nil || n != int(h.length) {
  2845  			log.Fatalf("capturing host obj: readat failed on %s: %v", h.pn, err)
  2846  		}
  2847  		return res
  2848  	}
  2849  
  2850  	// Write the object file.
  2851  	if err := os.WriteFile(opath, readObjData(), 0666); err != nil {
  2852  		log.Fatalf("error writing captured host object %s: %v", opath, err)
  2853  	}
  2854  
  2855  	fmt.Fprintf(os.Stderr, "link: info: captured host object %s to %s\n",
  2856  		h.file, opath)
  2857  }