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

View as plain text