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

View as plain text