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

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

View as plain text