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  	// In all cases way we mark the moduledata as noptrdata to hide it from
   927  	// the GC.
   928  	mdsb.SetType(sym.SNOPTRDATA)
   929  	ctxt.loader.SetAttrReachable(moduledata, true)
   930  	ctxt.Moduledata = moduledata
   931  
   932  	if ctxt.Arch == sys.Arch386 && ctxt.HeadType != objabi.Hwindows {
   933  		if (ctxt.BuildMode == BuildModeCArchive && ctxt.IsELF) || ctxt.BuildMode == BuildModeCShared || ctxt.BuildMode == BuildModePIE || ctxt.DynlinkingGo() {
   934  			got := ctxt.loader.LookupOrCreateSym("_GLOBAL_OFFSET_TABLE_", 0)
   935  			sb := ctxt.loader.MakeSymbolUpdater(got)
   936  			sb.SetType(sym.SDYNIMPORT)
   937  			ctxt.loader.SetAttrReachable(got, true)
   938  		}
   939  	}
   940  
   941  	// DWARF-gen and other phases require that the unit Textp slices
   942  	// be populated, so that it can walk the functions in each unit.
   943  	// Call into the loader to do this (requires that we collect the
   944  	// set of internal libraries first). NB: might be simpler if we
   945  	// moved isRuntimeDepPkg to cmd/internal and then did the test in
   946  	// loader.AssignTextSymbolOrder.
   947  	ctxt.Library = postorder(ctxt.Library)
   948  	intlibs := []bool{}
   949  	for _, lib := range ctxt.Library {
   950  		intlibs = append(intlibs, isRuntimeDepPkg(lib.Pkg))
   951  	}
   952  	ctxt.Textp = ctxt.loader.AssignTextSymbolOrder(ctxt.Library, intlibs, ctxt.Textp)
   953  }
   954  
   955  // mangleTypeSym shortens the names of symbols that represent Go types
   956  // if they are visible in the symbol table.
   957  //
   958  // As the names of these symbols are derived from the string of
   959  // the type, they can run to many kilobytes long. So we shorten
   960  // them using a SHA-1 when the name appears in the final binary.
   961  // This also removes characters that upset external linkers.
   962  //
   963  // These are the symbols that begin with the prefix 'type.' and
   964  // contain run-time type information used by the runtime and reflect
   965  // packages. All Go binaries contain these symbols, but only
   966  // those programs loaded dynamically in multiple parts need these
   967  // symbols to have entries in the symbol table.
   968  func (ctxt *Link) mangleTypeSym() {
   969  	if ctxt.BuildMode != BuildModeShared && !ctxt.linkShared && ctxt.BuildMode != BuildModePlugin && !ctxt.CanUsePlugins() {
   970  		return
   971  	}
   972  
   973  	ldr := ctxt.loader
   974  	for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
   975  		if !ldr.AttrReachable(s) && !ctxt.linkShared {
   976  			// If -linkshared, the gc mask generation code may need to reach
   977  			// out to the shared library for the type descriptor's data, even
   978  			// the type descriptor itself is not actually needed at run time
   979  			// (therefore not reachable). We still need to mangle its name,
   980  			// so it is consistent with the one stored in the shared library.
   981  			continue
   982  		}
   983  		name := ldr.SymName(s)
   984  		newName := typeSymbolMangle(name)
   985  		if newName != name {
   986  			ldr.SetSymExtname(s, newName)
   987  
   988  			// When linking against a shared library, the Go object file may
   989  			// have reference to the original symbol name whereas the shared
   990  			// library provides a symbol with the mangled name. We need to
   991  			// copy the payload of mangled to original.
   992  			// XXX maybe there is a better way to do this.
   993  			dup := ldr.Lookup(newName, ldr.SymVersion(s))
   994  			if dup != 0 {
   995  				st := ldr.SymType(s)
   996  				dt := ldr.SymType(dup)
   997  				if st == sym.Sxxx && dt != sym.Sxxx {
   998  					ldr.CopySym(dup, s)
   999  				}
  1000  			}
  1001  		}
  1002  	}
  1003  }
  1004  
  1005  // typeSymbolMangle mangles the given symbol name into something shorter.
  1006  //
  1007  // Keep the type:. prefix, which parts of the linker (like the
  1008  // DWARF generator) know means the symbol is not decodable.
  1009  // Leave type:runtime. symbols alone, because other parts of
  1010  // the linker manipulates them.
  1011  func typeSymbolMangle(name string) string {
  1012  	isType := strings.HasPrefix(name, "type:")
  1013  	if !isType && !strings.Contains(name, "@") {
  1014  		// Issue 58800: instantiated symbols may include a type name, which may contain "@"
  1015  		return name
  1016  	}
  1017  	if strings.HasPrefix(name, "type:runtime.") {
  1018  		return name
  1019  	}
  1020  	if strings.HasPrefix(name, "go:string.") {
  1021  		// String symbols will be grouped to a single go:string.* symbol.
  1022  		// No need to mangle individual symbol names.
  1023  		return name
  1024  	}
  1025  	if len(name) <= 14 && !strings.Contains(name, "@") { // Issue 19529
  1026  		return name
  1027  	}
  1028  	if isType {
  1029  		hb := hash.Sum32([]byte(name[5:]))
  1030  		prefix := "type:"
  1031  		if name[5] == '.' {
  1032  			prefix = "type:."
  1033  		}
  1034  		return prefix + base64.StdEncoding.EncodeToString(hb[:6])
  1035  	}
  1036  	// instantiated symbol, replace type name in []
  1037  	i := strings.IndexByte(name, '[')
  1038  	j := strings.LastIndexByte(name, ']')
  1039  	if j == -1 || j <= i {
  1040  		j = len(name)
  1041  	}
  1042  	hb := hash.Sum32([]byte(name[i+1 : j]))
  1043  	return name[:i+1] + base64.StdEncoding.EncodeToString(hb[:6]) + name[j:]
  1044  }
  1045  
  1046  /*
  1047   * look for the next file in an archive.
  1048   * adapted from libmach.
  1049   */
  1050  func nextar(bp *bio.Reader, off int64, a *ArHdr) int64 {
  1051  	if off&1 != 0 {
  1052  		off++
  1053  	}
  1054  	bp.MustSeek(off, 0)
  1055  	var buf [SAR_HDR]byte
  1056  	if n, err := io.ReadFull(bp, buf[:]); err != nil {
  1057  		if n == 0 && err != io.EOF {
  1058  			return -1
  1059  		}
  1060  		return 0
  1061  	}
  1062  
  1063  	a.name = artrim(buf[0:16])
  1064  	a.date = artrim(buf[16:28])
  1065  	a.uid = artrim(buf[28:34])
  1066  	a.gid = artrim(buf[34:40])
  1067  	a.mode = artrim(buf[40:48])
  1068  	a.size = artrim(buf[48:58])
  1069  	a.fmag = artrim(buf[58:60])
  1070  
  1071  	arsize := atolwhex(a.size)
  1072  	if arsize&1 != 0 {
  1073  		arsize++
  1074  	}
  1075  	return arsize + SAR_HDR
  1076  }
  1077  
  1078  func loadobjfile(ctxt *Link, lib *sym.Library) {
  1079  	pkg := objabi.PathToPrefix(lib.Pkg)
  1080  
  1081  	if ctxt.Debugvlog > 1 {
  1082  		ctxt.Logf("ldobj: %s (%s)\n", lib.File, pkg)
  1083  	}
  1084  	f, err := bio.Open(lib.File)
  1085  	if err != nil {
  1086  		Exitf("cannot open file %s: %v", lib.File, err)
  1087  	}
  1088  	defer f.Close()
  1089  	defer func() {
  1090  		if pkg == "main" && !lib.Main {
  1091  			Exitf("%s: not package main", lib.File)
  1092  		}
  1093  	}()
  1094  
  1095  	for i := 0; i < len(ARMAG); i++ {
  1096  		if c, err := f.ReadByte(); err == nil && c == ARMAG[i] {
  1097  			continue
  1098  		}
  1099  
  1100  		/* load it as a regular file */
  1101  		l := f.MustSeek(0, 2)
  1102  		f.MustSeek(0, 0)
  1103  		ldobj(ctxt, f, lib, l, lib.File, lib.File)
  1104  		return
  1105  	}
  1106  
  1107  	/*
  1108  	 * load all the object files from the archive now.
  1109  	 * this gives us sequential file access and keeps us
  1110  	 * from needing to come back later to pick up more
  1111  	 * objects.  it breaks the usual C archive model, but
  1112  	 * this is Go, not C.  the common case in Go is that
  1113  	 * we need to load all the objects, and then we throw away
  1114  	 * the individual symbols that are unused.
  1115  	 *
  1116  	 * loading every object will also make it possible to
  1117  	 * load foreign objects not referenced by __.PKGDEF.
  1118  	 */
  1119  	var arhdr ArHdr
  1120  	off := f.Offset()
  1121  	for {
  1122  		l := nextar(f, off, &arhdr)
  1123  		if l == 0 {
  1124  			break
  1125  		}
  1126  		if l < 0 {
  1127  			Exitf("%s: malformed archive", lib.File)
  1128  		}
  1129  		off += l
  1130  
  1131  		// __.PKGDEF isn't a real Go object file, and it's
  1132  		// absent in -linkobj builds anyway. Skipping it
  1133  		// ensures consistency between -linkobj and normal
  1134  		// build modes.
  1135  		if arhdr.name == pkgdef {
  1136  			continue
  1137  		}
  1138  
  1139  		if arhdr.name == "dynimportfail" {
  1140  			dynimportfail = append(dynimportfail, lib.Pkg)
  1141  		}
  1142  		if arhdr.name == "preferlinkext" {
  1143  			// Ignore this directive if -linkmode has been
  1144  			// set explicitly.
  1145  			if ctxt.LinkMode == LinkAuto {
  1146  				preferlinkext = append(preferlinkext, lib.Pkg)
  1147  			}
  1148  		}
  1149  
  1150  		// Skip other special (non-object-file) sections that
  1151  		// build tools may have added. Such sections must have
  1152  		// short names so that the suffix is not truncated.
  1153  		if len(arhdr.name) < 16 {
  1154  			if ext := filepath.Ext(arhdr.name); ext != ".o" && ext != ".syso" {
  1155  				continue
  1156  			}
  1157  		}
  1158  
  1159  		pname := fmt.Sprintf("%s(%s)", lib.File, arhdr.name)
  1160  		l = atolwhex(arhdr.size)
  1161  		ldobj(ctxt, f, lib, l, pname, lib.File)
  1162  	}
  1163  }
  1164  
  1165  type Hostobj struct {
  1166  	ld     func(*Link, *bio.Reader, string, int64, string)
  1167  	pkg    string
  1168  	pn     string
  1169  	file   string
  1170  	off    int64
  1171  	length int64
  1172  }
  1173  
  1174  var hostobj []Hostobj
  1175  
  1176  // These packages can use internal linking mode.
  1177  // Others trigger external mode.
  1178  var internalpkg = []string{
  1179  	"crypto/internal/boring",
  1180  	"crypto/internal/boring/syso",
  1181  	"crypto/x509",
  1182  	"net",
  1183  	"os/user",
  1184  	"runtime/cgo",
  1185  	"runtime/race",
  1186  	"runtime/race/internal/amd64v1",
  1187  	"runtime/race/internal/amd64v3",
  1188  	"runtime/msan",
  1189  	"runtime/asan",
  1190  }
  1191  
  1192  func ldhostobj(ld func(*Link, *bio.Reader, string, int64, string), headType objabi.HeadType, f *bio.Reader, pkg string, length int64, pn string, file string) *Hostobj {
  1193  	isinternal := false
  1194  	for _, intpkg := range internalpkg {
  1195  		if pkg == intpkg {
  1196  			isinternal = true
  1197  			break
  1198  		}
  1199  	}
  1200  
  1201  	// DragonFly declares errno with __thread, which results in a symbol
  1202  	// type of R_386_TLS_GD or R_X86_64_TLSGD. The Go linker does not
  1203  	// currently know how to handle TLS relocations, hence we have to
  1204  	// force external linking for any libraries that link in code that
  1205  	// uses errno. This can be removed if the Go linker ever supports
  1206  	// these relocation types.
  1207  	if headType == objabi.Hdragonfly {
  1208  		if pkg == "net" || pkg == "os/user" {
  1209  			isinternal = false
  1210  		}
  1211  	}
  1212  
  1213  	if !isinternal {
  1214  		externalobj = true
  1215  	}
  1216  
  1217  	hostobj = append(hostobj, Hostobj{})
  1218  	h := &hostobj[len(hostobj)-1]
  1219  	h.ld = ld
  1220  	h.pkg = pkg
  1221  	h.pn = pn
  1222  	h.file = file
  1223  	h.off = f.Offset()
  1224  	h.length = length
  1225  	return h
  1226  }
  1227  
  1228  func hostobjs(ctxt *Link) {
  1229  	if ctxt.LinkMode != LinkInternal {
  1230  		return
  1231  	}
  1232  	var h *Hostobj
  1233  
  1234  	for i := 0; i < len(hostobj); i++ {
  1235  		h = &hostobj[i]
  1236  		f, err := bio.Open(h.file)
  1237  		if err != nil {
  1238  			Exitf("cannot reopen %s: %v", h.pn, err)
  1239  		}
  1240  		f.MustSeek(h.off, 0)
  1241  		if h.ld == nil {
  1242  			Errorf("%s: unrecognized object file format", h.pn)
  1243  			continue
  1244  		}
  1245  		h.ld(ctxt, f, h.pkg, h.length, h.pn)
  1246  		if *flagCaptureHostObjs != "" {
  1247  			captureHostObj(h)
  1248  		}
  1249  		f.Close()
  1250  	}
  1251  }
  1252  
  1253  func hostlinksetup(ctxt *Link) {
  1254  	if ctxt.LinkMode != LinkExternal {
  1255  		return
  1256  	}
  1257  
  1258  	// For external link, record that we need to tell the external linker -s,
  1259  	// and turn off -s internally: the external linker needs the symbol
  1260  	// information for its final link.
  1261  	debug_s = *FlagS
  1262  	*FlagS = false
  1263  
  1264  	// create temporary directory and arrange cleanup
  1265  	if *flagTmpdir == "" {
  1266  		dir, err := os.MkdirTemp("", "go-link-")
  1267  		if err != nil {
  1268  			log.Fatal(err)
  1269  		}
  1270  		*flagTmpdir = dir
  1271  		ownTmpDir = true
  1272  		AtExit(func() {
  1273  			os.RemoveAll(*flagTmpdir)
  1274  		})
  1275  	}
  1276  
  1277  	// change our output to temporary object file
  1278  	if err := ctxt.Out.Close(); err != nil {
  1279  		Exitf("error closing output file")
  1280  	}
  1281  	mayberemoveoutfile()
  1282  
  1283  	p := filepath.Join(*flagTmpdir, "go.o")
  1284  	if err := ctxt.Out.Open(p); err != nil {
  1285  		Exitf("cannot create %s: %v", p, err)
  1286  	}
  1287  }
  1288  
  1289  // cleanTimeStamps resets the timestamps for the specified list of
  1290  // existing files to the Unix epoch (1970-01-01 00:00:00 +0000 UTC).
  1291  // We take this step in order to help preserve reproducible builds;
  1292  // this seems to be primarily needed for external linking on Darwin
  1293  // with later versions of xcode, which (unfortunately) seem to want to
  1294  // incorporate object file times into the final output file's build
  1295  // ID. See issue 64947 for the unpleasant details.
  1296  func cleanTimeStamps(files []string) {
  1297  	epocht := time.Unix(0, 0)
  1298  	for _, f := range files {
  1299  		if err := os.Chtimes(f, epocht, epocht); err != nil {
  1300  			Exitf("cannot chtimes %s: %v", f, err)
  1301  		}
  1302  	}
  1303  }
  1304  
  1305  // hostobjCopy creates a copy of the object files in hostobj in a
  1306  // temporary directory.
  1307  func (ctxt *Link) hostobjCopy() (paths []string) {
  1308  	var wg sync.WaitGroup
  1309  	sema := make(chan struct{}, runtime.NumCPU()) // limit open file descriptors
  1310  	for i, h := range hostobj {
  1311  		h := h
  1312  		dst := filepath.Join(*flagTmpdir, fmt.Sprintf("%06d.o", i))
  1313  		paths = append(paths, dst)
  1314  		if ctxt.Debugvlog != 0 {
  1315  			ctxt.Logf("host obj copy: %s from pkg %s -> %s\n", h.pn, h.pkg, dst)
  1316  		}
  1317  
  1318  		wg.Add(1)
  1319  		go func() {
  1320  			sema <- struct{}{}
  1321  			defer func() {
  1322  				<-sema
  1323  				wg.Done()
  1324  			}()
  1325  			f, err := os.Open(h.file)
  1326  			if err != nil {
  1327  				Exitf("cannot reopen %s: %v", h.pn, err)
  1328  			}
  1329  			defer f.Close()
  1330  			if _, err := f.Seek(h.off, 0); err != nil {
  1331  				Exitf("cannot seek %s: %v", h.pn, err)
  1332  			}
  1333  
  1334  			w, err := os.Create(dst)
  1335  			if err != nil {
  1336  				Exitf("cannot create %s: %v", dst, err)
  1337  			}
  1338  			if _, err := io.CopyN(w, f, h.length); err != nil {
  1339  				Exitf("cannot write %s: %v", dst, err)
  1340  			}
  1341  			if err := w.Close(); err != nil {
  1342  				Exitf("cannot close %s: %v", dst, err)
  1343  			}
  1344  		}()
  1345  	}
  1346  	wg.Wait()
  1347  	return paths
  1348  }
  1349  
  1350  // writeGDBLinkerScript creates gcc linker script file in temp
  1351  // directory. writeGDBLinkerScript returns created file path.
  1352  // The script is used to work around gcc bug
  1353  // (see https://golang.org/issue/20183 for details).
  1354  func writeGDBLinkerScript() string {
  1355  	name := "fix_debug_gdb_scripts.ld"
  1356  	path := filepath.Join(*flagTmpdir, name)
  1357  	src := `SECTIONS
  1358  {
  1359    .debug_gdb_scripts BLOCK(__section_alignment__) (NOLOAD) :
  1360    {
  1361      *(.debug_gdb_scripts)
  1362    }
  1363  }
  1364  INSERT AFTER .debug_types;
  1365  `
  1366  	err := os.WriteFile(path, []byte(src), 0666)
  1367  	if err != nil {
  1368  		Errorf("WriteFile %s failed: %v", name, err)
  1369  	}
  1370  	return path
  1371  }
  1372  
  1373  type machoUpdateFunc func(ctxt *Link, exef *os.File, exem *macho.File, outexe string) error
  1374  
  1375  // archive builds a .a archive from the hostobj object files.
  1376  func (ctxt *Link) archive() {
  1377  	if ctxt.BuildMode != BuildModeCArchive {
  1378  		return
  1379  	}
  1380  
  1381  	exitIfErrors()
  1382  
  1383  	if *flagExtar == "" {
  1384  		const printProgName = "--print-prog-name=ar"
  1385  		cc := ctxt.extld()
  1386  		*flagExtar = "ar"
  1387  		if linkerFlagSupported(ctxt.Arch, cc[0], "", printProgName) {
  1388  			*flagExtar = ctxt.findExtLinkTool("ar")
  1389  		}
  1390  	}
  1391  
  1392  	mayberemoveoutfile()
  1393  
  1394  	// Force the buffer to flush here so that external
  1395  	// tools will see a complete file.
  1396  	if err := ctxt.Out.Close(); err != nil {
  1397  		Exitf("error closing %v", *flagOutfile)
  1398  	}
  1399  
  1400  	argv := []string{*flagExtar, "-q", "-c", "-s"}
  1401  	if ctxt.HeadType == objabi.Haix {
  1402  		argv = append(argv, "-X64")
  1403  	}
  1404  	godotopath := filepath.Join(*flagTmpdir, "go.o")
  1405  	cleanTimeStamps([]string{godotopath})
  1406  	hostObjCopyPaths := ctxt.hostobjCopy()
  1407  	cleanTimeStamps(hostObjCopyPaths)
  1408  
  1409  	argv = append(argv, *flagOutfile)
  1410  	argv = append(argv, godotopath)
  1411  	argv = append(argv, hostObjCopyPaths...)
  1412  
  1413  	if ctxt.Debugvlog != 0 {
  1414  		ctxt.Logf("archive: %s\n", strings.Join(argv, " "))
  1415  	}
  1416  
  1417  	// If supported, use syscall.Exec() to invoke the archive command,
  1418  	// which should be the final remaining step needed for the link.
  1419  	// This will reduce peak RSS for the link (and speed up linking of
  1420  	// large applications), since when the archive command runs we
  1421  	// won't be holding onto all of the linker's live memory.
  1422  	if syscallExecSupported && !ownTmpDir {
  1423  		runAtExitFuncs()
  1424  		ctxt.execArchive(argv)
  1425  		panic("should not get here")
  1426  	}
  1427  
  1428  	// Otherwise invoke 'ar' in the usual way (fork + exec).
  1429  	if out, err := exec.Command(argv[0], argv[1:]...).CombinedOutput(); err != nil {
  1430  		Exitf("running %s failed: %v\n%s", argv[0], err, out)
  1431  	}
  1432  }
  1433  
  1434  func (ctxt *Link) hostlink() {
  1435  	if ctxt.LinkMode != LinkExternal || nerrors > 0 {
  1436  		return
  1437  	}
  1438  	if ctxt.BuildMode == BuildModeCArchive {
  1439  		return
  1440  	}
  1441  
  1442  	var argv []string
  1443  	argv = append(argv, ctxt.extld()...)
  1444  	argv = append(argv, hostlinkArchArgs(ctxt.Arch)...)
  1445  
  1446  	if *FlagS || debug_s {
  1447  		if ctxt.HeadType == objabi.Hdarwin {
  1448  			// Recent versions of macOS print
  1449  			//	ld: warning: option -s is obsolete and being ignored
  1450  			// so do not pass any arguments (but we strip symbols below).
  1451  		} else {
  1452  			argv = append(argv, "-s")
  1453  		}
  1454  	}
  1455  
  1456  	// On darwin, whether to combine DWARF into executable.
  1457  	// Only macOS supports unmapped segments such as our __DWARF segment.
  1458  	combineDwarf := ctxt.IsDarwin() && !*FlagW && machoPlatform == PLATFORM_MACOS
  1459  
  1460  	var isMSVC bool // used on Windows
  1461  	wlPrefix := "-Wl,--"
  1462  
  1463  	switch ctxt.HeadType {
  1464  	case objabi.Hdarwin:
  1465  		if combineDwarf {
  1466  			// Leave room for DWARF combining.
  1467  			// -headerpad is incompatible with -fembed-bitcode.
  1468  			argv = append(argv, "-Wl,-headerpad,1144")
  1469  		}
  1470  		if ctxt.DynlinkingGo() && buildcfg.GOOS != "ios" {
  1471  			// -flat_namespace is deprecated on iOS.
  1472  			// It is useful for supporting plugins. We don't support plugins on iOS.
  1473  			// -flat_namespace may cause the dynamic linker to hang at forkExec when
  1474  			// resolving a lazy binding. See issue 38824.
  1475  			// Force eager resolution to work around.
  1476  			argv = append(argv, "-Wl,-flat_namespace", "-Wl,-bind_at_load")
  1477  		}
  1478  		if !combineDwarf {
  1479  			argv = append(argv, "-Wl,-S") // suppress STAB (symbolic debugging) symbols
  1480  			if debug_s {
  1481  				// We are generating a binary with symbol table suppressed.
  1482  				// Suppress local symbols. We need to keep dynamically exported
  1483  				// and referenced symbols so the dynamic linker can resolve them.
  1484  				argv = append(argv, "-Wl,-x")
  1485  			}
  1486  		}
  1487  		if *flagHostBuildid == "none" {
  1488  			argv = append(argv, "-Wl,-no_uuid")
  1489  		}
  1490  	case objabi.Hopenbsd:
  1491  		argv = append(argv, "-pthread")
  1492  		if ctxt.BuildMode != BuildModePIE {
  1493  			argv = append(argv, "-Wl,-nopie")
  1494  		}
  1495  		if linkerFlagSupported(ctxt.Arch, argv[0], "", "-Wl,-z,nobtcfi") {
  1496  			// -Wl,-z,nobtcfi is only supported on OpenBSD 7.4+, remove guard
  1497  			// when OpenBSD 7.5 is released and 7.3 is no longer supported.
  1498  			argv = append(argv, "-Wl,-z,nobtcfi")
  1499  		}
  1500  		if ctxt.Arch.InFamily(sys.ARM64) {
  1501  			// Disable execute-only on openbsd/arm64 - the Go arm64 assembler
  1502  			// currently stores constants in the text section rather than in rodata.
  1503  			// See issue #59615.
  1504  			argv = append(argv, "-Wl,--no-execute-only")
  1505  		}
  1506  	case objabi.Hwindows:
  1507  		isMSVC = ctxt.isMSVC()
  1508  		if isMSVC {
  1509  			// For various options, MSVC lld-link only accepts one dash.
  1510  			// TODO: It seems mingw clang supports one or two dashes,
  1511  			// maybe we can always use one dash,  but I'm not sure about
  1512  			// legacy compilers that currently work.
  1513  			wlPrefix = "-Wl,-"
  1514  		}
  1515  
  1516  		if windowsgui {
  1517  			argv = append(argv, "-mwindows")
  1518  		} else {
  1519  			argv = append(argv, "-mconsole")
  1520  		}
  1521  		// Mark as having awareness of terminal services, to avoid
  1522  		// ancient compatibility hacks.
  1523  
  1524  		argv = append(argv, wlPrefix+"tsaware")
  1525  
  1526  		// Enable DEP
  1527  		argv = append(argv, wlPrefix+"nxcompat")
  1528  
  1529  		if !isMSVC {
  1530  			argv = append(argv, fmt.Sprintf("-Wl,--major-os-version=%d", PeMinimumTargetMajorVersion))
  1531  			argv = append(argv, fmt.Sprintf("-Wl,--minor-os-version=%d", PeMinimumTargetMinorVersion))
  1532  			argv = append(argv, fmt.Sprintf("-Wl,--major-subsystem-version=%d", PeMinimumTargetMajorVersion))
  1533  			argv = append(argv, fmt.Sprintf("-Wl,--minor-subsystem-version=%d", PeMinimumTargetMinorVersion))
  1534  		}
  1535  	case objabi.Haix:
  1536  		argv = append(argv, "-pthread")
  1537  		// prevent ld to reorder .text functions to keep the same
  1538  		// first/last functions for moduledata.
  1539  		argv = append(argv, "-Wl,-bnoobjreorder")
  1540  		// mcmodel=large is needed for every gcc generated files, but
  1541  		// ld still need -bbigtoc in order to allow larger TOC.
  1542  		argv = append(argv, "-mcmodel=large")
  1543  		argv = append(argv, "-Wl,-bbigtoc")
  1544  	}
  1545  
  1546  	// On PPC64, verify the external toolchain supports Power10. This is needed when
  1547  	// PC relative relocations might be generated by Go. Only targets compiling ELF
  1548  	// binaries might generate these relocations.
  1549  	if ctxt.IsPPC64() && ctxt.IsElf() && buildcfg.GOPPC64 >= 10 {
  1550  		if !linkerFlagSupported(ctxt.Arch, argv[0], "", "-mcpu=power10") {
  1551  			Exitf("The external toolchain does not support -mcpu=power10. " +
  1552  				" This is required to externally link GOPPC64 >= power10")
  1553  		}
  1554  	}
  1555  
  1556  	// Enable/disable ASLR on Windows.
  1557  	addASLRargs := func(argv []string, val bool) []string {
  1558  		// Old/ancient versions of GCC support "--dynamicbase" and
  1559  		// "--high-entropy-va" but don't enable it by default. In
  1560  		// addition, they don't accept "--disable-dynamicbase" or
  1561  		// "--no-dynamicbase", so the only way to disable ASLR is to
  1562  		// not pass any flags at all.
  1563  		//
  1564  		// More modern versions of GCC (and also clang) enable ASLR
  1565  		// by default. With these compilers, however you can turn it
  1566  		// off if you want using "--disable-dynamicbase" or
  1567  		// "--no-dynamicbase".
  1568  		//
  1569  		// The strategy below is to try using "--disable-dynamicbase";
  1570  		// if this succeeds, then assume we're working with more
  1571  		// modern compilers and act accordingly. If it fails, assume
  1572  		// an ancient compiler with ancient defaults.
  1573  		var dbopt string
  1574  		var heopt string
  1575  		dbon := wlPrefix + "dynamicbase"
  1576  		heon := wlPrefix + "high-entropy-va"
  1577  		dboff := wlPrefix + "disable-dynamicbase"
  1578  		heoff := wlPrefix + "disable-high-entropy-va"
  1579  		if isMSVC {
  1580  			heon = wlPrefix + "highentropyva"
  1581  			heoff = wlPrefix + "highentropyva:no"
  1582  			dboff = wlPrefix + "dynamicbase:no"
  1583  		}
  1584  		if val {
  1585  			dbopt = dbon
  1586  			heopt = heon
  1587  		} else {
  1588  			// Test to see whether "--disable-dynamicbase" works.
  1589  			newer := linkerFlagSupported(ctxt.Arch, argv[0], "", dboff)
  1590  			if newer {
  1591  				// Newer compiler, which supports both on/off options.
  1592  				dbopt = dboff
  1593  				heopt = heoff
  1594  			} else {
  1595  				// older toolchain: we have to say nothing in order to
  1596  				// get a no-ASLR binary.
  1597  				dbopt = ""
  1598  				heopt = ""
  1599  			}
  1600  		}
  1601  		if dbopt != "" {
  1602  			argv = append(argv, dbopt)
  1603  		}
  1604  		// enable high-entropy ASLR on 64-bit.
  1605  		if ctxt.Arch.PtrSize >= 8 && heopt != "" {
  1606  			argv = append(argv, heopt)
  1607  		}
  1608  		return argv
  1609  	}
  1610  
  1611  	switch ctxt.BuildMode {
  1612  	case BuildModeExe:
  1613  		if ctxt.HeadType == objabi.Hdarwin {
  1614  			if machoPlatform == PLATFORM_MACOS && ctxt.IsAMD64() {
  1615  				argv = append(argv, "-Wl,-no_pie")
  1616  			}
  1617  		}
  1618  		if *flagRace && ctxt.HeadType == objabi.Hwindows {
  1619  			// Current windows/amd64 race detector tsan support
  1620  			// library can't handle PIE mode (see #53539 for more details).
  1621  			// For now, explicitly disable PIE (since some compilers
  1622  			// default to it) if -race is in effect.
  1623  			argv = addASLRargs(argv, false)
  1624  		}
  1625  	case BuildModePIE:
  1626  		switch ctxt.HeadType {
  1627  		case objabi.Hdarwin, objabi.Haix:
  1628  		case objabi.Hwindows:
  1629  			if *flagAslr && *flagRace {
  1630  				// Current windows/amd64 race detector tsan support
  1631  				// library can't handle PIE mode (see #53539 for more details).
  1632  				// Disable alsr if -race in effect.
  1633  				*flagAslr = false
  1634  			}
  1635  			argv = addASLRargs(argv, *flagAslr)
  1636  		default:
  1637  			// ELF.
  1638  			if ctxt.UseRelro() {
  1639  				argv = append(argv, "-Wl,-z,relro")
  1640  			}
  1641  			argv = append(argv, "-pie")
  1642  		}
  1643  	case BuildModeCShared:
  1644  		if ctxt.HeadType == objabi.Hdarwin {
  1645  			argv = append(argv, "-dynamiclib")
  1646  		} else {
  1647  			if ctxt.UseRelro() {
  1648  				argv = append(argv, "-Wl,-z,relro")
  1649  			}
  1650  			argv = append(argv, "-shared")
  1651  			if ctxt.HeadType == objabi.Hwindows {
  1652  				argv = addASLRargs(argv, *flagAslr)
  1653  			} else {
  1654  				// Pass -z nodelete to mark the shared library as
  1655  				// non-closeable: a dlclose will do nothing.
  1656  				argv = append(argv, "-Wl,-z,nodelete")
  1657  				// Only pass Bsymbolic on non-Windows.
  1658  				argv = append(argv, "-Wl,-Bsymbolic")
  1659  			}
  1660  		}
  1661  	case BuildModeShared:
  1662  		if ctxt.UseRelro() {
  1663  			argv = append(argv, "-Wl,-z,relro")
  1664  		}
  1665  		argv = append(argv, "-shared")
  1666  	case BuildModePlugin:
  1667  		if ctxt.HeadType == objabi.Hdarwin {
  1668  			argv = append(argv, "-dynamiclib")
  1669  		} else {
  1670  			if ctxt.UseRelro() {
  1671  				argv = append(argv, "-Wl,-z,relro")
  1672  			}
  1673  			argv = append(argv, "-shared")
  1674  		}
  1675  	}
  1676  
  1677  	var altLinker string
  1678  	if ctxt.IsELF && (ctxt.DynlinkingGo() || *flagBindNow) {
  1679  		// For ELF targets, when producing dynamically linked Go code
  1680  		// or when immediate binding is explicitly requested,
  1681  		// we force all symbol resolution to be done at program startup
  1682  		// because lazy PLT resolution can use large amounts of stack at
  1683  		// times we cannot allow it to do so.
  1684  		argv = append(argv, "-Wl,-z,now")
  1685  	}
  1686  
  1687  	if ctxt.IsELF && ctxt.DynlinkingGo() {
  1688  		// Do not let the host linker generate COPY relocations. These
  1689  		// can move symbols out of sections that rely on stable offsets
  1690  		// from the beginning of the section (like sym.STYPE).
  1691  		argv = append(argv, "-Wl,-z,nocopyreloc")
  1692  
  1693  		if buildcfg.GOOS == "android" {
  1694  			// Use lld to avoid errors from default linker (issue #38838)
  1695  			altLinker = "lld"
  1696  		}
  1697  
  1698  		if ctxt.Arch.InFamily(sys.ARM64) && buildcfg.GOOS == "linux" {
  1699  			// On ARM64, the GNU linker will fail with
  1700  			// -znocopyreloc if it thinks a COPY relocation is
  1701  			// required. Switch to gold.
  1702  			// https://sourceware.org/bugzilla/show_bug.cgi?id=19962
  1703  			// https://go.dev/issue/22040
  1704  			altLinker = "gold"
  1705  
  1706  			// If gold is not installed, gcc will silently switch
  1707  			// back to ld.bfd. So we parse the version information
  1708  			// and provide a useful error if gold is missing.
  1709  			name, args := flagExtld[0], flagExtld[1:]
  1710  			args = append(args, "-fuse-ld=gold", "-Wl,--version")
  1711  			cmd := exec.Command(name, args...)
  1712  			if out, err := cmd.CombinedOutput(); err == nil {
  1713  				if !bytes.Contains(out, []byte("GNU gold")) {
  1714  					log.Fatalf("ARM64 external linker must be gold (issue #15696, 22040), but is not: %s", out)
  1715  				}
  1716  			}
  1717  		}
  1718  	}
  1719  	if ctxt.Arch.Family == sys.ARM64 && buildcfg.GOOS == "freebsd" {
  1720  		// Switch to ld.bfd on freebsd/arm64.
  1721  		altLinker = "bfd"
  1722  
  1723  		// Provide a useful error if ld.bfd is missing.
  1724  		name, args := flagExtld[0], flagExtld[1:]
  1725  		args = append(args, "-fuse-ld=bfd", "-Wl,--version")
  1726  		cmd := exec.Command(name, args...)
  1727  		if out, err := cmd.CombinedOutput(); err == nil {
  1728  			if !bytes.Contains(out, []byte("GNU ld")) {
  1729  				log.Fatalf("ARM64 external linker must be ld.bfd (issue #35197), please install devel/binutils")
  1730  			}
  1731  		}
  1732  	}
  1733  	if altLinker != "" {
  1734  		argv = append(argv, "-fuse-ld="+altLinker)
  1735  	}
  1736  
  1737  	if ctxt.IsELF && linkerFlagSupported(ctxt.Arch, argv[0], "", "-Wl,--build-id=0x1234567890abcdef") { // Solaris ld doesn't support --build-id.
  1738  		if len(buildinfo) > 0 {
  1739  			argv = append(argv, fmt.Sprintf("-Wl,--build-id=0x%x", buildinfo))
  1740  		} else if *flagHostBuildid == "none" {
  1741  			argv = append(argv, "-Wl,--build-id=none")
  1742  		}
  1743  	}
  1744  
  1745  	// On Windows, given -o foo, GCC will append ".exe" to produce
  1746  	// "foo.exe".  We have decided that we want to honor the -o
  1747  	// option. To make this work, we append a '.' so that GCC
  1748  	// will decide that the file already has an extension. We
  1749  	// only want to do this when producing a Windows output file
  1750  	// on a Windows host.
  1751  	outopt := *flagOutfile
  1752  	if buildcfg.GOOS == "windows" && runtime.GOOS == "windows" && filepath.Ext(outopt) == "" {
  1753  		outopt += "."
  1754  	}
  1755  	argv = append(argv, "-o")
  1756  	argv = append(argv, outopt)
  1757  
  1758  	if rpath.val != "" {
  1759  		argv = append(argv, fmt.Sprintf("-Wl,-rpath,%s", rpath.val))
  1760  	}
  1761  
  1762  	if *flagInterpreter != "" {
  1763  		// Many linkers support both -I and the --dynamic-linker flags
  1764  		// to set the ELF interpreter, but lld only supports
  1765  		// --dynamic-linker so prefer that (ld on very old Solaris only
  1766  		// supports -I but that seems less important).
  1767  		argv = append(argv, fmt.Sprintf("-Wl,--dynamic-linker,%s", *flagInterpreter))
  1768  	}
  1769  
  1770  	// Force global symbols to be exported for dlopen, etc.
  1771  	if ctxt.IsELF {
  1772  		if ctxt.DynlinkingGo() || ctxt.BuildMode == BuildModeCShared || !linkerFlagSupported(ctxt.Arch, argv[0], altLinker, "-Wl,--export-dynamic-symbol=main") {
  1773  			argv = append(argv, "-rdynamic")
  1774  		} else {
  1775  			var exports []string
  1776  			ctxt.loader.ForAllCgoExportDynamic(func(s loader.Sym) {
  1777  				exports = append(exports, "-Wl,--export-dynamic-symbol="+ctxt.loader.SymExtname(s))
  1778  			})
  1779  			sort.Strings(exports)
  1780  			argv = append(argv, exports...)
  1781  		}
  1782  	}
  1783  	if ctxt.HeadType == objabi.Haix {
  1784  		fileName := xcoffCreateExportFile(ctxt)
  1785  		argv = append(argv, "-Wl,-bE:"+fileName)
  1786  	}
  1787  
  1788  	const unusedArguments = "-Qunused-arguments"
  1789  	if linkerFlagSupported(ctxt.Arch, argv[0], altLinker, unusedArguments) {
  1790  		argv = append(argv, unusedArguments)
  1791  	}
  1792  
  1793  	if ctxt.IsWindows() {
  1794  		// Suppress generation of the PE file header timestamp,
  1795  		// so as to avoid spurious build ID differences between
  1796  		// linked binaries that are otherwise identical other than
  1797  		// the date/time they were linked.
  1798  		const noTimeStamp = "-Wl,--no-insert-timestamp"
  1799  		if linkerFlagSupported(ctxt.Arch, argv[0], altLinker, noTimeStamp) {
  1800  			argv = append(argv, noTimeStamp)
  1801  		}
  1802  	}
  1803  
  1804  	const compressDWARF = "-Wl,--compress-debug-sections=zlib"
  1805  	if ctxt.compressDWARF && linkerFlagSupported(ctxt.Arch, argv[0], altLinker, compressDWARF) {
  1806  		argv = append(argv, compressDWARF)
  1807  	}
  1808  
  1809  	hostObjCopyPaths := ctxt.hostobjCopy()
  1810  	cleanTimeStamps(hostObjCopyPaths)
  1811  	godotopath := filepath.Join(*flagTmpdir, "go.o")
  1812  	cleanTimeStamps([]string{godotopath})
  1813  
  1814  	argv = append(argv, godotopath)
  1815  	argv = append(argv, hostObjCopyPaths...)
  1816  	if ctxt.HeadType == objabi.Haix {
  1817  		// We want to have C files after Go files to remove
  1818  		// trampolines csects made by ld.
  1819  		argv = append(argv, "-nostartfiles")
  1820  		argv = append(argv, "/lib/crt0_64.o")
  1821  
  1822  		extld := ctxt.extld()
  1823  		name, args := extld[0], extld[1:]
  1824  		// Get starting files.
  1825  		getPathFile := func(file string) string {
  1826  			args := append(args, "-maix64", "--print-file-name="+file)
  1827  			out, err := exec.Command(name, args...).CombinedOutput()
  1828  			if err != nil {
  1829  				log.Fatalf("running %s failed: %v\n%s", extld, err, out)
  1830  			}
  1831  			return strings.Trim(string(out), "\n")
  1832  		}
  1833  		// Since GCC version 11, the 64-bit version of GCC starting files
  1834  		// are now suffixed by "_64". Even under "-maix64" multilib directory
  1835  		// "crtcxa.o" is 32-bit.
  1836  		crtcxa := getPathFile("crtcxa_64.o")
  1837  		if !filepath.IsAbs(crtcxa) {
  1838  			crtcxa = getPathFile("crtcxa.o")
  1839  		}
  1840  		crtdbase := getPathFile("crtdbase_64.o")
  1841  		if !filepath.IsAbs(crtdbase) {
  1842  			crtdbase = getPathFile("crtdbase.o")
  1843  		}
  1844  		argv = append(argv, crtcxa)
  1845  		argv = append(argv, crtdbase)
  1846  	}
  1847  
  1848  	if ctxt.linkShared {
  1849  		seenDirs := make(map[string]bool)
  1850  		seenLibs := make(map[string]bool)
  1851  		addshlib := func(path string) {
  1852  			dir, base := filepath.Split(path)
  1853  			if !seenDirs[dir] {
  1854  				argv = append(argv, "-L"+dir)
  1855  				if !rpath.set {
  1856  					argv = append(argv, "-Wl,-rpath="+dir)
  1857  				}
  1858  				seenDirs[dir] = true
  1859  			}
  1860  			base = strings.TrimSuffix(base, ".so")
  1861  			base = strings.TrimPrefix(base, "lib")
  1862  			if !seenLibs[base] {
  1863  				argv = append(argv, "-l"+base)
  1864  				seenLibs[base] = true
  1865  			}
  1866  		}
  1867  		for _, shlib := range ctxt.Shlibs {
  1868  			addshlib(shlib.Path)
  1869  			for _, dep := range shlib.Deps {
  1870  				if dep == "" {
  1871  					continue
  1872  				}
  1873  				libpath := findshlib(ctxt, dep)
  1874  				if libpath != "" {
  1875  					addshlib(libpath)
  1876  				}
  1877  			}
  1878  		}
  1879  	}
  1880  
  1881  	// clang, unlike GCC, passes -rdynamic to the linker
  1882  	// even when linking with -static, causing a linker
  1883  	// error when using GNU ld. So take out -rdynamic if
  1884  	// we added it. We do it in this order, rather than
  1885  	// only adding -rdynamic later, so that -extldflags
  1886  	// can override -rdynamic without using -static.
  1887  	// Similarly for -Wl,--dynamic-linker.
  1888  	checkStatic := func(arg string) {
  1889  		if ctxt.IsELF && arg == "-static" {
  1890  			for i := range argv {
  1891  				if argv[i] == "-rdynamic" || strings.HasPrefix(argv[i], "-Wl,--dynamic-linker,") {
  1892  					argv[i] = "-static"
  1893  				}
  1894  			}
  1895  		}
  1896  	}
  1897  
  1898  	for _, p := range ldflag {
  1899  		argv = append(argv, p)
  1900  		checkStatic(p)
  1901  	}
  1902  
  1903  	// When building a program with the default -buildmode=exe the
  1904  	// gc compiler generates code requires DT_TEXTREL in a
  1905  	// position independent executable (PIE). On systems where the
  1906  	// toolchain creates PIEs by default, and where DT_TEXTREL
  1907  	// does not work, the resulting programs will not run. See
  1908  	// issue #17847. To avoid this problem pass -no-pie to the
  1909  	// toolchain if it is supported.
  1910  	if ctxt.BuildMode == BuildModeExe && !ctxt.linkShared && !(ctxt.IsDarwin() && ctxt.IsARM64()) {
  1911  		// GCC uses -no-pie, clang uses -nopie.
  1912  		for _, nopie := range []string{"-no-pie", "-nopie"} {
  1913  			if linkerFlagSupported(ctxt.Arch, argv[0], altLinker, nopie) {
  1914  				argv = append(argv, nopie)
  1915  				break
  1916  			}
  1917  		}
  1918  	}
  1919  
  1920  	for _, p := range flagExtldflags {
  1921  		argv = append(argv, p)
  1922  		checkStatic(p)
  1923  	}
  1924  	if ctxt.HeadType == objabi.Hwindows {
  1925  		// Determine which linker we're using. Add in the extldflags in
  1926  		// case used has specified "-fuse-ld=...".
  1927  		extld := ctxt.extld()
  1928  		name, args := extld[0], extld[1:]
  1929  		args = append(args, trimLinkerArgv(flagExtldflags)...)
  1930  		args = append(args, "-Wl,--version")
  1931  		cmd := exec.Command(name, args...)
  1932  		usingLLD := false
  1933  		if out, err := cmd.CombinedOutput(); err == nil {
  1934  			if bytes.Contains(out, []byte("LLD ")) {
  1935  				usingLLD = true
  1936  			}
  1937  		}
  1938  
  1939  		// use gcc linker script to work around gcc bug
  1940  		// (see https://golang.org/issue/20183 for details).
  1941  		if !usingLLD {
  1942  			p := writeGDBLinkerScript()
  1943  			argv = append(argv, "-Wl,-T,"+p)
  1944  		}
  1945  		if *flagRace {
  1946  			// Apparently --print-file-name doesn't work with -msvc clang.
  1947  			// (The library name is synchronization.lib, but even with that
  1948  			// name it still doesn't print the full path.) Assume it always
  1949  			// it.
  1950  			if isMSVC || ctxt.findLibPath("libsynchronization.a") != "libsynchronization.a" {
  1951  				argv = append(argv, "-lsynchronization")
  1952  			}
  1953  		}
  1954  		if !isMSVC {
  1955  			// libmingw32 and libmingwex have some inter-dependencies,
  1956  			// so must use linker groups.
  1957  			argv = append(argv, "-Wl,--start-group", "-lmingwex", "-lmingw32", "-Wl,--end-group")
  1958  		}
  1959  		argv = append(argv, peimporteddlls()...)
  1960  	}
  1961  
  1962  	argv = ctxt.passLongArgsInResponseFile(argv, altLinker)
  1963  
  1964  	if ctxt.Debugvlog != 0 {
  1965  		ctxt.Logf("host link:")
  1966  		for _, v := range argv {
  1967  			ctxt.Logf(" %q", v)
  1968  		}
  1969  		ctxt.Logf("\n")
  1970  	}
  1971  
  1972  	cmd := exec.Command(argv[0], argv[1:]...)
  1973  	out, err := cmd.CombinedOutput()
  1974  	if err != nil {
  1975  		Exitf("running %s failed: %v\n%s\n%s", argv[0], err, cmd, out)
  1976  	}
  1977  
  1978  	// Filter out useless linker warnings caused by bugs outside Go.
  1979  	// See also cmd/go/internal/work/exec.go's gccld method.
  1980  	var save [][]byte
  1981  	var skipLines int
  1982  	for _, line := range bytes.SplitAfter(out, []byte("\n")) {
  1983  		// golang.org/issue/26073 - Apple Xcode bug
  1984  		if bytes.Contains(line, []byte("ld: warning: text-based stub file")) {
  1985  			continue
  1986  		}
  1987  
  1988  		if skipLines > 0 {
  1989  			skipLines--
  1990  			continue
  1991  		}
  1992  
  1993  		// Remove TOC overflow warning on AIX.
  1994  		if bytes.Contains(line, []byte("ld: 0711-783")) {
  1995  			skipLines = 2
  1996  			continue
  1997  		}
  1998  
  1999  		save = append(save, line)
  2000  	}
  2001  	out = bytes.Join(save, nil)
  2002  
  2003  	if len(out) > 0 {
  2004  		// always print external output even if the command is successful, so that we don't
  2005  		// swallow linker warnings (see https://golang.org/issue/17935).
  2006  		if ctxt.IsDarwin() && ctxt.IsAMD64() {
  2007  			const noPieWarning = "ld: warning: -no_pie is deprecated when targeting new OS versions\n"
  2008  			if i := bytes.Index(out, []byte(noPieWarning)); i >= 0 {
  2009  				// swallow -no_pie deprecation warning, issue 54482
  2010  				out = append(out[:i], out[i+len(noPieWarning):]...)
  2011  			}
  2012  		}
  2013  		if ctxt.IsDarwin() {
  2014  			const bindAtLoadWarning = "ld: warning: -bind_at_load is deprecated on macOS\n"
  2015  			if i := bytes.Index(out, []byte(bindAtLoadWarning)); i >= 0 {
  2016  				// -bind_at_load is deprecated with ld-prime, but needed for
  2017  				// correctness with older versions of ld64. Swallow the warning.
  2018  				// TODO: maybe pass -bind_at_load conditionally based on C
  2019  				// linker version.
  2020  				out = append(out[:i], out[i+len(bindAtLoadWarning):]...)
  2021  			}
  2022  		}
  2023  		ctxt.Logf("%s", out)
  2024  	}
  2025  
  2026  	// Helper for updating a Macho binary in some way (shared between
  2027  	// dwarf combining and UUID update).
  2028  	updateMachoOutFile := func(op string, updateFunc machoUpdateFunc) {
  2029  		// For os.Rename to work reliably, must be in same directory as outfile.
  2030  		rewrittenOutput := *flagOutfile + "~"
  2031  		exef, err := os.Open(*flagOutfile)
  2032  		if err != nil {
  2033  			Exitf("%s: %s failed: %v", os.Args[0], op, err)
  2034  		}
  2035  		defer exef.Close()
  2036  		exem, err := macho.NewFile(exef)
  2037  		if err != nil {
  2038  			Exitf("%s: parsing Mach-O header failed: %v", os.Args[0], err)
  2039  		}
  2040  		if err := updateFunc(ctxt, exef, exem, rewrittenOutput); err != nil {
  2041  			Exitf("%s: %s failed: %v", os.Args[0], op, err)
  2042  		}
  2043  		os.Remove(*flagOutfile)
  2044  		if err := os.Rename(rewrittenOutput, *flagOutfile); err != nil {
  2045  			Exitf("%s: %v", os.Args[0], err)
  2046  		}
  2047  	}
  2048  
  2049  	uuidUpdated := false
  2050  	if combineDwarf {
  2051  		// Find "dsymutils" and "strip" tools using CC --print-prog-name.
  2052  		dsymutilCmd := ctxt.findExtLinkTool("dsymutil")
  2053  		stripCmd := ctxt.findExtLinkTool("strip")
  2054  
  2055  		dsym := filepath.Join(*flagTmpdir, "go.dwarf")
  2056  		cmd := exec.Command(dsymutilCmd, "-f", *flagOutfile, "-o", dsym)
  2057  		// dsymutil may not clean up its temp directory at exit.
  2058  		// Set DSYMUTIL_REPRODUCER_PATH to work around. see issue 59026.
  2059  		// dsymutil (Apple LLVM version 16.0.0) deletes the directory
  2060  		// even if it is not empty. We still need our tmpdir, so give a
  2061  		// subdirectory to dsymutil.
  2062  		dsymDir := filepath.Join(*flagTmpdir, "dsymutil")
  2063  		err := os.MkdirAll(dsymDir, 0777)
  2064  		if err != nil {
  2065  			Exitf("fail to create temp dir: %v", err)
  2066  		}
  2067  		cmd.Env = append(os.Environ(), "DSYMUTIL_REPRODUCER_PATH="+dsymDir)
  2068  		if ctxt.Debugvlog != 0 {
  2069  			ctxt.Logf("host link dsymutil:")
  2070  			for _, v := range cmd.Args {
  2071  				ctxt.Logf(" %q", v)
  2072  			}
  2073  			ctxt.Logf("\n")
  2074  		}
  2075  		if out, err := cmd.CombinedOutput(); err != nil {
  2076  			Exitf("%s: running dsymutil failed: %v\n%s\n%s", os.Args[0], err, cmd, out)
  2077  		}
  2078  		// Remove STAB (symbolic debugging) symbols after we are done with them (by dsymutil).
  2079  		// They contain temporary file paths and make the build not reproducible.
  2080  		var stripArgs = []string{"-S"}
  2081  		if debug_s {
  2082  			// We are generating a binary with symbol table suppressed.
  2083  			// Suppress local symbols. We need to keep dynamically exported
  2084  			// and referenced symbols so the dynamic linker can resolve them.
  2085  			stripArgs = append(stripArgs, "-x")
  2086  		}
  2087  		stripArgs = append(stripArgs, *flagOutfile)
  2088  		if ctxt.Debugvlog != 0 {
  2089  			ctxt.Logf("host link strip: %q", stripCmd)
  2090  			for _, v := range stripArgs {
  2091  				ctxt.Logf(" %q", v)
  2092  			}
  2093  			ctxt.Logf("\n")
  2094  		}
  2095  		cmd = exec.Command(stripCmd, stripArgs...)
  2096  		if out, err := cmd.CombinedOutput(); err != nil {
  2097  			Exitf("%s: running strip failed: %v\n%s\n%s", os.Args[0], err, cmd, out)
  2098  		}
  2099  		// Skip combining if `dsymutil` didn't generate a file. See #11994.
  2100  		if _, err := os.Stat(dsym); err == nil {
  2101  			updateMachoOutFile("combining dwarf",
  2102  				func(ctxt *Link, exef *os.File, exem *macho.File, outexe string) error {
  2103  					return machoCombineDwarf(ctxt, exef, exem, dsym, outexe)
  2104  				})
  2105  			uuidUpdated = true
  2106  		}
  2107  	}
  2108  	if ctxt.IsDarwin() && !uuidUpdated && len(buildinfo) > 0 {
  2109  		updateMachoOutFile("rewriting uuid",
  2110  			func(ctxt *Link, exef *os.File, exem *macho.File, outexe string) error {
  2111  				return machoRewriteUuid(ctxt, exef, exem, outexe)
  2112  			})
  2113  	}
  2114  	hostlinkfips(ctxt, *flagOutfile, *flagFipso)
  2115  	if ctxt.NeedCodeSign() {
  2116  		err := machoCodeSign(ctxt, *flagOutfile)
  2117  		if err != nil {
  2118  			Exitf("%s: code signing failed: %v", os.Args[0], err)
  2119  		}
  2120  	}
  2121  }
  2122  
  2123  // passLongArgsInResponseFile writes the arguments into a file if they
  2124  // are very long.
  2125  func (ctxt *Link) passLongArgsInResponseFile(argv []string, altLinker string) []string {
  2126  	c := 0
  2127  	for _, arg := range argv {
  2128  		c += len(arg)
  2129  	}
  2130  
  2131  	if c < sys.ExecArgLengthLimit {
  2132  		return argv
  2133  	}
  2134  
  2135  	// Only use response files if they are supported.
  2136  	response := filepath.Join(*flagTmpdir, "response")
  2137  	if err := os.WriteFile(response, nil, 0644); err != nil {
  2138  		log.Fatalf("failed while testing response file: %v", err)
  2139  	}
  2140  	if !linkerFlagSupported(ctxt.Arch, argv[0], altLinker, "@"+response) {
  2141  		if ctxt.Debugvlog != 0 {
  2142  			ctxt.Logf("not using response file because linker does not support one")
  2143  		}
  2144  		return argv
  2145  	}
  2146  
  2147  	var buf bytes.Buffer
  2148  	for _, arg := range argv[1:] {
  2149  		// The external linker response file supports quoted strings.
  2150  		fmt.Fprintf(&buf, "%q\n", arg)
  2151  	}
  2152  	if err := os.WriteFile(response, buf.Bytes(), 0644); err != nil {
  2153  		log.Fatalf("failed while writing response file: %v", err)
  2154  	}
  2155  	if ctxt.Debugvlog != 0 {
  2156  		ctxt.Logf("response file %s contents:\n%s", response, buf.Bytes())
  2157  	}
  2158  	return []string{
  2159  		argv[0],
  2160  		"@" + response,
  2161  	}
  2162  }
  2163  
  2164  var createTrivialCOnce sync.Once
  2165  
  2166  func linkerFlagSupported(arch *sys.Arch, linker, altLinker, flag string) bool {
  2167  	createTrivialCOnce.Do(func() {
  2168  		src := filepath.Join(*flagTmpdir, "trivial.c")
  2169  		if err := os.WriteFile(src, []byte("int main() { return 0; }"), 0666); err != nil {
  2170  			Errorf("WriteFile trivial.c failed: %v", err)
  2171  		}
  2172  	})
  2173  
  2174  	flags := hostlinkArchArgs(arch)
  2175  
  2176  	moreFlags := trimLinkerArgv(append(ldflag, flagExtldflags...))
  2177  	flags = append(flags, moreFlags...)
  2178  
  2179  	if altLinker != "" {
  2180  		flags = append(flags, "-fuse-ld="+altLinker)
  2181  	}
  2182  	trivialPath := filepath.Join(*flagTmpdir, "trivial.c")
  2183  	outPath := filepath.Join(*flagTmpdir, "a.out")
  2184  	flags = append(flags, "-o", outPath, flag, trivialPath)
  2185  
  2186  	cmd := exec.Command(linker, flags...)
  2187  	cmd.Env = append([]string{"LC_ALL=C"}, os.Environ()...)
  2188  	out, err := cmd.CombinedOutput()
  2189  	// GCC says "unrecognized command line option ‘-no-pie’"
  2190  	// clang says "unknown argument: '-no-pie'"
  2191  	return err == nil && !bytes.Contains(out, []byte("unrecognized")) && !bytes.Contains(out, []byte("unknown"))
  2192  }
  2193  
  2194  // trimLinkerArgv returns a new copy of argv that does not include flags
  2195  // that are not relevant for testing whether some linker option works.
  2196  func trimLinkerArgv(argv []string) []string {
  2197  	flagsWithNextArgSkip := []string{
  2198  		"-F",
  2199  		"-l",
  2200  		"-L",
  2201  		"-framework",
  2202  		"-Wl,-framework",
  2203  		"-Wl,-rpath",
  2204  		"-Wl,-undefined",
  2205  	}
  2206  	flagsWithNextArgKeep := []string{
  2207  		"-arch",
  2208  		"-isysroot",
  2209  		"--sysroot",
  2210  		"-target",
  2211  		"--target",
  2212  	}
  2213  	prefixesToKeep := []string{
  2214  		"-f",
  2215  		"-m",
  2216  		"-p",
  2217  		"-Wl,",
  2218  		"-arch",
  2219  		"-isysroot",
  2220  		"--sysroot",
  2221  		"-target",
  2222  		"--target",
  2223  	}
  2224  
  2225  	var flags []string
  2226  	keep := false
  2227  	skip := false
  2228  	for _, f := range argv {
  2229  		if keep {
  2230  			flags = append(flags, f)
  2231  			keep = false
  2232  		} else if skip {
  2233  			skip = false
  2234  		} else if f == "" || f[0] != '-' {
  2235  		} else if slices.Contains(flagsWithNextArgSkip, f) {
  2236  			skip = true
  2237  		} else if slices.Contains(flagsWithNextArgKeep, f) {
  2238  			flags = append(flags, f)
  2239  			keep = true
  2240  		} else {
  2241  			for _, p := range prefixesToKeep {
  2242  				if strings.HasPrefix(f, p) {
  2243  					flags = append(flags, f)
  2244  					break
  2245  				}
  2246  			}
  2247  		}
  2248  	}
  2249  	return flags
  2250  }
  2251  
  2252  // hostlinkArchArgs returns arguments to pass to the external linker
  2253  // based on the architecture.
  2254  func hostlinkArchArgs(arch *sys.Arch) []string {
  2255  	switch arch.Family {
  2256  	case sys.I386:
  2257  		return []string{"-m32"}
  2258  	case sys.AMD64:
  2259  		if buildcfg.GOOS == "darwin" {
  2260  			return []string{"-arch", "x86_64", "-m64"}
  2261  		}
  2262  		return []string{"-m64"}
  2263  	case sys.S390X:
  2264  		return []string{"-m64"}
  2265  	case sys.ARM:
  2266  		return []string{"-marm"}
  2267  	case sys.ARM64:
  2268  		if buildcfg.GOOS == "darwin" {
  2269  			return []string{"-arch", "arm64"}
  2270  		}
  2271  	case sys.Loong64:
  2272  		return []string{"-mabi=lp64d"}
  2273  	case sys.MIPS64:
  2274  		return []string{"-mabi=64"}
  2275  	case sys.MIPS:
  2276  		return []string{"-mabi=32"}
  2277  	case sys.PPC64:
  2278  		if buildcfg.GOOS == "aix" {
  2279  			return []string{"-maix64"}
  2280  		} else {
  2281  			return []string{"-m64"}
  2282  		}
  2283  
  2284  	}
  2285  	return nil
  2286  }
  2287  
  2288  var wantHdr = objabi.HeaderString()
  2289  
  2290  // ldobj loads an input object. If it is a host object (an object
  2291  // compiled by a non-Go compiler) it returns the Hostobj pointer. If
  2292  // it is a Go object, it returns nil.
  2293  func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string, file string) *Hostobj {
  2294  	pkg := objabi.PathToPrefix(lib.Pkg)
  2295  
  2296  	eof := f.Offset() + length
  2297  	start := f.Offset()
  2298  	c1 := bgetc(f)
  2299  	c2 := bgetc(f)
  2300  	c3 := bgetc(f)
  2301  	c4 := bgetc(f)
  2302  	f.MustSeek(start, 0)
  2303  
  2304  	unit := &sym.CompilationUnit{Lib: lib}
  2305  	lib.Units = append(lib.Units, unit)
  2306  
  2307  	magic := uint32(c1)<<24 | uint32(c2)<<16 | uint32(c3)<<8 | uint32(c4)
  2308  	if magic == 0x7f454c46 { // \x7F E L F
  2309  		ldelf := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
  2310  			textp, flags, err := loadelf.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn, ehdr.Flags)
  2311  			if err != nil {
  2312  				Errorf("%v", err)
  2313  				return
  2314  			}
  2315  			ehdr.Flags = flags
  2316  			ctxt.Textp = append(ctxt.Textp, textp...)
  2317  		}
  2318  		return ldhostobj(ldelf, ctxt.HeadType, f, pkg, length, pn, file)
  2319  	}
  2320  
  2321  	if magic&^1 == 0xfeedface || magic&^0x01000000 == 0xcefaedfe {
  2322  		ldmacho := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
  2323  			textp, err := loadmacho.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn)
  2324  			if err != nil {
  2325  				Errorf("%v", err)
  2326  				return
  2327  			}
  2328  			ctxt.Textp = append(ctxt.Textp, textp...)
  2329  		}
  2330  		return ldhostobj(ldmacho, ctxt.HeadType, f, pkg, length, pn, file)
  2331  	}
  2332  
  2333  	switch c1<<8 | c2 {
  2334  	case 0x4c01, // 386
  2335  		0x6486, // amd64
  2336  		0xc401, // arm
  2337  		0x64aa: // arm64
  2338  		ldpe := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
  2339  			ls, err := loadpe.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn)
  2340  			if err != nil {
  2341  				Errorf("%v", err)
  2342  				return
  2343  			}
  2344  			if len(ls.Resources) != 0 {
  2345  				setpersrc(ctxt, ls.Resources)
  2346  			}
  2347  			if ls.PData != 0 {
  2348  				sehp.pdata = append(sehp.pdata, ls.PData)
  2349  			}
  2350  			if ls.XData != 0 {
  2351  				sehp.xdata = append(sehp.xdata, ls.XData)
  2352  			}
  2353  			ctxt.Textp = append(ctxt.Textp, ls.Textp...)
  2354  		}
  2355  		return ldhostobj(ldpe, ctxt.HeadType, f, pkg, length, pn, file)
  2356  	}
  2357  
  2358  	if c1 == 0x01 && (c2 == 0xD7 || c2 == 0xF7) {
  2359  		ldxcoff := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
  2360  			textp, err := loadxcoff.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn)
  2361  			if err != nil {
  2362  				Errorf("%v", err)
  2363  				return
  2364  			}
  2365  			ctxt.Textp = append(ctxt.Textp, textp...)
  2366  		}
  2367  		return ldhostobj(ldxcoff, ctxt.HeadType, f, pkg, length, pn, file)
  2368  	}
  2369  
  2370  	if c1 != 'g' || c2 != 'o' || c3 != ' ' || c4 != 'o' {
  2371  		// An unrecognized object is just passed to the external linker.
  2372  		// If we try to read symbols from this object, we will
  2373  		// report an error at that time.
  2374  		unknownObjFormat = true
  2375  		return ldhostobj(nil, ctxt.HeadType, f, pkg, length, pn, file)
  2376  	}
  2377  
  2378  	/* check the header */
  2379  	line, err := f.ReadString('\n')
  2380  	if err != nil {
  2381  		Errorf("truncated object file: %s: %v", pn, err)
  2382  		return nil
  2383  	}
  2384  
  2385  	if !strings.HasPrefix(line, "go object ") {
  2386  		if strings.HasSuffix(pn, ".go") {
  2387  			Exitf("%s: uncompiled .go source file", pn)
  2388  			return nil
  2389  		}
  2390  
  2391  		if line == ctxt.Arch.Name {
  2392  			// old header format: just $GOOS
  2393  			Errorf("%s: stale object file", pn)
  2394  			return nil
  2395  		}
  2396  
  2397  		Errorf("%s: not an object file: @%d %q", pn, start, line)
  2398  		return nil
  2399  	}
  2400  
  2401  	// First, check that the basic GOOS, GOARCH, and Version match.
  2402  	if line != wantHdr {
  2403  		Errorf("%s: linked object header mismatch:\nhave %q\nwant %q\n", pn, line, wantHdr)
  2404  	}
  2405  
  2406  	// Skip over exports and other info -- ends with \n!\n.
  2407  	//
  2408  	// Note: It's possible for "\n!\n" to appear within the binary
  2409  	// package export data format. To avoid truncating the package
  2410  	// definition prematurely (issue 21703), we keep track of
  2411  	// how many "$$" delimiters we've seen.
  2412  
  2413  	import0 := f.Offset()
  2414  
  2415  	c1 = '\n' // the last line ended in \n
  2416  	c2 = bgetc(f)
  2417  	c3 = bgetc(f)
  2418  	markers := 0
  2419  	for {
  2420  		if c1 == '\n' {
  2421  			if markers%2 == 0 && c2 == '!' && c3 == '\n' {
  2422  				break
  2423  			}
  2424  			if c2 == '$' && c3 == '$' {
  2425  				markers++
  2426  			}
  2427  		}
  2428  
  2429  		c1 = c2
  2430  		c2 = c3
  2431  		c3 = bgetc(f)
  2432  		if c3 == -1 {
  2433  			Errorf("truncated object file: %s", pn)
  2434  			return nil
  2435  		}
  2436  	}
  2437  
  2438  	import1 := f.Offset()
  2439  
  2440  	f.MustSeek(import0, 0)
  2441  	ldpkg(ctxt, f, lib, import1-import0-2, pn) // -2 for !\n
  2442  	f.MustSeek(import1, 0)
  2443  
  2444  	fingerprint := ctxt.loader.Preload(ctxt.IncVersion(), f, lib, unit, eof-f.Offset())
  2445  	if !fingerprint.IsZero() { // Assembly objects don't have fingerprints. Ignore them.
  2446  		// Check fingerprint, to ensure the importing and imported packages
  2447  		// have consistent view of symbol indices.
  2448  		// Normally the go command should ensure this. But in case something
  2449  		// goes wrong, it could lead to obscure bugs like run-time crash.
  2450  		// Check it here to be sure.
  2451  		if lib.Fingerprint.IsZero() { // Not yet imported. Update its fingerprint.
  2452  			lib.Fingerprint = fingerprint
  2453  		}
  2454  		checkFingerprint(lib, fingerprint, lib.Srcref, lib.Fingerprint)
  2455  	}
  2456  
  2457  	addImports(ctxt, lib, pn)
  2458  	return nil
  2459  }
  2460  
  2461  // symbolsAreUnresolved scans through the loader's list of unresolved
  2462  // symbols and checks to see whether any of them match the names of the
  2463  // symbols in 'want'. Return value is a list of bools, with list[K] set
  2464  // to true if there is an unresolved reference to the symbol in want[K].
  2465  func symbolsAreUnresolved(ctxt *Link, want []string) []bool {
  2466  	returnAllUndefs := -1
  2467  	undefs, _ := ctxt.loader.UndefinedRelocTargets(returnAllUndefs)
  2468  	seen := make(map[loader.Sym]struct{})
  2469  	rval := make([]bool, len(want))
  2470  	wantm := make(map[string]int)
  2471  	for k, w := range want {
  2472  		wantm[w] = k
  2473  	}
  2474  	count := 0
  2475  	for _, s := range undefs {
  2476  		if _, ok := seen[s]; ok {
  2477  			continue
  2478  		}
  2479  		seen[s] = struct{}{}
  2480  		if k, ok := wantm[ctxt.loader.SymName(s)]; ok {
  2481  			rval[k] = true
  2482  			count++
  2483  			if count == len(want) {
  2484  				return rval
  2485  			}
  2486  		}
  2487  	}
  2488  	return rval
  2489  }
  2490  
  2491  // hostObject reads a single host object file (compare to "hostArchive").
  2492  // This is used as part of internal linking when we need to pull in
  2493  // files such as "crt?.o".
  2494  func hostObject(ctxt *Link, objname string, path string) {
  2495  	if ctxt.Debugvlog > 1 {
  2496  		ctxt.Logf("hostObject(%s)\n", path)
  2497  	}
  2498  	objlib := sym.Library{
  2499  		Pkg: objname,
  2500  	}
  2501  	f, err := bio.Open(path)
  2502  	if err != nil {
  2503  		Exitf("cannot open host object %q file %s: %v", objname, path, err)
  2504  	}
  2505  	defer f.Close()
  2506  	h := ldobj(ctxt, f, &objlib, 0, path, path)
  2507  	if h.ld == nil {
  2508  		Exitf("unrecognized object file format in %s", path)
  2509  	}
  2510  	h.file = path
  2511  	h.length = f.MustSeek(0, 2)
  2512  	f.MustSeek(h.off, 0)
  2513  	h.ld(ctxt, f, h.pkg, h.length, h.pn)
  2514  	if *flagCaptureHostObjs != "" {
  2515  		captureHostObj(h)
  2516  	}
  2517  }
  2518  
  2519  func checkFingerprint(lib *sym.Library, libfp goobj.FingerprintType, src string, srcfp goobj.FingerprintType) {
  2520  	if libfp != srcfp {
  2521  		Exitf("fingerprint mismatch: %s has %x, import from %s expecting %x", lib, libfp, src, srcfp)
  2522  	}
  2523  }
  2524  
  2525  func readelfsymboldata(ctxt *Link, f *elf.File, sym *elf.Symbol) []byte {
  2526  	data := make([]byte, sym.Size)
  2527  	sect := f.Sections[sym.Section]
  2528  	if sect.Type != elf.SHT_PROGBITS && sect.Type != elf.SHT_NOTE {
  2529  		Errorf("reading %s from non-data section", sym.Name)
  2530  	}
  2531  	n, err := sect.ReadAt(data, int64(sym.Value-sect.Addr))
  2532  	if uint64(n) != sym.Size {
  2533  		Errorf("reading contents of %s: %v", sym.Name, err)
  2534  	}
  2535  	return data
  2536  }
  2537  
  2538  func readwithpad(r io.Reader, sz int32) ([]byte, error) {
  2539  	data := make([]byte, Rnd(int64(sz), 4))
  2540  	_, err := io.ReadFull(r, data)
  2541  	if err != nil {
  2542  		return nil, err
  2543  	}
  2544  	data = data[:sz]
  2545  	return data, nil
  2546  }
  2547  
  2548  func readnote(f *elf.File, name []byte, typ int32) ([]byte, error) {
  2549  	for _, sect := range f.Sections {
  2550  		if sect.Type != elf.SHT_NOTE {
  2551  			continue
  2552  		}
  2553  		r := sect.Open()
  2554  		for {
  2555  			var namesize, descsize, noteType int32
  2556  			err := binary.Read(r, f.ByteOrder, &namesize)
  2557  			if err != nil {
  2558  				if err == io.EOF {
  2559  					break
  2560  				}
  2561  				return nil, fmt.Errorf("read namesize failed: %v", err)
  2562  			}
  2563  			err = binary.Read(r, f.ByteOrder, &descsize)
  2564  			if err != nil {
  2565  				return nil, fmt.Errorf("read descsize failed: %v", err)
  2566  			}
  2567  			err = binary.Read(r, f.ByteOrder, &noteType)
  2568  			if err != nil {
  2569  				return nil, fmt.Errorf("read type failed: %v", err)
  2570  			}
  2571  			noteName, err := readwithpad(r, namesize)
  2572  			if err != nil {
  2573  				return nil, fmt.Errorf("read name failed: %v", err)
  2574  			}
  2575  			desc, err := readwithpad(r, descsize)
  2576  			if err != nil {
  2577  				return nil, fmt.Errorf("read desc failed: %v", err)
  2578  			}
  2579  			if string(name) == string(noteName) && typ == noteType {
  2580  				return desc, nil
  2581  			}
  2582  		}
  2583  	}
  2584  	return nil, nil
  2585  }
  2586  
  2587  func findshlib(ctxt *Link, shlib string) string {
  2588  	if filepath.IsAbs(shlib) {
  2589  		return shlib
  2590  	}
  2591  	for _, libdir := range ctxt.Libdir {
  2592  		libpath := filepath.Join(libdir, shlib)
  2593  		if _, err := os.Stat(libpath); err == nil {
  2594  			return libpath
  2595  		}
  2596  	}
  2597  	Errorf("cannot find shared library: %s", shlib)
  2598  	return ""
  2599  }
  2600  
  2601  func ldshlibsyms(ctxt *Link, shlib string) {
  2602  	var libpath string
  2603  	if filepath.IsAbs(shlib) {
  2604  		libpath = shlib
  2605  		shlib = filepath.Base(shlib)
  2606  	} else {
  2607  		libpath = findshlib(ctxt, shlib)
  2608  		if libpath == "" {
  2609  			return
  2610  		}
  2611  	}
  2612  	for _, processedlib := range ctxt.Shlibs {
  2613  		if processedlib.Path == libpath {
  2614  			return
  2615  		}
  2616  	}
  2617  	if ctxt.Debugvlog > 1 {
  2618  		ctxt.Logf("ldshlibsyms: found library with name %s at %s\n", shlib, libpath)
  2619  	}
  2620  
  2621  	f, err := elf.Open(libpath)
  2622  	if err != nil {
  2623  		Errorf("cannot open shared library: %s", libpath)
  2624  		return
  2625  	}
  2626  	// Keep the file open as decodetypeGcprog needs to read from it.
  2627  	// TODO: fix. Maybe mmap the file.
  2628  	//defer f.Close()
  2629  
  2630  	hash, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GOABIHASH_TAG)
  2631  	if err != nil {
  2632  		Errorf("cannot read ABI hash from shared library %s: %v", libpath, err)
  2633  		return
  2634  	}
  2635  
  2636  	depsbytes, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GODEPS_TAG)
  2637  	if err != nil {
  2638  		Errorf("cannot read dep list from shared library %s: %v", libpath, err)
  2639  		return
  2640  	}
  2641  	var deps []string
  2642  	for _, dep := range strings.Split(string(depsbytes), "\n") {
  2643  		if dep == "" {
  2644  			continue
  2645  		}
  2646  		if !filepath.IsAbs(dep) {
  2647  			// If the dep can be interpreted as a path relative to the shlib
  2648  			// in which it was found, do that. Otherwise, we will leave it
  2649  			// to be resolved by libdir lookup.
  2650  			abs := filepath.Join(filepath.Dir(libpath), dep)
  2651  			if _, err := os.Stat(abs); err == nil {
  2652  				dep = abs
  2653  			}
  2654  		}
  2655  		deps = append(deps, dep)
  2656  	}
  2657  
  2658  	syms, err := f.DynamicSymbols()
  2659  	if err != nil {
  2660  		Errorf("cannot read symbols from shared library: %s", libpath)
  2661  		return
  2662  	}
  2663  
  2664  	symAddr := map[string]uint64{}
  2665  	for _, elfsym := range syms {
  2666  		if elf.ST_TYPE(elfsym.Info) == elf.STT_NOTYPE || elf.ST_TYPE(elfsym.Info) == elf.STT_SECTION {
  2667  			continue
  2668  		}
  2669  
  2670  		// Symbols whose names start with "type:" are compiler generated,
  2671  		// so make functions with that prefix internal.
  2672  		ver := 0
  2673  		symname := elfsym.Name // (unmangled) symbol name
  2674  		if elf.ST_TYPE(elfsym.Info) == elf.STT_FUNC && strings.HasPrefix(elfsym.Name, "type:") {
  2675  			ver = abiInternalVer
  2676  		} else if buildcfg.Experiment.RegabiWrappers && elf.ST_TYPE(elfsym.Info) == elf.STT_FUNC {
  2677  			// Demangle the ABI name. Keep in sync with symtab.go:mangleABIName.
  2678  			if strings.HasSuffix(elfsym.Name, ".abiinternal") {
  2679  				ver = sym.SymVerABIInternal
  2680  				symname = strings.TrimSuffix(elfsym.Name, ".abiinternal")
  2681  			} else if strings.HasSuffix(elfsym.Name, ".abi0") {
  2682  				ver = 0
  2683  				symname = strings.TrimSuffix(elfsym.Name, ".abi0")
  2684  			}
  2685  		}
  2686  
  2687  		l := ctxt.loader
  2688  		s := l.LookupOrCreateSym(symname, ver)
  2689  
  2690  		// Because loadlib above loads all .a files before loading
  2691  		// any shared libraries, any non-dynimport symbols we find
  2692  		// that duplicate symbols already loaded should be ignored
  2693  		// (the symbols from the .a files "win").
  2694  		if l.SymType(s) != 0 && l.SymType(s) != sym.SDYNIMPORT {
  2695  			continue
  2696  		}
  2697  		su := l.MakeSymbolUpdater(s)
  2698  		su.SetType(sym.SDYNIMPORT)
  2699  		l.SetSymElfType(s, elf.ST_TYPE(elfsym.Info))
  2700  		su.SetSize(int64(elfsym.Size))
  2701  		if elfsym.Section != elf.SHN_UNDEF {
  2702  			// Set .File for the library that actually defines the symbol.
  2703  			l.SetSymPkg(s, libpath)
  2704  
  2705  			// The decodetype_* functions in decodetype.go need access to
  2706  			// the type data.
  2707  			sname := l.SymName(s)
  2708  			if strings.HasPrefix(sname, "type:") && !strings.HasPrefix(sname, "type:.") {
  2709  				su.SetData(readelfsymboldata(ctxt, f, &elfsym))
  2710  			}
  2711  		}
  2712  
  2713  		if symname != elfsym.Name {
  2714  			l.SetSymExtname(s, elfsym.Name)
  2715  		}
  2716  		symAddr[elfsym.Name] = elfsym.Value
  2717  	}
  2718  
  2719  	// Load relocations.
  2720  	// We only really need these for grokking the links between type descriptors
  2721  	// when dynamic linking.
  2722  	relocTarget := map[uint64]string{}
  2723  	addends := false
  2724  	sect := f.SectionByType(elf.SHT_REL)
  2725  	if sect == nil {
  2726  		sect = f.SectionByType(elf.SHT_RELA)
  2727  		if sect == nil {
  2728  			log.Fatalf("can't find SHT_REL or SHT_RELA section of %s", shlib)
  2729  		}
  2730  		addends = true
  2731  	}
  2732  	// TODO: Multiple SHT_RELA/SHT_REL sections?
  2733  	data, err := sect.Data()
  2734  	if err != nil {
  2735  		log.Fatalf("can't read relocation section of %s: %v", shlib, err)
  2736  	}
  2737  	bo := f.ByteOrder
  2738  	for len(data) > 0 {
  2739  		var off, idx uint64
  2740  		var addend int64
  2741  		switch f.Class {
  2742  		case elf.ELFCLASS64:
  2743  			off = bo.Uint64(data)
  2744  			info := bo.Uint64(data[8:])
  2745  			data = data[16:]
  2746  			if addends {
  2747  				addend = int64(bo.Uint64(data))
  2748  				data = data[8:]
  2749  			}
  2750  
  2751  			idx = info >> 32
  2752  			typ := info & 0xffff
  2753  			// buildmode=shared is only supported for amd64,arm64,loong64,s390x,ppc64le.
  2754  			// (List found by looking at the translation of R_ADDR by ../$ARCH/asm.go:elfreloc1)
  2755  			switch typ {
  2756  			case uint64(elf.R_X86_64_64):
  2757  			case uint64(elf.R_AARCH64_ABS64):
  2758  			case uint64(elf.R_LARCH_64):
  2759  			case uint64(elf.R_390_64):
  2760  			case uint64(elf.R_PPC64_ADDR64):
  2761  			default:
  2762  				continue
  2763  			}
  2764  		case elf.ELFCLASS32:
  2765  			off = uint64(bo.Uint32(data))
  2766  			info := bo.Uint32(data[4:])
  2767  			data = data[8:]
  2768  			if addends {
  2769  				addend = int64(int32(bo.Uint32(data)))
  2770  				data = data[4:]
  2771  			}
  2772  
  2773  			idx = uint64(info >> 8)
  2774  			typ := info & 0xff
  2775  			// buildmode=shared is only supported for 386,arm.
  2776  			switch typ {
  2777  			case uint32(elf.R_386_32):
  2778  			case uint32(elf.R_ARM_ABS32):
  2779  			default:
  2780  				continue
  2781  			}
  2782  		default:
  2783  			log.Fatalf("unknown bit size %s", f.Class)
  2784  		}
  2785  		if addend != 0 {
  2786  			continue
  2787  		}
  2788  		relocTarget[off] = syms[idx-1].Name
  2789  	}
  2790  
  2791  	ctxt.Shlibs = append(ctxt.Shlibs, Shlib{Path: libpath, Hash: hash, Deps: deps, File: f, symAddr: symAddr, relocTarget: relocTarget})
  2792  }
  2793  
  2794  func addsection(ldr *loader.Loader, arch *sys.Arch, seg *sym.Segment, name string, rwx int) *sym.Section {
  2795  	sect := ldr.NewSection()
  2796  	sect.Rwx = uint8(rwx)
  2797  	sect.Name = name
  2798  	sect.Seg = seg
  2799  	sect.Align = int32(arch.PtrSize) // everything is at least pointer-aligned
  2800  	seg.Sections = append(seg.Sections, sect)
  2801  	return sect
  2802  }
  2803  
  2804  func usage() {
  2805  	fmt.Fprintf(os.Stderr, "usage: link [options] main.o\n")
  2806  	objabi.Flagprint(os.Stderr)
  2807  	Exit(2)
  2808  }
  2809  
  2810  type SymbolType int8 // TODO: after genasmsym is gone, maybe rename to plan9typeChar or something
  2811  
  2812  const (
  2813  	// see also https://9p.io/magic/man2html/1/nm
  2814  	TextSym      SymbolType = 'T'
  2815  	DataSym      SymbolType = 'D'
  2816  	BSSSym       SymbolType = 'B'
  2817  	UndefinedSym SymbolType = 'U'
  2818  	TLSSym       SymbolType = 't'
  2819  	FrameSym     SymbolType = 'm'
  2820  	ParamSym     SymbolType = 'p'
  2821  	AutoSym      SymbolType = 'a'
  2822  
  2823  	// Deleted auto (not a real sym, just placeholder for type)
  2824  	DeletedAutoSym = 'x'
  2825  )
  2826  
  2827  // defineInternal defines a symbol used internally by the go runtime.
  2828  func (ctxt *Link) defineInternal(p string, t sym.SymKind) loader.Sym {
  2829  	s := ctxt.loader.CreateSymForUpdate(p, 0)
  2830  	s.SetType(t)
  2831  	s.SetSpecial(true)
  2832  	s.SetLocal(true)
  2833  	return s.Sym()
  2834  }
  2835  
  2836  func (ctxt *Link) xdefine(p string, t sym.SymKind, v int64) loader.Sym {
  2837  	s := ctxt.defineInternal(p, t)
  2838  	ctxt.loader.SetSymValue(s, v)
  2839  	return s
  2840  }
  2841  
  2842  func datoff(ldr *loader.Loader, s loader.Sym, addr int64) int64 {
  2843  	if uint64(addr) >= Segdata.Vaddr {
  2844  		return int64(uint64(addr) - Segdata.Vaddr + Segdata.Fileoff)
  2845  	}
  2846  	if uint64(addr) >= Segtext.Vaddr {
  2847  		return int64(uint64(addr) - Segtext.Vaddr + Segtext.Fileoff)
  2848  	}
  2849  	ldr.Errorf(s, "invalid datoff %#x", addr)
  2850  	return 0
  2851  }
  2852  
  2853  func Entryvalue(ctxt *Link) int64 {
  2854  	a := *flagEntrySymbol
  2855  	if a[0] >= '0' && a[0] <= '9' {
  2856  		return atolwhex(a)
  2857  	}
  2858  	ldr := ctxt.loader
  2859  	s := ldr.Lookup(a, 0)
  2860  	if s == 0 {
  2861  		Errorf("missing entry symbol %q", a)
  2862  		return 0
  2863  	}
  2864  	st := ldr.SymType(s)
  2865  	if st == 0 {
  2866  		return *FlagTextAddr
  2867  	}
  2868  	if !ctxt.IsAIX() && !st.IsText() {
  2869  		ldr.Errorf(s, "entry not text")
  2870  	}
  2871  	return ldr.SymValue(s)
  2872  }
  2873  
  2874  func (ctxt *Link) callgraph() {
  2875  	if !*FlagC {
  2876  		return
  2877  	}
  2878  
  2879  	ldr := ctxt.loader
  2880  	for _, s := range ctxt.Textp {
  2881  		relocs := ldr.Relocs(s)
  2882  		for i := 0; i < relocs.Count(); i++ {
  2883  			r := relocs.At(i)
  2884  			rs := r.Sym()
  2885  			if rs == 0 {
  2886  				continue
  2887  			}
  2888  			if r.Type().IsDirectCall() && ldr.SymType(rs).IsText() {
  2889  				ctxt.Logf("%s calls %s\n", ldr.SymName(s), ldr.SymName(rs))
  2890  			}
  2891  		}
  2892  	}
  2893  }
  2894  
  2895  func Rnd(v int64, r int64) int64 {
  2896  	if r <= 0 {
  2897  		return v
  2898  	}
  2899  	v += r - 1
  2900  	c := v % r
  2901  	if c < 0 {
  2902  		c += r
  2903  	}
  2904  	v -= c
  2905  	return v
  2906  }
  2907  
  2908  func bgetc(r *bio.Reader) int {
  2909  	c, err := r.ReadByte()
  2910  	if err != nil {
  2911  		if err != io.EOF {
  2912  			log.Fatalf("reading input: %v", err)
  2913  		}
  2914  		return -1
  2915  	}
  2916  	return int(c)
  2917  }
  2918  
  2919  type markKind uint8 // for postorder traversal
  2920  const (
  2921  	_ markKind = iota
  2922  	visiting
  2923  	visited
  2924  )
  2925  
  2926  func postorder(libs []*sym.Library) []*sym.Library {
  2927  	order := make([]*sym.Library, 0, len(libs)) // hold the result
  2928  	mark := make(map[*sym.Library]markKind, len(libs))
  2929  	for _, lib := range libs {
  2930  		dfs(lib, mark, &order)
  2931  	}
  2932  	return order
  2933  }
  2934  
  2935  func dfs(lib *sym.Library, mark map[*sym.Library]markKind, order *[]*sym.Library) {
  2936  	if mark[lib] == visited {
  2937  		return
  2938  	}
  2939  	if mark[lib] == visiting {
  2940  		panic("found import cycle while visiting " + lib.Pkg)
  2941  	}
  2942  	mark[lib] = visiting
  2943  	for _, i := range lib.Imports {
  2944  		dfs(i, mark, order)
  2945  	}
  2946  	mark[lib] = visited
  2947  	*order = append(*order, lib)
  2948  }
  2949  
  2950  func ElfSymForReloc(ctxt *Link, s loader.Sym) int32 {
  2951  	// If putelfsym created a local version of this symbol, use that in all
  2952  	// relocations.
  2953  	les := ctxt.loader.SymLocalElfSym(s)
  2954  	if les != 0 {
  2955  		return les
  2956  	} else {
  2957  		return ctxt.loader.SymElfSym(s)
  2958  	}
  2959  }
  2960  
  2961  func AddGotSym(target *Target, ldr *loader.Loader, syms *ArchSyms, s loader.Sym, elfRelocTyp uint32) {
  2962  	if ldr.SymGot(s) >= 0 {
  2963  		return
  2964  	}
  2965  
  2966  	Adddynsym(ldr, target, syms, s)
  2967  	got := ldr.MakeSymbolUpdater(syms.GOT)
  2968  	ldr.SetGot(s, int32(got.Size()))
  2969  	got.AddUint(target.Arch, 0)
  2970  
  2971  	if target.IsElf() {
  2972  		if target.Arch.PtrSize == 8 {
  2973  			rela := ldr.MakeSymbolUpdater(syms.Rela)
  2974  			rela.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
  2975  			rela.AddUint64(target.Arch, elf.R_INFO(uint32(ldr.SymDynid(s)), elfRelocTyp))
  2976  			rela.AddUint64(target.Arch, 0)
  2977  		} else {
  2978  			rel := ldr.MakeSymbolUpdater(syms.Rel)
  2979  			rel.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
  2980  			rel.AddUint32(target.Arch, elf.R_INFO32(uint32(ldr.SymDynid(s)), elfRelocTyp))
  2981  		}
  2982  	} else if target.IsDarwin() {
  2983  		leg := ldr.MakeSymbolUpdater(syms.LinkEditGOT)
  2984  		leg.AddUint32(target.Arch, uint32(ldr.SymDynid(s)))
  2985  		if target.IsPIE() && target.IsInternal() {
  2986  			// Mach-O relocations are a royal pain to lay out.
  2987  			// They use a compact stateful bytecode representation.
  2988  			// Here we record what are needed and encode them later.
  2989  			MachoAddBind(int64(ldr.SymGot(s)), s)
  2990  		}
  2991  	} else {
  2992  		ldr.Errorf(s, "addgotsym: unsupported binary format")
  2993  	}
  2994  }
  2995  
  2996  var hostobjcounter int
  2997  
  2998  // captureHostObj writes out the content of a host object (pulled from
  2999  // an archive or loaded from a *.o file directly) to a directory
  3000  // specified via the linker's "-capturehostobjs" debugging flag. This
  3001  // is intended to make it easier for a developer to inspect the actual
  3002  // object feeding into "CGO internal" link step.
  3003  func captureHostObj(h *Hostobj) {
  3004  	// Form paths for info file and obj file.
  3005  	ofile := fmt.Sprintf("captured-obj-%d.o", hostobjcounter)
  3006  	ifile := fmt.Sprintf("captured-obj-%d.txt", hostobjcounter)
  3007  	hostobjcounter++
  3008  	opath := filepath.Join(*flagCaptureHostObjs, ofile)
  3009  	ipath := filepath.Join(*flagCaptureHostObjs, ifile)
  3010  
  3011  	// Write the info file.
  3012  	info := fmt.Sprintf("pkg: %s\npn: %s\nfile: %s\noff: %d\nlen: %d\n",
  3013  		h.pkg, h.pn, h.file, h.off, h.length)
  3014  	if err := os.WriteFile(ipath, []byte(info), 0666); err != nil {
  3015  		log.Fatalf("error writing captured host obj info %s: %v", ipath, err)
  3016  	}
  3017  
  3018  	readObjData := func() []byte {
  3019  		inf, err := os.Open(h.file)
  3020  		if err != nil {
  3021  			log.Fatalf("capturing host obj: open failed on %s: %v", h.pn, err)
  3022  		}
  3023  		defer inf.Close()
  3024  		res := make([]byte, h.length)
  3025  		if n, err := inf.ReadAt(res, h.off); err != nil || n != int(h.length) {
  3026  			log.Fatalf("capturing host obj: readat failed on %s: %v", h.pn, err)
  3027  		}
  3028  		return res
  3029  	}
  3030  
  3031  	// Write the object file.
  3032  	if err := os.WriteFile(opath, readObjData(), 0666); err != nil {
  3033  		log.Fatalf("error writing captured host object %s: %v", opath, err)
  3034  	}
  3035  
  3036  	fmt.Fprintf(os.Stderr, "link: info: captured host object %s to %s\n",
  3037  		h.file, opath)
  3038  }
  3039  
  3040  // findExtLinkTool invokes the external linker CC with --print-prog-name
  3041  // passing the name of the tool we're interested in, such as "strip",
  3042  // "ar", or "dsymutil", and returns the path passed back from the command.
  3043  func (ctxt *Link) findExtLinkTool(toolname string) string {
  3044  	var cc []string
  3045  	cc = append(cc, ctxt.extld()...)
  3046  	cc = append(cc, hostlinkArchArgs(ctxt.Arch)...)
  3047  	cc = append(cc, "--print-prog-name", toolname)
  3048  	out, err := exec.Command(cc[0], cc[1:]...).CombinedOutput()
  3049  	if err != nil {
  3050  		Exitf("%s: finding %s failed: %v\n%s", os.Args[0], toolname, err, out)
  3051  	}
  3052  	cmdpath := strings.TrimRight(string(out), "\r\n")
  3053  	return cmdpath
  3054  }
  3055  
  3056  // isMSVC reports whether the C toolchain is clang with a -msvc target,
  3057  // e.g. the clang bundled in MSVC.
  3058  func (ctxt *Link) isMSVC() bool {
  3059  	extld := ctxt.extld()
  3060  	name, args := extld[0], extld[1:]
  3061  	args = append(args, trimLinkerArgv(flagExtldflags)...)
  3062  	args = append(args, "--version")
  3063  	cmd := exec.Command(name, args...)
  3064  	if out, err := cmd.CombinedOutput(); err == nil {
  3065  		if bytes.Contains(out, []byte("-msvc\n")) || bytes.Contains(out, []byte("-msvc\r")) {
  3066  			return true
  3067  		}
  3068  	}
  3069  	return false
  3070  }
  3071  

View as plain text