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

View as plain text