...

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

Documentation: cmd/link/internal/ld

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

View as plain text