Source file src/cmd/link/internal/ld/lib.go

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

View as plain text