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

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

View as plain text