2015-02-27 22:57:28 -05:00
|
|
|
|
// Inferno utils/8l/asm.c
|
2020-06-03 13:17:17 +02:00
|
|
|
|
// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/8l/asm.c
|
2015-02-27 22:57:28 -05:00
|
|
|
|
//
|
|
|
|
|
|
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
|
|
|
|
|
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
|
|
|
|
|
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
|
|
|
|
|
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
|
|
|
|
|
// Portions Copyright © 2004,2006 Bruce Ellis
|
|
|
|
|
|
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
|
|
|
|
|
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
2016-04-10 14:32:26 -07:00
|
|
|
|
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
2015-02-27 22:57:28 -05:00
|
|
|
|
//
|
|
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
|
|
|
|
// in the Software without restriction, including without limitation the rights
|
|
|
|
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
|
|
|
|
// furnished to do so, subject to the following conditions:
|
|
|
|
|
|
//
|
|
|
|
|
|
// The above copyright notice and this permission notice shall be included in
|
|
|
|
|
|
// all copies or substantial portions of the Software.
|
|
|
|
|
|
//
|
|
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
|
|
// THE SOFTWARE.
|
|
|
|
|
|
|
|
|
|
|
|
package ld
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"bytes"
|
2015-04-01 14:57:34 +13:00
|
|
|
|
"debug/elf"
|
2019-03-20 20:10:38 +01:00
|
|
|
|
"debug/macho"
|
2017-09-30 12:36:34 +00:00
|
|
|
|
"encoding/base64"
|
2015-05-25 13:59:08 +12:00
|
|
|
|
"encoding/binary"
|
2015-02-27 22:57:28 -05:00
|
|
|
|
"fmt"
|
2021-04-15 23:05:49 -04:00
|
|
|
|
"internal/buildcfg"
|
2015-04-08 16:49:43 -04:00
|
|
|
|
"io"
|
2015-02-27 22:57:28 -05:00
|
|
|
|
"log"
|
|
|
|
|
|
"os"
|
2022-01-27 13:10:48 -05:00
|
|
|
|
"os/exec"
|
2015-04-01 14:57:34 +13:00
|
|
|
|
"path/filepath"
|
2015-07-15 09:05:33 -07:00
|
|
|
|
"runtime"
|
2024-09-12 14:47:32 +02:00
|
|
|
|
"slices"
|
2023-07-12 16:54:32 -04:00
|
|
|
|
"sort"
|
2015-02-27 22:57:28 -05:00
|
|
|
|
"strings"
|
2015-10-28 14:41:58 -04:00
|
|
|
|
"sync"
|
2024-05-14 14:59:03 +00:00
|
|
|
|
"time"
|
2022-08-28 03:38:00 +08:00
|
|
|
|
|
|
|
|
|
|
"cmd/internal/bio"
|
|
|
|
|
|
"cmd/internal/goobj"
|
2024-09-04 18:30:35 +07:00
|
|
|
|
"cmd/internal/hash"
|
2022-08-28 03:38:00 +08:00
|
|
|
|
"cmd/internal/objabi"
|
|
|
|
|
|
"cmd/internal/sys"
|
|
|
|
|
|
"cmd/link/internal/loadelf"
|
|
|
|
|
|
"cmd/link/internal/loader"
|
|
|
|
|
|
"cmd/link/internal/loadmacho"
|
|
|
|
|
|
"cmd/link/internal/loadpe"
|
|
|
|
|
|
"cmd/link/internal/loadxcoff"
|
|
|
|
|
|
"cmd/link/internal/sym"
|
2015-02-27 22:57:28 -05:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// Data layout and relocation.
|
|
|
|
|
|
|
|
|
|
|
|
// Derived from Inferno utils/6l/l.h
|
2020-06-03 13:17:17 +02:00
|
|
|
|
// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h
|
2015-02-27 22:57:28 -05:00
|
|
|
|
//
|
|
|
|
|
|
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
|
|
|
|
|
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
|
|
|
|
|
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
|
|
|
|
|
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
|
|
|
|
|
// Portions Copyright © 2004,2006 Bruce Ellis
|
|
|
|
|
|
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
|
|
|
|
|
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
2016-04-10 14:32:26 -07:00
|
|
|
|
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
2015-02-27 22:57:28 -05:00
|
|
|
|
//
|
|
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
|
|
|
|
// in the Software without restriction, including without limitation the rights
|
|
|
|
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
|
|
|
|
// furnished to do so, subject to the following conditions:
|
|
|
|
|
|
//
|
|
|
|
|
|
// The above copyright notice and this permission notice shall be included in
|
|
|
|
|
|
// all copies or substantial portions of the Software.
|
|
|
|
|
|
//
|
|
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
|
|
// THE SOFTWARE.
|
|
|
|
|
|
|
2020-02-24 21:06:21 -05:00
|
|
|
|
// ArchSyms holds a number of architecture specific symbols used during
|
|
|
|
|
|
// relocation. Rather than allowing them universal access to all symbols,
|
|
|
|
|
|
// we keep a subset for relocation application.
|
|
|
|
|
|
type ArchSyms struct {
|
2020-05-15 18:35:05 -04:00
|
|
|
|
Rel loader.Sym
|
|
|
|
|
|
Rela loader.Sym
|
|
|
|
|
|
RelPLT loader.Sym
|
|
|
|
|
|
RelaPLT loader.Sym
|
2020-03-30 10:05:23 -04:00
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
|
LinkEditGOT loader.Sym
|
|
|
|
|
|
LinkEditPLT loader.Sym
|
2020-03-30 10:05:23 -04:00
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
|
TOC loader.Sym
|
|
|
|
|
|
DotTOC []loader.Sym // for each version
|
2020-03-18 13:26:38 -04:00
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
|
GOT loader.Sym
|
|
|
|
|
|
PLT loader.Sym
|
|
|
|
|
|
GOTPLT loader.Sym
|
2020-03-18 13:26:38 -04:00
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
|
Tlsg loader.Sym
|
2020-05-14 16:05:29 -04:00
|
|
|
|
Tlsoffset int
|
2020-03-18 13:26:38 -04:00
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
|
Dynamic loader.Sym
|
|
|
|
|
|
DynSym loader.Sym
|
|
|
|
|
|
DynStr loader.Sym
|
2020-11-08 15:18:35 -05:00
|
|
|
|
|
|
|
|
|
|
unreachableMethod loader.Sym
|
2023-01-12 20:25:39 -08:00
|
|
|
|
|
|
|
|
|
|
// Symbol containing a list of all the inittasks that need
|
|
|
|
|
|
// to be run at startup.
|
|
|
|
|
|
mainInittasks loader.Sym
|
2020-02-24 21:06:21 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-05-14 16:05:29 -04:00
|
|
|
|
// mkArchSym is a helper for setArchSyms, to set up a special symbol.
|
|
|
|
|
|
func (ctxt *Link) mkArchSym(name string, ver int, ls *loader.Sym) {
|
|
|
|
|
|
*ls = ctxt.loader.LookupOrCreateSym(name, ver)
|
2020-07-10 14:54:13 -04:00
|
|
|
|
ctxt.loader.SetAttrReachable(*ls, true)
|
2020-03-30 10:05:23 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-01-29 14:40:22 +08:00
|
|
|
|
// mkArchSymVec is similar to setArchSyms, but operates on elements within
|
2020-04-05 12:40:20 -04:00
|
|
|
|
// a slice, where each element corresponds to some symbol version.
|
2020-05-14 16:05:29 -04:00
|
|
|
|
func (ctxt *Link) mkArchSymVec(name string, ver int, ls []loader.Sym) {
|
|
|
|
|
|
ls[ver] = ctxt.loader.LookupOrCreateSym(name, ver)
|
2020-07-10 14:54:13 -04:00
|
|
|
|
ctxt.loader.SetAttrReachable(ls[ver], true)
|
2020-03-30 10:05:23 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-02-24 21:06:21 -05:00
|
|
|
|
// setArchSyms sets up the ArchSyms structure, and must be called before
|
2020-05-14 20:20:20 -04:00
|
|
|
|
// relocations are applied.
|
2020-05-14 16:05:29 -04:00
|
|
|
|
func (ctxt *Link) setArchSyms() {
|
2020-05-15 18:35:05 -04:00
|
|
|
|
ctxt.mkArchSym(".got", 0, &ctxt.GOT)
|
|
|
|
|
|
ctxt.mkArchSym(".plt", 0, &ctxt.PLT)
|
|
|
|
|
|
ctxt.mkArchSym(".got.plt", 0, &ctxt.GOTPLT)
|
|
|
|
|
|
ctxt.mkArchSym(".dynamic", 0, &ctxt.Dynamic)
|
|
|
|
|
|
ctxt.mkArchSym(".dynsym", 0, &ctxt.DynSym)
|
|
|
|
|
|
ctxt.mkArchSym(".dynstr", 0, &ctxt.DynStr)
|
2021-09-21 14:35:37 -04:00
|
|
|
|
ctxt.mkArchSym("runtime.unreachableMethod", abiInternalVer, &ctxt.unreachableMethod)
|
2020-03-13 17:02:31 -04:00
|
|
|
|
|
2020-04-05 12:40:20 -04:00
|
|
|
|
if ctxt.IsPPC64() {
|
2020-05-15 18:35:05 -04:00
|
|
|
|
ctxt.mkArchSym("TOC", 0, &ctxt.TOC)
|
2020-03-30 10:05:23 -04:00
|
|
|
|
|
2021-03-23 15:52:49 -05:00
|
|
|
|
ctxt.DotTOC = make([]loader.Sym, ctxt.MaxVersion()+1)
|
2020-05-21 16:35:24 -04:00
|
|
|
|
for i := 0; i <= ctxt.MaxVersion(); i++ {
|
2021-03-23 15:52:49 -05:00
|
|
|
|
if i >= sym.SymVerABICount && i < sym.SymVerStatic { // these versions are not used currently
|
2020-03-13 17:02:31 -04:00
|
|
|
|
continue
|
|
|
|
|
|
}
|
2020-05-15 18:35:05 -04:00
|
|
|
|
ctxt.mkArchSymVec(".TOC.", i, ctxt.DotTOC)
|
2020-03-13 17:02:31 -04:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2020-03-04 17:25:01 -05:00
|
|
|
|
if ctxt.IsElf() {
|
2020-05-15 18:35:05 -04:00
|
|
|
|
ctxt.mkArchSym(".rel", 0, &ctxt.Rel)
|
|
|
|
|
|
ctxt.mkArchSym(".rela", 0, &ctxt.Rela)
|
|
|
|
|
|
ctxt.mkArchSym(".rel.plt", 0, &ctxt.RelPLT)
|
|
|
|
|
|
ctxt.mkArchSym(".rela.plt", 0, &ctxt.RelaPLT)
|
2020-03-04 17:25:01 -05:00
|
|
|
|
}
|
|
|
|
|
|
if ctxt.IsDarwin() {
|
2020-05-15 18:35:05 -04:00
|
|
|
|
ctxt.mkArchSym(".linkedit.got", 0, &ctxt.LinkEditGOT)
|
|
|
|
|
|
ctxt.mkArchSym(".linkedit.plt", 0, &ctxt.LinkEditPLT)
|
2020-03-04 17:25:01 -05:00
|
|
|
|
}
|
2020-02-24 21:06:21 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2015-02-27 22:57:28 -05:00
|
|
|
|
type Arch struct {
|
cmd/link: use a two-pass approach for trampoline insertion
Currently in the linker, for trampoline insertion it does a one-pass
approach, where it assigns addresses for each function and inserts
trampolines on the go. For this to work and not to emit too many
unnecessary trampolines, the functions need to be laid out in
dependency order, so a direct call's target is always as a known
address (or known to be not too far).
This mostly works, but there are a few exceptions:
- linkname can break dependency tree and cause cycles.
- in internal linking mode, on some platforms, some calls are turned
into calls via PLT, but the PLT stubs are inserted rather late.
Also, this is expensive in that it has to investigate all CALL
relocations.
This CL changes it to use a two-pass approach. The first pass is
just to assign addresses without inserting any trampolines, assuming
the program is not too big. If this succeeds, no extra work needs to
be done. If this fails, start over and insert trampolines for too-
far targets as well as targets with unknown addresses. This should
make it faster for small programs (most cases) and generate fewer
conservative trampolines.
Change-Id: Ib13e01f38ec6dfbef1cd446b06da33ee17bded5d
Reviewed-on: https://go-review.googlesource.com/c/go/+/314450
Trust: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
2021-04-26 19:26:34 -04:00
|
|
|
|
Funcalign int
|
|
|
|
|
|
Maxalign int
|
|
|
|
|
|
Minalign int
|
|
|
|
|
|
Dwarfregsp int
|
|
|
|
|
|
Dwarfreglr int
|
|
|
|
|
|
|
|
|
|
|
|
// Threshold of total text size, used for trampoline insertion. If the total
|
|
|
|
|
|
// text size is smaller than TrampLimit, we won't need to insert trampolines.
|
|
|
|
|
|
// It is pretty close to the offset range of a direct CALL machine instruction.
|
|
|
|
|
|
// We leave some room for extra stuff like PLT stubs.
|
|
|
|
|
|
TrampLimit uint64
|
|
|
|
|
|
|
2020-05-20 15:10:05 -04:00
|
|
|
|
// Empty spaces between codeblocks will be padded with this value.
|
|
|
|
|
|
// For example an architecture might want to pad with a trap instruction to
|
|
|
|
|
|
// catch wayward programs. Architectures that do not define a padding value
|
|
|
|
|
|
// are padded with zeros.
|
|
|
|
|
|
CodePad []byte
|
|
|
|
|
|
|
2020-05-21 20:20:26 -04:00
|
|
|
|
// Plan 9 variables.
|
|
|
|
|
|
Plan9Magic uint32
|
|
|
|
|
|
Plan9_64Bit bool
|
|
|
|
|
|
|
2020-07-29 13:26:50 -04:00
|
|
|
|
Adddynrel func(*Target, *loader.Loader, *ArchSyms, loader.Sym, loader.Reloc, int) bool
|
2020-05-20 15:10:05 -04:00
|
|
|
|
Archinit func(*Link)
|
2020-04-29 12:20:38 -04:00
|
|
|
|
// Archreloc is an arch-specific hook that assists in relocation processing
|
|
|
|
|
|
// (invoked by 'relocsym'); it handles target-specific relocation tasks.
|
|
|
|
|
|
// Here "rel" is the current relocation being examined, "sym" is the symbol
|
|
|
|
|
|
// containing the chunk of data to which the relocation applies, and "off"
|
|
|
|
|
|
// is the contents of the to-be-relocated data item (from sym.P). Return
|
|
|
|
|
|
// value is the appropriately relocated value (to be written back to the
|
2020-07-04 18:14:08 -04:00
|
|
|
|
// same spot in sym.P), number of external _host_ relocations needed (i.e.
|
2023-01-30 12:09:33 -08:00
|
|
|
|
// ELF/Mach-O/etc. relocations, not Go relocations, this must match ELF.Reloc1,
|
2020-07-04 18:14:08 -04:00
|
|
|
|
// etc.), and a boolean indicating success/failure (a failing value indicates
|
|
|
|
|
|
// a fatal error).
|
2020-07-29 13:26:50 -04:00
|
|
|
|
Archreloc func(*Target, *loader.Loader, *ArchSyms, loader.Reloc, loader.Sym,
|
2020-07-24 01:33:15 -04:00
|
|
|
|
int64) (relocatedOffset int64, nExtReloc int, ok bool)
|
2018-07-06 12:45:03 -04:00
|
|
|
|
// Archrelocvariant is a second arch-specific hook used for
|
|
|
|
|
|
// relocation processing; it handles relocations where r.Type is
|
|
|
|
|
|
// insufficient to describe the relocation (r.Variant !=
|
|
|
|
|
|
// sym.RV_NONE). Here "rel" is the relocation being applied, "sym"
|
|
|
|
|
|
// is the symbol containing the chunk of data to which the
|
|
|
|
|
|
// relocation applies, and "off" is the contents of the
|
|
|
|
|
|
// to-be-relocated data item (from sym.P). Return is an updated
|
|
|
|
|
|
// offset value.
|
2020-07-29 13:26:50 -04:00
|
|
|
|
Archrelocvariant func(target *Target, ldr *loader.Loader, rel loader.Reloc,
|
2021-03-10 15:10:05 -06:00
|
|
|
|
rv sym.RelocVariant, sym loader.Sym, offset int64, data []byte) (relocatedOffset int64)
|
2020-04-06 15:58:21 -04:00
|
|
|
|
|
|
|
|
|
|
// Generate a trampoline for a call from s to rs if necessary. ri is
|
|
|
|
|
|
// index of the relocation.
|
|
|
|
|
|
Trampoline func(ctxt *Link, ldr *loader.Loader, ri int, rs, s loader.Sym)
|
2019-04-03 22:41:48 -04:00
|
|
|
|
|
2020-05-20 15:10:05 -04:00
|
|
|
|
// Assembling the binary breaks into two phases, writing the code/data/
|
|
|
|
|
|
// dwarf information (which is rather generic), and some more architecture
|
|
|
|
|
|
// specific work like setting up the elf headers/dynamic relocations, etc.
|
|
|
|
|
|
// The phases are called "Asmb" and "Asmb2". Asmb2 needs to be defined for
|
|
|
|
|
|
// every architecture, but only if architecture has an Asmb function will
|
|
|
|
|
|
// it be used for assembly. Otherwise a generic assembly Asmb function is
|
|
|
|
|
|
// used.
|
2020-04-28 09:53:29 -04:00
|
|
|
|
Asmb func(*Link, *loader.Loader)
|
2020-05-08 14:09:57 -04:00
|
|
|
|
Asmb2 func(*Link, *loader.Loader)
|
2019-04-03 22:41:48 -04:00
|
|
|
|
|
2020-07-17 17:56:17 -04:00
|
|
|
|
// Extreloc is an arch-specific hook that converts a Go relocation to an
|
|
|
|
|
|
// external relocation. Return the external relocation and whether it is
|
|
|
|
|
|
// needed.
|
2020-07-29 13:26:50 -04:00
|
|
|
|
Extreloc func(*Target, *loader.Loader, loader.Reloc, loader.Sym) (loader.ExtReloc, bool)
|
2020-07-17 17:56:17 -04:00
|
|
|
|
|
2020-08-14 00:13:28 +10:00
|
|
|
|
Gentext func(*Link, *loader.Loader) // Generate text before addressing has been performed.
|
2020-07-28 21:35:53 -04:00
|
|
|
|
Machoreloc1 func(*sys.Arch, *OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool
|
2020-07-06 18:44:42 -04:00
|
|
|
|
MachorelocSize uint32 // size of an Mach-O relocation record, must match Machoreloc1.
|
2020-07-28 21:35:53 -04:00
|
|
|
|
PEreloc1 func(*sys.Arch, *OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool
|
|
|
|
|
|
Xcoffreloc1 func(*sys.Arch, *OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool
|
2016-09-06 07:46:59 -04:00
|
|
|
|
|
2020-08-14 00:13:28 +10:00
|
|
|
|
// Generate additional symbols for the native symbol table just prior to
|
|
|
|
|
|
// code generation.
|
|
|
|
|
|
GenSymsLate func(*Link, *loader.Loader)
|
|
|
|
|
|
|
2016-09-06 07:46:59 -04:00
|
|
|
|
// TLSIEtoLE converts a TLS Initial Executable relocation to
|
|
|
|
|
|
// a TLS Local Executable relocation.
|
|
|
|
|
|
//
|
|
|
|
|
|
// This is possible when a TLS IE relocation refers to a local
|
|
|
|
|
|
// symbol in an executable, which is typical when internally
|
|
|
|
|
|
// linking PIE binaries.
|
2020-04-25 22:08:50 -04:00
|
|
|
|
TLSIEtoLE func(P []byte, off, size int)
|
2018-03-04 12:59:15 +01:00
|
|
|
|
|
|
|
|
|
|
// optional override for assignAddress
|
2020-04-06 15:58:21 -04:00
|
|
|
|
AssignAddress func(ldr *loader.Loader, sect *sym.Section, n int, s loader.Sym, va uint64, isTramp bool) (*sym.Section, int, uint64)
|
2023-01-27 12:01:38 -08:00
|
|
|
|
|
|
|
|
|
|
// ELF specific information.
|
|
|
|
|
|
ELF ELFArch
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2015-03-07 16:28:07 +13:00
|
|
|
|
var (
|
2018-04-01 00:58:48 +03:00
|
|
|
|
thearch Arch
|
2020-05-26 14:59:40 -04:00
|
|
|
|
lcSize int32
|
2015-04-12 02:31:28 +02:00
|
|
|
|
rpath Rpath
|
2020-05-26 14:59:40 -04:00
|
|
|
|
spSize int32
|
|
|
|
|
|
symSize int32
|
2015-03-07 16:28:07 +13:00
|
|
|
|
)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
2021-09-21 14:35:37 -04:00
|
|
|
|
// Symbol version of ABIInternal symbols. It is sym.SymVerABIInternal if ABI wrappers
|
|
|
|
|
|
// are used, 0 otherwise.
|
|
|
|
|
|
var abiInternalVer = sym.SymVerABIInternal
|
|
|
|
|
|
|
2018-11-22 11:46:44 +01:00
|
|
|
|
// DynlinkingGo reports whether we are producing Go code that can live
|
2015-03-30 02:59:10 +00:00
|
|
|
|
// in separate shared libraries linked together at runtime.
|
2016-08-25 21:06:10 -04:00
|
|
|
|
func (ctxt *Link) DynlinkingGo() bool {
|
2016-08-25 21:58:45 -04:00
|
|
|
|
if !ctxt.Loaded {
|
|
|
|
|
|
panic("DynlinkingGo called before all symbols loaded")
|
|
|
|
|
|
}
|
2019-09-04 11:25:06 -04:00
|
|
|
|
return ctxt.BuildMode == BuildModeShared || ctxt.linkShared || ctxt.BuildMode == BuildModePlugin || ctxt.canUsePlugins
|
2017-08-15 14:34:53 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-22 11:46:44 +01:00
|
|
|
|
// CanUsePlugins reports whether a plugins can be used
|
2017-08-15 14:34:53 -04:00
|
|
|
|
func (ctxt *Link) CanUsePlugins() bool {
|
2019-09-04 11:25:06 -04:00
|
|
|
|
if !ctxt.Loaded {
|
|
|
|
|
|
panic("CanUsePlugins called before all symbols loaded")
|
|
|
|
|
|
}
|
|
|
|
|
|
return ctxt.canUsePlugins
|
2015-03-30 02:59:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-11-21 20:11:03 -05:00
|
|
|
|
// NeedCodeSign reports whether we need to code-sign the output binary.
|
|
|
|
|
|
func (ctxt *Link) NeedCodeSign() bool {
|
|
|
|
|
|
return ctxt.IsDarwin() && ctxt.IsARM64()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-03-07 16:28:07 +13:00
|
|
|
|
var (
|
2016-08-21 18:34:24 -04:00
|
|
|
|
dynlib []string
|
|
|
|
|
|
ldflag []string
|
|
|
|
|
|
havedynamic int
|
|
|
|
|
|
Funcalign int
|
|
|
|
|
|
iscgo bool
|
|
|
|
|
|
elfglobalsymndx int
|
2016-08-22 22:29:24 -07:00
|
|
|
|
interpreter string
|
2016-08-21 18:34:24 -04:00
|
|
|
|
|
2017-10-07 13:49:44 -04:00
|
|
|
|
debug_s bool // backup old value of debug['s']
|
|
|
|
|
|
HEADR int32
|
2016-08-21 18:34:24 -04:00
|
|
|
|
|
|
|
|
|
|
nerrors int
|
2021-10-01 12:21:36 -04:00
|
|
|
|
liveness int64 // size of liveness data (funcdata), printed if -v
|
2019-03-26 12:02:36 -04:00
|
|
|
|
|
|
|
|
|
|
// See -strictdups command line flag.
|
|
|
|
|
|
checkStrictDups int // 0=off 1=warning 2=error
|
|
|
|
|
|
strictDupMsgCount int
|
2015-03-07 16:28:07 +13:00
|
|
|
|
)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
2015-03-07 16:28:07 +13:00
|
|
|
|
var (
|
2017-10-04 17:54:04 -04:00
|
|
|
|
Segtext sym.Segment
|
|
|
|
|
|
Segrodata sym.Segment
|
|
|
|
|
|
Segrelrodata sym.Segment
|
|
|
|
|
|
Segdata sym.Segment
|
|
|
|
|
|
Segdwarf sym.Segment
|
2023-01-17 08:15:33 +01:00
|
|
|
|
Segpdata sym.Segment // windows-only
|
2023-01-12 15:47:19 +01:00
|
|
|
|
Segxdata sym.Segment // windows-only
|
[dev.link] cmd/link: emit ELF relocations in mmap
Currently, ELF relocations are generated sequentially in the heap
and flushed to output file periodically. In fact, in some cases,
the output size of the relocation records can be easily computed,
as a relocation entry has fixed size. We only need to count the
number of relocation records to compute the size.
Once the size is computed, we can mmap the output with the proper
size, and directly write relocation records in the mapped memory.
It also opens the possibility of writing relocations in parallel
(not done in this CL).
Note: on some architectures, a Go relocation may turn into
multiple ELF relocations, which makes size calculation harder.
This CL does not handle those cases, and it still writes
sequentially in the heap there.
Linking cmd/compile with external linking,
name old time/op new time/op delta
Asmb2 190ms ± 2% 141ms ± 4% -25.74% (p=0.000 n=10+10)
name old alloc/op new alloc/op delta
Asmb2_GC 66.8MB ± 0% 8.2MB ± 0% -87.79% (p=0.008 n=5+5)
name old live-B new live-B delta
Asmb2_GC 66.9M ± 0% 55.2M ± 0% -17.58% (p=0.008 n=5+5)
Change-Id: If7056bbe909dc90033eef6b9c4891fcca310602c
Reviewed-on: https://go-review.googlesource.com/c/go/+/240399
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
2020-06-26 16:35:49 -04:00
|
|
|
|
|
2023-01-12 15:47:19 +01:00
|
|
|
|
Segments = []*sym.Segment{&Segtext, &Segrodata, &Segrelrodata, &Segdata, &Segdwarf, &Segpdata, &Segxdata}
|
2015-03-07 16:28:07 +13:00
|
|
|
|
)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
2017-08-28 15:10:25 +09:00
|
|
|
|
const pkgdef = "__.PKGDEF"
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
2015-03-07 16:28:07 +13:00
|
|
|
|
var (
|
2021-05-25 16:31:41 -07:00
|
|
|
|
// externalobj is set to true if we see an object compiled by
|
|
|
|
|
|
// the host compiler that is not from a package that is known
|
|
|
|
|
|
// to support internal linking mode.
|
2015-03-07 16:28:07 +13:00
|
|
|
|
externalobj = false
|
2021-05-25 16:31:41 -07:00
|
|
|
|
|
2022-06-21 18:11:32 -07:00
|
|
|
|
// dynimportfail is a list of packages for which generating
|
|
|
|
|
|
// the dynimport file, _cgo_import.go, failed. If there are
|
|
|
|
|
|
// any of these objects, we must link externally. Issue 52863.
|
|
|
|
|
|
dynimportfail []string
|
|
|
|
|
|
|
2023-03-10 10:29:38 -05:00
|
|
|
|
// preferlinkext is a list of packages for which the Go command
|
|
|
|
|
|
// noticed use of peculiar C flags. If we see any of these,
|
|
|
|
|
|
// default to linking externally unless overridden by the
|
|
|
|
|
|
// user. See issues #58619, #58620, and #58848.
|
|
|
|
|
|
preferlinkext []string
|
|
|
|
|
|
|
2021-05-25 16:31:41 -07:00
|
|
|
|
// unknownObjFormat is set to true if we see an object whose
|
|
|
|
|
|
// format we don't recognize.
|
|
|
|
|
|
unknownObjFormat = false
|
|
|
|
|
|
|
|
|
|
|
|
theline string
|
2015-03-07 16:28:07 +13:00
|
|
|
|
)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
2016-08-19 22:40:38 -04:00
|
|
|
|
func Lflag(ctxt *Link, arg string) {
|
|
|
|
|
|
ctxt.Libdir = append(ctxt.Libdir, arg)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* Unix doesn't like it when we write to a running (or, sometimes,
|
|
|
|
|
|
* recently run) binary, so remove the output file before writing it.
|
|
|
|
|
|
* On Windows 7, remove() can force a subsequent create() to fail.
|
|
|
|
|
|
* S_ISREG() does not exist on Plan 9.
|
|
|
|
|
|
*/
|
|
|
|
|
|
func mayberemoveoutfile() {
|
2016-08-21 18:34:24 -04:00
|
|
|
|
if fi, err := os.Lstat(*flagOutfile); err == nil && !fi.Mode().IsRegular() {
|
2015-02-27 22:57:28 -05:00
|
|
|
|
return
|
|
|
|
|
|
}
|
2016-08-21 18:34:24 -04:00
|
|
|
|
os.Remove(*flagOutfile)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-08-19 22:40:38 -04:00
|
|
|
|
func libinit(ctxt *Link) {
|
2025-03-26 18:47:15 +03:00
|
|
|
|
if *FlagFuncAlign != 0 {
|
|
|
|
|
|
Funcalign = *FlagFuncAlign
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Funcalign = thearch.Funcalign
|
|
|
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
|
|
|
|
|
// add goroot to the end of the libdir list.
|
2015-03-02 12:35:15 -05:00
|
|
|
|
suffix := ""
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
2015-03-02 12:35:15 -05:00
|
|
|
|
suffixsep := ""
|
2016-08-21 18:34:24 -04:00
|
|
|
|
if *flagInstallSuffix != "" {
|
2015-02-27 22:57:28 -05:00
|
|
|
|
suffixsep = "_"
|
2016-08-21 18:34:24 -04:00
|
|
|
|
suffix = *flagInstallSuffix
|
|
|
|
|
|
} else if *flagRace {
|
2015-02-27 22:57:28 -05:00
|
|
|
|
suffixsep = "_"
|
|
|
|
|
|
suffix = "race"
|
2016-08-21 18:34:24 -04:00
|
|
|
|
} else if *flagMsan {
|
2015-10-21 07:11:01 -07:00
|
|
|
|
suffixsep = "_"
|
|
|
|
|
|
suffix = "msan"
|
2021-01-04 16:23:01 +08:00
|
|
|
|
} else if *flagAsan {
|
|
|
|
|
|
suffixsep = "_"
|
|
|
|
|
|
suffix = "asan"
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-03-15 16:31:02 -04:00
|
|
|
|
if buildcfg.GOROOT != "" {
|
|
|
|
|
|
Lflag(ctxt, filepath.Join(buildcfg.GOROOT, "pkg", fmt.Sprintf("%s_%s%s%s", buildcfg.GOOS, buildcfg.GOARCH, suffixsep, suffix)))
|
|
|
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
|
|
|
|
|
mayberemoveoutfile()
|
2020-03-17 10:24:40 -04:00
|
|
|
|
|
|
|
|
|
|
if err := ctxt.Out.Open(*flagOutfile); err != nil {
|
2016-08-21 18:34:24 -04:00
|
|
|
|
Exitf("cannot create %s: %v", *flagOutfile, err)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-08-21 18:34:24 -04:00
|
|
|
|
if *flagEntrySymbol == "" {
|
2017-10-05 10:20:17 -04:00
|
|
|
|
switch ctxt.BuildMode {
|
|
|
|
|
|
case BuildModeCShared, BuildModeCArchive:
|
2021-04-15 23:05:49 -04:00
|
|
|
|
*flagEntrySymbol = fmt.Sprintf("_rt0_%s_%s_lib", buildcfg.GOARCH, buildcfg.GOOS)
|
2017-10-05 10:20:17 -04:00
|
|
|
|
case BuildModeExe, BuildModePIE:
|
2021-04-15 23:05:49 -04:00
|
|
|
|
*flagEntrySymbol = fmt.Sprintf("_rt0_%s_%s", buildcfg.GOARCH, buildcfg.GOOS)
|
2017-10-05 10:20:17 -04:00
|
|
|
|
case BuildModeShared, BuildModePlugin:
|
2016-08-25 21:58:45 -04:00
|
|
|
|
// No *flagEntrySymbol for -buildmode=shared and plugin
|
2015-03-27 02:48:27 +00:00
|
|
|
|
default:
|
2024-11-01 14:56:25 -04:00
|
|
|
|
Errorf("unknown *flagEntrySymbol for buildmode %v", ctxt.BuildMode)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-10-28 11:51:13 -04:00
|
|
|
|
func exitIfErrors() {
|
|
|
|
|
|
if nerrors != 0 || checkStrictDups > 1 && strictDupMsgCount > 0 {
|
|
|
|
|
|
mayberemoveoutfile()
|
2019-03-26 12:02:36 -04:00
|
|
|
|
Exit(2)
|
|
|
|
|
|
}
|
2019-10-28 11:51:13 -04:00
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func errorexit() {
|
|
|
|
|
|
exitIfErrors()
|
2015-02-27 22:57:28 -05:00
|
|
|
|
Exit(0)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-10-04 18:13:35 -04:00
|
|
|
|
func loadinternal(ctxt *Link, name string) *sym.Library {
|
2020-08-02 19:36:28 -04:00
|
|
|
|
zerofp := goobj.FingerprintType{}
|
2017-10-07 13:28:51 -04:00
|
|
|
|
if ctxt.linkShared && ctxt.PackageShlib != nil {
|
2017-06-09 11:15:53 -04:00
|
|
|
|
if shlib := ctxt.PackageShlib[name]; shlib != "" {
|
2020-04-22 22:20:44 -04:00
|
|
|
|
return addlibpath(ctxt, "internal", "internal", "", name, shlib, zerofp)
|
2017-05-31 11:35:29 -04:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if ctxt.PackageFile != nil {
|
|
|
|
|
|
if pname := ctxt.PackageFile[name]; pname != "" {
|
2020-04-22 22:20:44 -04:00
|
|
|
|
return addlibpath(ctxt, "internal", "internal", pname, name, "", zerofp)
|
2017-05-31 11:35:29 -04:00
|
|
|
|
}
|
|
|
|
|
|
ctxt.Logf("loadinternal: cannot find %s\n", name)
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-04-06 21:41:06 +01:00
|
|
|
|
for _, libdir := range ctxt.Libdir {
|
2017-10-07 13:28:51 -04:00
|
|
|
|
if ctxt.linkShared {
|
2018-04-06 21:41:06 +01:00
|
|
|
|
shlibname := filepath.Join(libdir, name+".shlibname")
|
2016-08-21 18:25:28 -04:00
|
|
|
|
if ctxt.Debugvlog != 0 {
|
2016-08-25 12:32:42 +10:00
|
|
|
|
ctxt.Logf("searching for %s.a in %s\n", name, shlibname)
|
2015-04-01 14:57:34 +13:00
|
|
|
|
}
|
2015-09-07 15:00:52 +12:00
|
|
|
|
if _, err := os.Stat(shlibname); err == nil {
|
2020-04-22 22:20:44 -04:00
|
|
|
|
return addlibpath(ctxt, "internal", "internal", "", name, shlibname, zerofp)
|
2015-04-01 14:57:34 +13:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2018-04-06 21:41:06 +01:00
|
|
|
|
pname := filepath.Join(libdir, name+".a")
|
2016-08-21 18:25:28 -04:00
|
|
|
|
if ctxt.Debugvlog != 0 {
|
2016-08-25 12:32:42 +10:00
|
|
|
|
ctxt.Logf("searching for %s.a in %s\n", name, pname)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
2015-09-07 15:00:52 +12:00
|
|
|
|
if _, err := os.Stat(pname); err == nil {
|
2020-04-22 22:20:44 -04:00
|
|
|
|
return addlibpath(ctxt, "internal", "internal", pname, name, "", zerofp)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-11-10 17:17:54 -05:00
|
|
|
|
if name == "runtime" {
|
|
|
|
|
|
Exitf("error: unable to find runtime.a")
|
|
|
|
|
|
}
|
2016-09-14 14:47:12 -04:00
|
|
|
|
ctxt.Logf("warning: unable to find %s.a\n", name)
|
|
|
|
|
|
return nil
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-02-20 16:39:09 +01:00
|
|
|
|
// extld returns the current external linker.
|
cmd: support space and quotes in CC and CXX
The CC and CXX environment variables now support spaces and quotes
(both double and single). This fixes two issues: first, if CC is a
single path that contains spaces (like 'c:\Program
Files\gcc\bin\gcc.exe'), that should now work if the space is quoted
or escaped (#41400). Second, if CC or CXX has multiple arguments (like
'gcc -O2'), they are now split correctly, and the arguments are passed
before other arguments when invoking the C compiler. Previously,
strings.Fields was used to split arguments, and the arguments were
placed later in the command line. (#43078).
Fixes golang/go#41400
Fixes golang/go#43078
NOTE: This change also includes a fix (CL 341929) for a test that was
broken by the original CL. Commit message for the fix is below.
[dev.cmdgo] cmd/link: fix TestBuildForTvOS
This test was broken in CL 334732 on darwin.
The test invokes 'go build' with a CC containing the arguments
-framework CoreFoundation. Previously, the go command split CC on
whitespace, and inserted the arguments after the command line when
running CC directly. Those arguments weren't passed to cgo though,
so cgo ran CC without -framework CoreFoundation (or any of the other
flags).
In CL 334732, we pass CC through to cgo, and cgo splits arguments
using str.SplitQuotedFields. So -framework CoreFoundation actually
gets passed to the C compiler. It appears that -framework flags are
only meant to be used in linking operations, so when cgo invokes clang
with -E (run preprocessor only), clang emits an error that -framework
is unused.
This change fixes the test by moving -framework CoreFoundation out of
CC and into CGO_LDFLAGS.
Change-Id: I2d5d89ddb19c94adef65982a8137b01f037d5c11
Reviewed-on: https://go-review.googlesource.com/c/go/+/334732
Trust: Jay Conrod <jayconrod@google.com>
Trust: Michael Matloob <matloob@golang.org>
Run-TryBot: Jay Conrod <jayconrod@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Michael Matloob <matloob@golang.org>
Reviewed-on: https://go-review.googlesource.com/c/go/+/341936
Reviewed-by: Bryan C. Mills <bcmills@google.com>
2021-07-14 16:57:24 -07:00
|
|
|
|
func (ctxt *Link) extld() []string {
|
|
|
|
|
|
if len(flagExtld) == 0 {
|
2022-09-22 06:59:42 -05:00
|
|
|
|
// Return the default external linker for the platform.
|
|
|
|
|
|
// This only matters when link tool is called directly without explicit -extld,
|
|
|
|
|
|
// go tool already passes the correct linker in other cases.
|
|
|
|
|
|
switch buildcfg.GOOS {
|
|
|
|
|
|
case "darwin", "freebsd", "openbsd":
|
|
|
|
|
|
flagExtld = []string{"clang"}
|
|
|
|
|
|
default:
|
|
|
|
|
|
flagExtld = []string{"gcc"}
|
|
|
|
|
|
}
|
2016-08-10 11:06:46 +10:00
|
|
|
|
}
|
cmd: support space and quotes in CC and CXX
The CC and CXX environment variables now support spaces and quotes
(both double and single). This fixes two issues: first, if CC is a
single path that contains spaces (like 'c:\Program
Files\gcc\bin\gcc.exe'), that should now work if the space is quoted
or escaped (#41400). Second, if CC or CXX has multiple arguments (like
'gcc -O2'), they are now split correctly, and the arguments are passed
before other arguments when invoking the C compiler. Previously,
strings.Fields was used to split arguments, and the arguments were
placed later in the command line. (#43078).
Fixes golang/go#41400
Fixes golang/go#43078
NOTE: This change also includes a fix (CL 341929) for a test that was
broken by the original CL. Commit message for the fix is below.
[dev.cmdgo] cmd/link: fix TestBuildForTvOS
This test was broken in CL 334732 on darwin.
The test invokes 'go build' with a CC containing the arguments
-framework CoreFoundation. Previously, the go command split CC on
whitespace, and inserted the arguments after the command line when
running CC directly. Those arguments weren't passed to cgo though,
so cgo ran CC without -framework CoreFoundation (or any of the other
flags).
In CL 334732, we pass CC through to cgo, and cgo splits arguments
using str.SplitQuotedFields. So -framework CoreFoundation actually
gets passed to the C compiler. It appears that -framework flags are
only meant to be used in linking operations, so when cgo invokes clang
with -E (run preprocessor only), clang emits an error that -framework
is unused.
This change fixes the test by moving -framework CoreFoundation out of
CC and into CGO_LDFLAGS.
Change-Id: I2d5d89ddb19c94adef65982a8137b01f037d5c11
Reviewed-on: https://go-review.googlesource.com/c/go/+/334732
Trust: Jay Conrod <jayconrod@google.com>
Trust: Michael Matloob <matloob@golang.org>
Run-TryBot: Jay Conrod <jayconrod@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Michael Matloob <matloob@golang.org>
Reviewed-on: https://go-review.googlesource.com/c/go/+/341936
Reviewed-by: Bryan C. Mills <bcmills@google.com>
2021-07-14 16:57:24 -07:00
|
|
|
|
return flagExtld
|
2019-02-20 16:39:09 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// findLibPathCmd uses cmd command to find gcc library libname.
|
|
|
|
|
|
// It returns library full path if found, or "none" if not found.
|
|
|
|
|
|
func (ctxt *Link) findLibPathCmd(cmd, libname string) string {
|
|
|
|
|
|
extld := ctxt.extld()
|
cmd: support space and quotes in CC and CXX
The CC and CXX environment variables now support spaces and quotes
(both double and single). This fixes two issues: first, if CC is a
single path that contains spaces (like 'c:\Program
Files\gcc\bin\gcc.exe'), that should now work if the space is quoted
or escaped (#41400). Second, if CC or CXX has multiple arguments (like
'gcc -O2'), they are now split correctly, and the arguments are passed
before other arguments when invoking the C compiler. Previously,
strings.Fields was used to split arguments, and the arguments were
placed later in the command line. (#43078).
Fixes golang/go#41400
Fixes golang/go#43078
NOTE: This change also includes a fix (CL 341929) for a test that was
broken by the original CL. Commit message for the fix is below.
[dev.cmdgo] cmd/link: fix TestBuildForTvOS
This test was broken in CL 334732 on darwin.
The test invokes 'go build' with a CC containing the arguments
-framework CoreFoundation. Previously, the go command split CC on
whitespace, and inserted the arguments after the command line when
running CC directly. Those arguments weren't passed to cgo though,
so cgo ran CC without -framework CoreFoundation (or any of the other
flags).
In CL 334732, we pass CC through to cgo, and cgo splits arguments
using str.SplitQuotedFields. So -framework CoreFoundation actually
gets passed to the C compiler. It appears that -framework flags are
only meant to be used in linking operations, so when cgo invokes clang
with -E (run preprocessor only), clang emits an error that -framework
is unused.
This change fixes the test by moving -framework CoreFoundation out of
CC and into CGO_LDFLAGS.
Change-Id: I2d5d89ddb19c94adef65982a8137b01f037d5c11
Reviewed-on: https://go-review.googlesource.com/c/go/+/334732
Trust: Jay Conrod <jayconrod@google.com>
Trust: Michael Matloob <matloob@golang.org>
Run-TryBot: Jay Conrod <jayconrod@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Michael Matloob <matloob@golang.org>
Reviewed-on: https://go-review.googlesource.com/c/go/+/341936
Reviewed-by: Bryan C. Mills <bcmills@google.com>
2021-07-14 16:57:24 -07:00
|
|
|
|
name, args := extld[0], extld[1:]
|
|
|
|
|
|
args = append(args, hostlinkArchArgs(ctxt.Arch)...)
|
2016-08-10 11:06:46 +10:00
|
|
|
|
args = append(args, cmd)
|
|
|
|
|
|
if ctxt.Debugvlog != 0 {
|
2019-02-20 16:39:09 +01:00
|
|
|
|
ctxt.Logf("%s %v\n", extld, args)
|
2016-08-10 11:06:46 +10:00
|
|
|
|
}
|
cmd: support space and quotes in CC and CXX
The CC and CXX environment variables now support spaces and quotes
(both double and single). This fixes two issues: first, if CC is a
single path that contains spaces (like 'c:\Program
Files\gcc\bin\gcc.exe'), that should now work if the space is quoted
or escaped (#41400). Second, if CC or CXX has multiple arguments (like
'gcc -O2'), they are now split correctly, and the arguments are passed
before other arguments when invoking the C compiler. Previously,
strings.Fields was used to split arguments, and the arguments were
placed later in the command line. (#43078).
Fixes golang/go#41400
Fixes golang/go#43078
NOTE: This change also includes a fix (CL 341929) for a test that was
broken by the original CL. Commit message for the fix is below.
[dev.cmdgo] cmd/link: fix TestBuildForTvOS
This test was broken in CL 334732 on darwin.
The test invokes 'go build' with a CC containing the arguments
-framework CoreFoundation. Previously, the go command split CC on
whitespace, and inserted the arguments after the command line when
running CC directly. Those arguments weren't passed to cgo though,
so cgo ran CC without -framework CoreFoundation (or any of the other
flags).
In CL 334732, we pass CC through to cgo, and cgo splits arguments
using str.SplitQuotedFields. So -framework CoreFoundation actually
gets passed to the C compiler. It appears that -framework flags are
only meant to be used in linking operations, so when cgo invokes clang
with -E (run preprocessor only), clang emits an error that -framework
is unused.
This change fixes the test by moving -framework CoreFoundation out of
CC and into CGO_LDFLAGS.
Change-Id: I2d5d89ddb19c94adef65982a8137b01f037d5c11
Reviewed-on: https://go-review.googlesource.com/c/go/+/334732
Trust: Jay Conrod <jayconrod@google.com>
Trust: Michael Matloob <matloob@golang.org>
Run-TryBot: Jay Conrod <jayconrod@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Michael Matloob <matloob@golang.org>
Reviewed-on: https://go-review.googlesource.com/c/go/+/341936
Reviewed-by: Bryan C. Mills <bcmills@google.com>
2021-07-14 16:57:24 -07:00
|
|
|
|
out, err := exec.Command(name, args...).Output()
|
2016-08-10 11:06:46 +10:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
if ctxt.Debugvlog != 0 {
|
|
|
|
|
|
ctxt.Logf("not using a %s file because compiler failed\n%v\n%s\n", libname, err, out)
|
|
|
|
|
|
}
|
|
|
|
|
|
return "none"
|
|
|
|
|
|
}
|
|
|
|
|
|
return strings.TrimSpace(string(out))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// findLibPath searches for library libname.
|
|
|
|
|
|
// It returns library full path if found, or "none" if not found.
|
|
|
|
|
|
func (ctxt *Link) findLibPath(libname string) string {
|
|
|
|
|
|
return ctxt.findLibPathCmd("--print-file-name="+libname, libname)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-08-19 22:40:38 -04:00
|
|
|
|
func (ctxt *Link) loadlib() {
|
2019-11-11 16:49:29 -05:00
|
|
|
|
var flags uint32
|
cmd/link: disallow pull-only linknames
As mentioned in CL 584598, linkname is a mechanism that, when
abused, can break API integrity and even safety of Go programs.
CL 584598 is a first step to restrict the use of linknames, by
implementing a blocklist. This CL takes a step further, tightening
up the restriction by allowing linkname references ("pull") only
when the definition side explicitly opts into it, by having a
linkname on the definition (possibly to itself). This way, it is at
least clear on the definition side that the symbol, despite being
unexported, is accessed outside of the package. Unexported symbols
without linkname can now be actually private. This is similar to
the symbol visibility rule used by gccgo for years (which defines
unexported non-linknamed symbols as C static symbols).
As there can be pull-only linknames in the wild that may be broken
by this change, we currently only enforce this rule for symbols
defined in the standard library. Push linknames are added in the
standard library to allow things build.
Linkname references to external (non-Go) symbols are still allowed,
as their visibility is controlled by the C symbol visibility rules
and enforced by the C (static or dynamic) linker.
Assembly symbols are treated similar to linknamed symbols.
This is controlled by -checklinkname linker flag, currently not
enabled by default. A follow-up CL will enable it by default.
Change-Id: I07344f5c7a02124dbbef0fbc8fec3b666a4b2b0e
Reviewed-on: https://go-review.googlesource.com/c/go/+/585358
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Russ Cox <rsc@golang.org>
2024-05-14 00:01:49 -04:00
|
|
|
|
if *flagCheckLinkname {
|
|
|
|
|
|
flags |= loader.FlagCheckLinkname
|
|
|
|
|
|
}
|
2019-11-11 16:49:29 -05:00
|
|
|
|
switch *FlagStrictDups {
|
|
|
|
|
|
case 0:
|
|
|
|
|
|
// nothing to do
|
|
|
|
|
|
case 1, 2:
|
2021-02-05 18:07:46 -05:00
|
|
|
|
flags |= loader.FlagStrictDups
|
2019-11-11 16:49:29 -05:00
|
|
|
|
default:
|
|
|
|
|
|
log.Fatalf("invalid -strictdups flag value %d", *FlagStrictDups)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
2023-05-04 17:09:49 -04:00
|
|
|
|
ctxt.loader = loader.NewLoader(flags, &ctxt.ErrorReporter.ErrorReporter)
|
2020-03-19 08:17:54 -04:00
|
|
|
|
ctxt.ErrorReporter.SymName = func(s loader.Sym) string {
|
|
|
|
|
|
return ctxt.loader.SymName(s)
|
|
|
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
2019-10-30 21:24:22 -04:00
|
|
|
|
// ctxt.Library grows during the loop, so not a range loop.
|
|
|
|
|
|
i := 0
|
|
|
|
|
|
for ; i < len(ctxt.Library); i++ {
|
|
|
|
|
|
lib := ctxt.Library[i]
|
|
|
|
|
|
if lib.Shlib == "" {
|
|
|
|
|
|
if ctxt.Debugvlog > 1 {
|
|
|
|
|
|
ctxt.Logf("autolib: %s (from %s)\n", lib.File, lib.Objref)
|
|
|
|
|
|
}
|
|
|
|
|
|
loadobjfile(ctxt, lib)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// load internal packages, if not already
|
2016-08-21 18:34:24 -04:00
|
|
|
|
if *flagRace {
|
2016-08-19 22:40:38 -04:00
|
|
|
|
loadinternal(ctxt, "runtime/race")
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
2016-08-21 18:34:24 -04:00
|
|
|
|
if *flagMsan {
|
2016-08-19 22:40:38 -04:00
|
|
|
|
loadinternal(ctxt, "runtime/msan")
|
2015-10-21 07:11:01 -07:00
|
|
|
|
}
|
2021-01-04 16:23:01 +08:00
|
|
|
|
if *flagAsan {
|
|
|
|
|
|
loadinternal(ctxt, "runtime/asan")
|
|
|
|
|
|
}
|
2019-10-30 21:24:22 -04:00
|
|
|
|
loadinternal(ctxt, "runtime")
|
|
|
|
|
|
for ; i < len(ctxt.Library); i++ {
|
2017-06-09 11:15:53 -04:00
|
|
|
|
lib := ctxt.Library[i]
|
|
|
|
|
|
if lib.Shlib == "" {
|
2017-09-30 17:28:05 +00:00
|
|
|
|
loadobjfile(ctxt, lib)
|
2016-01-20 15:31:26 +13:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2020-02-11 10:27:15 -05:00
|
|
|
|
// At this point, the Go objects are "preloaded". Not all the symbols are
|
|
|
|
|
|
// added to the symbol table (only defined package symbols are). Looking
|
|
|
|
|
|
// up symbol by name may not get expected result.
|
2016-01-20 15:31:26 +13:00
|
|
|
|
|
2020-02-11 10:27:15 -05:00
|
|
|
|
iscgo = ctxt.LibraryByPkg["runtime/cgo"] != nil
|
2021-04-27 15:05:51 -05:00
|
|
|
|
|
|
|
|
|
|
// Plugins a require cgo support to function. Similarly, plugins may require additional
|
|
|
|
|
|
// internal linker support on some platforms which may not be implemented.
|
|
|
|
|
|
ctxt.canUsePlugins = ctxt.LibraryByPkg["plugin"] != nil && iscgo
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
2016-09-09 17:34:07 -04:00
|
|
|
|
// We now have enough information to determine the link mode.
|
|
|
|
|
|
determineLinkMode(ctxt)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
2021-04-15 23:05:49 -04:00
|
|
|
|
if ctxt.LinkMode == LinkExternal && !iscgo && !(buildcfg.GOOS == "darwin" && ctxt.BuildMode != BuildModePlugin && ctxt.Arch.Family == sys.AMD64) {
|
2015-02-27 22:57:28 -05:00
|
|
|
|
// This indicates a user requested -linkmode=external.
|
|
|
|
|
|
// The startup code uses an import of runtime/cgo to decide
|
2016-03-01 23:21:55 +00:00
|
|
|
|
// whether to initialize the TLS. So give it one. This could
|
2015-02-27 22:57:28 -05:00
|
|
|
|
// be handled differently but it's an unusual case.
|
2020-02-11 10:27:15 -05:00
|
|
|
|
if lib := loadinternal(ctxt, "runtime/cgo"); lib != nil && lib.Shlib == "" {
|
|
|
|
|
|
if ctxt.BuildMode == BuildModeShared || ctxt.linkShared {
|
|
|
|
|
|
Exitf("cannot implicitly include runtime/cgo in a shared library")
|
2015-04-01 14:57:34 +13:00
|
|
|
|
}
|
2021-02-23 09:58:14 +01:00
|
|
|
|
for ; i < len(ctxt.Library); i++ {
|
|
|
|
|
|
lib := ctxt.Library[i]
|
|
|
|
|
|
if lib.Shlib == "" {
|
|
|
|
|
|
loadobjfile(ctxt, lib)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-02-11 10:27:15 -05:00
|
|
|
|
// Add non-package symbols and references of externally defined symbols.
|
2020-08-18 16:35:26 -04:00
|
|
|
|
ctxt.loader.LoadSyms(ctxt.Arch)
|
2020-02-11 10:27:15 -05:00
|
|
|
|
|
|
|
|
|
|
// Load symbols from shared libraries, after all Go object symbols are loaded.
|
2019-10-16 15:44:04 -04:00
|
|
|
|
for _, lib := range ctxt.Library {
|
|
|
|
|
|
if lib.Shlib != "" {
|
|
|
|
|
|
if ctxt.Debugvlog > 1 {
|
2019-11-01 10:44:44 -04:00
|
|
|
|
ctxt.Logf("autolib: %s (from %s)\n", lib.Shlib, lib.Objref)
|
2019-10-16 15:44:04 -04:00
|
|
|
|
}
|
|
|
|
|
|
ldshlibsyms(ctxt, lib.Shlib)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-12-06 20:11:36 -05:00
|
|
|
|
// Process cgo directives (has to be done before host object loading).
|
2020-01-31 14:35:37 -05:00
|
|
|
|
ctxt.loadcgodirectives()
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
2019-10-31 19:35:55 -04:00
|
|
|
|
// Conditionally load host objects, or setup for external linking.
|
|
|
|
|
|
hostobjs(ctxt)
|
|
|
|
|
|
hostlinksetup(ctxt)
|
2019-03-27 14:25:24 +01:00
|
|
|
|
|
2019-10-31 19:35:55 -04:00
|
|
|
|
if ctxt.LinkMode == LinkInternal && len(hostobj) != 0 {
|
2015-11-04 11:14:19 -08:00
|
|
|
|
// If we have any undefined symbols in external
|
2015-11-16 18:11:35 -08:00
|
|
|
|
// objects, try to read them from the libgcc file.
|
2015-11-04 11:14:19 -08:00
|
|
|
|
any := false
|
2022-11-01 10:27:18 -04:00
|
|
|
|
undefs, froms := ctxt.loader.UndefinedRelocTargets(1)
|
2020-01-31 14:35:37 -05:00
|
|
|
|
if len(undefs) > 0 {
|
|
|
|
|
|
any = true
|
2022-11-01 10:27:18 -04:00
|
|
|
|
if ctxt.Debugvlog > 1 {
|
|
|
|
|
|
ctxt.Logf("loadlib: first unresolved is %s [%d] from %s [%d]\n",
|
|
|
|
|
|
ctxt.loader.SymName(undefs[0]), undefs[0],
|
|
|
|
|
|
ctxt.loader.SymName(froms[0]), froms[0])
|
|
|
|
|
|
}
|
2015-11-04 11:14:19 -08:00
|
|
|
|
}
|
|
|
|
|
|
if any {
|
2016-08-21 18:34:24 -04:00
|
|
|
|
if *flagLibGCC == "" {
|
2016-08-10 11:06:46 +10:00
|
|
|
|
*flagLibGCC = ctxt.findLibPathCmd("--print-libgcc-file-name", "libgcc")
|
2015-11-16 18:11:35 -08:00
|
|
|
|
}
|
2024-12-02 19:10:37 +00:00
|
|
|
|
if runtime.GOOS == "freebsd" && strings.HasPrefix(filepath.Base(*flagLibGCC), "libclang_rt.builtins") {
|
|
|
|
|
|
// On newer versions of FreeBSD, libgcc is returned as something like
|
|
|
|
|
|
// /usr/lib/clang/18/lib/freebsd/libclang_rt.builtins-x86_64.a.
|
|
|
|
|
|
// Unfortunately this ends up missing a bunch of symbols we need from
|
|
|
|
|
|
// libcompiler_rt.
|
|
|
|
|
|
*flagLibGCC = ctxt.findLibPathCmd("--print-file-name=libcompiler_rt.a", "libcompiler_rt")
|
|
|
|
|
|
}
|
2018-12-17 01:18:51 +11:00
|
|
|
|
if runtime.GOOS == "openbsd" && *flagLibGCC == "libgcc.a" {
|
|
|
|
|
|
// On OpenBSD `clang --print-libgcc-file-name` returns "libgcc.a".
|
|
|
|
|
|
// In this case we fail to load libgcc.a and can encounter link
|
|
|
|
|
|
// errors - see if we can find libcompiler_rt.a instead.
|
|
|
|
|
|
*flagLibGCC = ctxt.findLibPathCmd("--print-file-name=libcompiler_rt.a", "libcompiler_rt")
|
|
|
|
|
|
}
|
2017-10-07 13:49:44 -04:00
|
|
|
|
if ctxt.HeadType == objabi.Hwindows {
|
2022-02-03 08:23:10 -05:00
|
|
|
|
loadWindowsHostArchives(ctxt)
|
2016-08-10 11:06:46 +10:00
|
|
|
|
}
|
2021-02-24 16:47:58 +01:00
|
|
|
|
if *flagLibGCC != "none" {
|
|
|
|
|
|
hostArchive(ctxt, *flagLibGCC)
|
2023-02-09 11:37:13 -05:00
|
|
|
|
}
|
|
|
|
|
|
// For glibc systems, the linker setup used by GCC
|
|
|
|
|
|
// looks like
|
|
|
|
|
|
//
|
|
|
|
|
|
// GROUP ( /lib/x86_64-linux-gnu/libc.so.6
|
|
|
|
|
|
// /usr/lib/x86_64-linux-gnu/libc_nonshared.a
|
|
|
|
|
|
// AS_NEEDED ( /lib64/ld-linux-x86-64.so.2 ) )
|
|
|
|
|
|
//
|
|
|
|
|
|
// where libc_nonshared.a contains a small set of
|
|
|
|
|
|
// symbols including "__stack_chk_fail_local" and a
|
|
|
|
|
|
// few others. Thus if we are doing internal linking
|
|
|
|
|
|
// and "__stack_chk_fail_local" is unresolved (most
|
|
|
|
|
|
// likely due to the use of -fstack-protector), try
|
|
|
|
|
|
// loading libc_nonshared.a to resolve it.
|
|
|
|
|
|
//
|
|
|
|
|
|
// On Alpine Linux (musl-based), the library providing
|
|
|
|
|
|
// this symbol is called libssp_nonshared.a.
|
|
|
|
|
|
isunresolved := symbolsAreUnresolved(ctxt, []string{"__stack_chk_fail_local"})
|
|
|
|
|
|
if isunresolved[0] {
|
|
|
|
|
|
if p := ctxt.findLibPath("libc_nonshared.a"); p != "none" {
|
|
|
|
|
|
hostArchive(ctxt, p)
|
|
|
|
|
|
}
|
|
|
|
|
|
if p := ctxt.findLibPath("libssp_nonshared.a"); p != "none" {
|
|
|
|
|
|
hostArchive(ctxt, p)
|
2022-12-12 11:04:05 -05:00
|
|
|
|
}
|
2021-02-24 16:47:58 +01:00
|
|
|
|
}
|
2015-11-04 11:14:19 -08:00
|
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-11-05 13:51:32 -05:00
|
|
|
|
loadfips(ctxt)
|
|
|
|
|
|
|
2015-02-27 22:57:28 -05:00
|
|
|
|
// We've loaded all the code now.
|
2016-08-25 21:58:45 -04:00
|
|
|
|
ctxt.Loaded = true
|
|
|
|
|
|
|
2019-11-11 16:49:29 -05:00
|
|
|
|
strictDupMsgCount = ctxt.loader.NStrictDupMsgs()
|
2019-09-23 22:44:02 -04:00
|
|
|
|
}
|
2018-11-01 12:30:23 -04:00
|
|
|
|
|
2022-02-03 08:23:10 -05:00
|
|
|
|
// loadWindowsHostArchives loads in host archives and objects when
|
|
|
|
|
|
// doing internal linking on windows. Older toolchains seem to require
|
|
|
|
|
|
// just a single pass through the various archives, but some modern
|
|
|
|
|
|
// toolchains when linking a C program with mingw pass library paths
|
|
|
|
|
|
// multiple times to the linker, e.g. "... -lmingwex -lmingw32 ...
|
|
|
|
|
|
// -lmingwex -lmingw32 ...". To accommodate this behavior, we make two
|
|
|
|
|
|
// passes over the host archives below.
|
|
|
|
|
|
func loadWindowsHostArchives(ctxt *Link) {
|
|
|
|
|
|
any := true
|
|
|
|
|
|
for i := 0; any && i < 2; i++ {
|
|
|
|
|
|
// Link crt2.o (if present) to resolve "atexit" when
|
|
|
|
|
|
// using LLVM-based compilers.
|
|
|
|
|
|
isunresolved := symbolsAreUnresolved(ctxt, []string{"atexit"})
|
|
|
|
|
|
if isunresolved[0] {
|
|
|
|
|
|
if p := ctxt.findLibPath("crt2.o"); p != "none" {
|
|
|
|
|
|
hostObject(ctxt, "crt2", p)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-06-24 15:31:35 -04:00
|
|
|
|
if *flagRace {
|
|
|
|
|
|
if p := ctxt.findLibPath("libsynchronization.a"); p != "none" {
|
|
|
|
|
|
hostArchive(ctxt, p)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-02-03 08:23:10 -05:00
|
|
|
|
if p := ctxt.findLibPath("libmingwex.a"); p != "none" {
|
|
|
|
|
|
hostArchive(ctxt, p)
|
|
|
|
|
|
}
|
|
|
|
|
|
if p := ctxt.findLibPath("libmingw32.a"); p != "none" {
|
|
|
|
|
|
hostArchive(ctxt, p)
|
|
|
|
|
|
}
|
|
|
|
|
|
// Link libmsvcrt.a to resolve '__acrt_iob_func' symbol
|
|
|
|
|
|
// (see https://golang.org/issue/23649 for details).
|
|
|
|
|
|
if p := ctxt.findLibPath("libmsvcrt.a"); p != "none" {
|
|
|
|
|
|
hostArchive(ctxt, p)
|
|
|
|
|
|
}
|
|
|
|
|
|
any = false
|
2022-11-01 10:27:18 -04:00
|
|
|
|
undefs, froms := ctxt.loader.UndefinedRelocTargets(1)
|
2022-02-03 08:23:10 -05:00
|
|
|
|
if len(undefs) > 0 {
|
|
|
|
|
|
any = true
|
2022-11-01 10:27:18 -04:00
|
|
|
|
if ctxt.Debugvlog > 1 {
|
|
|
|
|
|
ctxt.Logf("loadWindowsHostArchives: remaining unresolved is %s [%d] from %s [%d]\n",
|
|
|
|
|
|
ctxt.loader.SymName(undefs[0]), undefs[0],
|
|
|
|
|
|
ctxt.loader.SymName(froms[0]), froms[0])
|
|
|
|
|
|
}
|
2022-02-03 08:23:10 -05:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-02-07 15:30:34 -05:00
|
|
|
|
// If needed, create the __CTOR_LIST__ and __DTOR_LIST__
|
|
|
|
|
|
// symbols (referenced by some of the mingw support library
|
|
|
|
|
|
// routines). Creation of these symbols is normally done by the
|
|
|
|
|
|
// linker if not already present.
|
|
|
|
|
|
want := []string{"__CTOR_LIST__", "__DTOR_LIST__"}
|
|
|
|
|
|
isunresolved := symbolsAreUnresolved(ctxt, want)
|
|
|
|
|
|
for k, w := range want {
|
|
|
|
|
|
if isunresolved[k] {
|
|
|
|
|
|
sb := ctxt.loader.CreateSymForUpdate(w, 0)
|
|
|
|
|
|
sb.SetType(sym.SDATA)
|
|
|
|
|
|
sb.AddUint64(ctxt.Arch, 0)
|
|
|
|
|
|
sb.SetReachable(true)
|
|
|
|
|
|
ctxt.loader.SetAttrSpecial(sb.Sym(), true)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-11-17 14:41:18 -05:00
|
|
|
|
|
|
|
|
|
|
// Fix up references to DLL import symbols now that we're done
|
|
|
|
|
|
// pulling in new objects.
|
|
|
|
|
|
if err := loadpe.PostProcessImports(); err != nil {
|
2024-11-01 14:56:25 -04:00
|
|
|
|
Errorf("%v", err)
|
2022-11-17 14:41:18 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-02-03 08:23:10 -05:00
|
|
|
|
// TODO: maybe do something similar to peimporteddlls to collect
|
|
|
|
|
|
// all lib names and try link them all to final exe just like
|
|
|
|
|
|
// libmingwex.a and libmingw32.a:
|
|
|
|
|
|
/*
|
|
|
|
|
|
for:
|
|
|
|
|
|
#cgo windows LDFLAGS: -lmsvcrt -lm
|
|
|
|
|
|
import:
|
|
|
|
|
|
libmsvcrt.a libm.a
|
|
|
|
|
|
*/
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-01-31 14:35:37 -05:00
|
|
|
|
// loadcgodirectives reads the previously discovered cgo directives, creating
|
|
|
|
|
|
// symbols in preparation for host object loading or use later in the link.
|
|
|
|
|
|
func (ctxt *Link) loadcgodirectives() {
|
|
|
|
|
|
l := ctxt.loader
|
|
|
|
|
|
hostObjSyms := make(map[loader.Sym]struct{})
|
|
|
|
|
|
for _, d := range ctxt.cgodata {
|
2021-04-11 16:30:36 -04:00
|
|
|
|
setCgoAttr(ctxt, d.file, d.pkg, d.directives, hostObjSyms)
|
2020-01-31 14:35:37 -05:00
|
|
|
|
}
|
|
|
|
|
|
ctxt.cgodata = nil
|
|
|
|
|
|
|
|
|
|
|
|
if ctxt.LinkMode == LinkInternal {
|
|
|
|
|
|
// Drop all the cgo_import_static declarations.
|
|
|
|
|
|
// Turns out we won't be needing them.
|
|
|
|
|
|
for symIdx := range hostObjSyms {
|
|
|
|
|
|
if l.SymType(symIdx) == sym.SHOSTOBJ {
|
|
|
|
|
|
// If a symbol was marked both
|
|
|
|
|
|
// cgo_import_static and cgo_import_dynamic,
|
|
|
|
|
|
// then we want to make it cgo_import_dynamic
|
|
|
|
|
|
// now.
|
2020-02-12 17:23:47 -05:00
|
|
|
|
su := l.MakeSymbolUpdater(symIdx)
|
2020-01-31 14:35:37 -05:00
|
|
|
|
if l.SymExtname(symIdx) != "" && l.SymDynimplib(symIdx) != "" && !(l.AttrCgoExportStatic(symIdx) || l.AttrCgoExportDynamic(symIdx)) {
|
|
|
|
|
|
su.SetType(sym.SDYNIMPORT)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
su.SetType(0)
|
2019-12-06 20:11:36 -05:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-09-23 22:44:02 -04:00
|
|
|
|
// Set up flags and special symbols depending on the platform build mode.
|
2019-12-30 14:12:54 -05:00
|
|
|
|
// This version works with loader.Loader.
|
2019-09-23 22:44:02 -04:00
|
|
|
|
func (ctxt *Link) linksetup() {
|
2019-12-30 14:12:54 -05:00
|
|
|
|
switch ctxt.BuildMode {
|
|
|
|
|
|
case BuildModeCShared, BuildModePlugin:
|
|
|
|
|
|
symIdx := ctxt.loader.LookupOrCreateSym("runtime.islibrary", 0)
|
2020-02-12 17:23:47 -05:00
|
|
|
|
sb := ctxt.loader.MakeSymbolUpdater(symIdx)
|
2019-12-30 14:12:54 -05:00
|
|
|
|
sb.SetType(sym.SNOPTRDATA)
|
|
|
|
|
|
sb.AddUint8(1)
|
|
|
|
|
|
case BuildModeCArchive:
|
|
|
|
|
|
symIdx := ctxt.loader.LookupOrCreateSym("runtime.isarchive", 0)
|
2020-02-12 17:23:47 -05:00
|
|
|
|
sb := ctxt.loader.MakeSymbolUpdater(symIdx)
|
2019-12-30 14:12:54 -05:00
|
|
|
|
sb.SetType(sym.SNOPTRDATA)
|
|
|
|
|
|
sb.AddUint8(1)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Recalculate pe parameters now that we have ctxt.LinkMode set.
|
|
|
|
|
|
if ctxt.HeadType == objabi.Hwindows {
|
|
|
|
|
|
Peinit(ctxt)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-05-12 12:30:34 -04:00
|
|
|
|
if ctxt.LinkMode == LinkExternal {
|
|
|
|
|
|
// When external linking, we are creating an object file. The
|
|
|
|
|
|
// absolute address is irrelevant.
|
2019-12-30 14:12:54 -05:00
|
|
|
|
*FlagTextAddr = 0
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// If there are no dynamic libraries needed, gcc disables dynamic linking.
|
|
|
|
|
|
// Because of this, glibc's dynamic ELF loader occasionally (like in version 2.13)
|
|
|
|
|
|
// assumes that a dynamic binary always refers to at least one dynamic library.
|
|
|
|
|
|
// Rather than be a source of test cases for glibc, disable dynamic linking
|
|
|
|
|
|
// the same way that gcc would.
|
|
|
|
|
|
//
|
|
|
|
|
|
// Exception: on OS X, programs such as Shark only work with dynamic
|
|
|
|
|
|
// binaries, so leave it enabled on OS X (Mach-O) binaries.
|
|
|
|
|
|
// Also leave it enabled on Solaris which doesn't support
|
|
|
|
|
|
// statically linked binaries.
|
|
|
|
|
|
if ctxt.BuildMode == BuildModeExe {
|
|
|
|
|
|
if havedynamic == 0 && ctxt.HeadType != objabi.Hdarwin && ctxt.HeadType != objabi.Hsolaris {
|
|
|
|
|
|
*FlagD = true
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-04-15 23:05:49 -04:00
|
|
|
|
if ctxt.LinkMode == LinkExternal && ctxt.Arch.Family == sys.PPC64 && buildcfg.GOOS != "aix" {
|
2019-12-30 14:12:54 -05:00
|
|
|
|
toc := ctxt.loader.LookupOrCreateSym(".TOC.", 0)
|
2020-02-12 17:23:47 -05:00
|
|
|
|
sb := ctxt.loader.MakeSymbolUpdater(toc)
|
2019-12-30 14:12:54 -05:00
|
|
|
|
sb.SetType(sym.SDYNIMPORT)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// The Android Q linker started to complain about underalignment of the our TLS
|
|
|
|
|
|
// section. We don't actually use the section on android, so don't
|
|
|
|
|
|
// generate it.
|
2021-04-15 23:05:49 -04:00
|
|
|
|
if buildcfg.GOOS != "android" {
|
2020-02-12 17:23:47 -05:00
|
|
|
|
tlsg := ctxt.loader.LookupOrCreateSym("runtime.tlsg", 0)
|
|
|
|
|
|
sb := ctxt.loader.MakeSymbolUpdater(tlsg)
|
2019-12-30 14:12:54 -05:00
|
|
|
|
|
|
|
|
|
|
// runtime.tlsg is used for external linking on platforms that do not define
|
|
|
|
|
|
// a variable to hold g in assembly (currently only intel).
|
|
|
|
|
|
if sb.Type() == 0 {
|
|
|
|
|
|
sb.SetType(sym.STLSBSS)
|
|
|
|
|
|
sb.SetSize(int64(ctxt.Arch.PtrSize))
|
|
|
|
|
|
} else if sb.Type() != sym.SDYNIMPORT {
|
2024-11-01 14:56:25 -04:00
|
|
|
|
Errorf("runtime declared tlsg variable %v", sb.Type())
|
2019-12-30 14:12:54 -05:00
|
|
|
|
}
|
|
|
|
|
|
ctxt.loader.SetAttrReachable(tlsg, true)
|
2020-05-15 18:35:05 -04:00
|
|
|
|
ctxt.Tlsg = tlsg
|
2019-12-30 14:12:54 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var moduledata loader.Sym
|
|
|
|
|
|
var mdsb *loader.SymbolBuilder
|
|
|
|
|
|
if ctxt.BuildMode == BuildModePlugin {
|
2020-02-12 17:23:47 -05:00
|
|
|
|
moduledata = ctxt.loader.LookupOrCreateSym("local.pluginmoduledata", 0)
|
|
|
|
|
|
mdsb = ctxt.loader.MakeSymbolUpdater(moduledata)
|
2019-12-30 14:12:54 -05:00
|
|
|
|
ctxt.loader.SetAttrLocal(moduledata, true)
|
|
|
|
|
|
} else {
|
2020-02-12 17:23:47 -05:00
|
|
|
|
moduledata = ctxt.loader.LookupOrCreateSym("runtime.firstmoduledata", 0)
|
|
|
|
|
|
mdsb = ctxt.loader.MakeSymbolUpdater(moduledata)
|
2019-12-30 14:12:54 -05:00
|
|
|
|
}
|
|
|
|
|
|
if mdsb.Type() != 0 && mdsb.Type() != sym.SDYNIMPORT {
|
|
|
|
|
|
// If the module (toolchain-speak for "executable or shared
|
|
|
|
|
|
// library") we are linking contains the runtime package, it
|
|
|
|
|
|
// will define the runtime.firstmoduledata symbol and we
|
|
|
|
|
|
// truncate it back to 0 bytes so we can define its entire
|
|
|
|
|
|
// contents in symtab.go:symtab().
|
|
|
|
|
|
mdsb.SetSize(0)
|
|
|
|
|
|
|
|
|
|
|
|
// In addition, on ARM, the runtime depends on the linker
|
|
|
|
|
|
// recording the value of GOARM.
|
|
|
|
|
|
if ctxt.Arch.Family == sys.ARM {
|
|
|
|
|
|
goarm := ctxt.loader.LookupOrCreateSym("runtime.goarm", 0)
|
2020-02-12 17:23:47 -05:00
|
|
|
|
sb := ctxt.loader.MakeSymbolUpdater(goarm)
|
2024-09-25 22:34:43 -07:00
|
|
|
|
sb.SetType(sym.SNOPTRDATA)
|
2019-12-30 14:12:54 -05:00
|
|
|
|
sb.SetSize(0)
|
2023-07-29 18:25:42 -07:00
|
|
|
|
sb.AddUint8(uint8(buildcfg.GOARM.Version))
|
|
|
|
|
|
|
|
|
|
|
|
goarmsoftfp := ctxt.loader.LookupOrCreateSym("runtime.goarmsoftfp", 0)
|
|
|
|
|
|
sb2 := ctxt.loader.MakeSymbolUpdater(goarmsoftfp)
|
2024-09-25 22:34:43 -07:00
|
|
|
|
sb2.SetType(sym.SNOPTRDATA)
|
2023-07-29 18:25:42 -07:00
|
|
|
|
sb2.SetSize(0)
|
|
|
|
|
|
if buildcfg.GOARM.SoftFloat {
|
|
|
|
|
|
sb2.AddUint8(1)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
sb2.AddUint8(0)
|
|
|
|
|
|
}
|
2019-12-30 14:12:54 -05:00
|
|
|
|
}
|
2021-03-07 20:52:48 -08:00
|
|
|
|
|
|
|
|
|
|
// Set runtime.disableMemoryProfiling bool if
|
2024-07-03 14:14:34 -04:00
|
|
|
|
// runtime.memProfileInternal is not retained in the binary after
|
2021-03-07 20:52:48 -08:00
|
|
|
|
// deadcode (and we're not dynamically linking).
|
2024-07-03 14:14:34 -04:00
|
|
|
|
memProfile := ctxt.loader.Lookup("runtime.memProfileInternal", abiInternalVer)
|
2021-03-07 20:52:48 -08:00
|
|
|
|
if memProfile != 0 && !ctxt.loader.AttrReachable(memProfile) && !ctxt.DynlinkingGo() {
|
|
|
|
|
|
memProfSym := ctxt.loader.LookupOrCreateSym("runtime.disableMemoryProfiling", 0)
|
|
|
|
|
|
sb := ctxt.loader.MakeSymbolUpdater(memProfSym)
|
2024-09-25 22:34:43 -07:00
|
|
|
|
sb.SetType(sym.SNOPTRDATA)
|
2021-03-07 20:52:48 -08:00
|
|
|
|
sb.SetSize(0)
|
|
|
|
|
|
sb.AddUint8(1) // true bool
|
|
|
|
|
|
}
|
2019-12-30 14:12:54 -05:00
|
|
|
|
} else {
|
|
|
|
|
|
// If OTOH the module does not contain the runtime package,
|
|
|
|
|
|
// create a local symbol for the moduledata.
|
2020-02-12 17:23:47 -05:00
|
|
|
|
moduledata = ctxt.loader.LookupOrCreateSym("local.moduledata", 0)
|
|
|
|
|
|
mdsb = ctxt.loader.MakeSymbolUpdater(moduledata)
|
2019-12-30 14:12:54 -05:00
|
|
|
|
ctxt.loader.SetAttrLocal(moduledata, true)
|
|
|
|
|
|
}
|
|
|
|
|
|
// In all cases way we mark the moduledata as noptrdata to hide it from
|
|
|
|
|
|
// the GC.
|
|
|
|
|
|
mdsb.SetType(sym.SNOPTRDATA)
|
|
|
|
|
|
ctxt.loader.SetAttrReachable(moduledata, true)
|
2020-05-15 18:35:05 -04:00
|
|
|
|
ctxt.Moduledata = moduledata
|
2019-12-30 14:12:54 -05:00
|
|
|
|
|
|
|
|
|
|
if ctxt.Arch == sys.Arch386 && ctxt.HeadType != objabi.Hwindows {
|
|
|
|
|
|
if (ctxt.BuildMode == BuildModeCArchive && ctxt.IsELF) || ctxt.BuildMode == BuildModeCShared || ctxt.BuildMode == BuildModePIE || ctxt.DynlinkingGo() {
|
2020-02-12 17:23:47 -05:00
|
|
|
|
got := ctxt.loader.LookupOrCreateSym("_GLOBAL_OFFSET_TABLE_", 0)
|
|
|
|
|
|
sb := ctxt.loader.MakeSymbolUpdater(got)
|
2019-12-30 14:12:54 -05:00
|
|
|
|
sb.SetType(sym.SDYNIMPORT)
|
|
|
|
|
|
ctxt.loader.SetAttrReachable(got, true)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2020-02-25 09:07:39 -05:00
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
|
// DWARF-gen and other phases require that the unit Textp slices
|
2020-02-25 09:07:39 -05:00
|
|
|
|
// be populated, so that it can walk the functions in each unit.
|
|
|
|
|
|
// Call into the loader to do this (requires that we collect the
|
|
|
|
|
|
// set of internal libraries first). NB: might be simpler if we
|
|
|
|
|
|
// moved isRuntimeDepPkg to cmd/internal and then did the test in
|
|
|
|
|
|
// loader.AssignTextSymbolOrder.
|
|
|
|
|
|
ctxt.Library = postorder(ctxt.Library)
|
|
|
|
|
|
intlibs := []bool{}
|
|
|
|
|
|
for _, lib := range ctxt.Library {
|
|
|
|
|
|
intlibs = append(intlibs, isRuntimeDepPkg(lib.Pkg))
|
|
|
|
|
|
}
|
2020-05-15 18:35:05 -04:00
|
|
|
|
ctxt.Textp = ctxt.loader.AssignTextSymbolOrder(ctxt.Library, intlibs, ctxt.Textp)
|
2019-12-30 14:12:54 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-08-23 14:01:59 +02:00
|
|
|
|
// mangleTypeSym shortens the names of symbols that represent Go types
|
|
|
|
|
|
// if they are visible in the symbol table.
|
2017-09-30 12:36:34 +00:00
|
|
|
|
//
|
|
|
|
|
|
// As the names of these symbols are derived from the string of
|
|
|
|
|
|
// the type, they can run to many kilobytes long. So we shorten
|
|
|
|
|
|
// them using a SHA-1 when the name appears in the final binary.
|
2018-08-23 14:01:59 +02:00
|
|
|
|
// This also removes characters that upset external linkers.
|
2017-09-30 12:36:34 +00:00
|
|
|
|
//
|
|
|
|
|
|
// These are the symbols that begin with the prefix 'type.' and
|
|
|
|
|
|
// contain run-time type information used by the runtime and reflect
|
2018-10-08 01:19:51 +00:00
|
|
|
|
// packages. All Go binaries contain these symbols, but only
|
2017-09-30 12:36:34 +00:00
|
|
|
|
// those programs loaded dynamically in multiple parts need these
|
|
|
|
|
|
// symbols to have entries in the symbol table.
|
2018-08-23 14:01:59 +02:00
|
|
|
|
func (ctxt *Link) mangleTypeSym() {
|
2018-11-01 12:30:23 -04:00
|
|
|
|
if ctxt.BuildMode != BuildModeShared && !ctxt.linkShared && ctxt.BuildMode != BuildModePlugin && !ctxt.CanUsePlugins() {
|
2018-08-23 14:01:59 +02:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-03-21 13:50:46 -04:00
|
|
|
|
ldr := ctxt.loader
|
|
|
|
|
|
for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
|
2020-09-18 11:56:43 -04:00
|
|
|
|
if !ldr.AttrReachable(s) && !ctxt.linkShared {
|
2024-09-25 22:34:43 -07:00
|
|
|
|
// If -linkshared, the gc mask generation code may need to reach
|
2020-09-18 11:56:43 -04:00
|
|
|
|
// out to the shared library for the type descriptor's data, even
|
|
|
|
|
|
// the type descriptor itself is not actually needed at run time
|
|
|
|
|
|
// (therefore not reachable). We still need to mangle its name,
|
|
|
|
|
|
// so it is consistent with the one stored in the shared library.
|
2020-03-21 13:50:46 -04:00
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
name := ldr.SymName(s)
|
|
|
|
|
|
newName := typeSymbolMangle(name)
|
|
|
|
|
|
if newName != name {
|
|
|
|
|
|
ldr.SetSymExtname(s, newName)
|
|
|
|
|
|
|
|
|
|
|
|
// When linking against a shared library, the Go object file may
|
|
|
|
|
|
// have reference to the original symbol name whereas the shared
|
|
|
|
|
|
// library provides a symbol with the mangled name. We need to
|
|
|
|
|
|
// copy the payload of mangled to original.
|
|
|
|
|
|
// XXX maybe there is a better way to do this.
|
|
|
|
|
|
dup := ldr.Lookup(newName, ldr.SymVersion(s))
|
|
|
|
|
|
if dup != 0 {
|
|
|
|
|
|
st := ldr.SymType(s)
|
|
|
|
|
|
dt := ldr.SymType(dup)
|
|
|
|
|
|
if st == sym.Sxxx && dt != sym.Sxxx {
|
|
|
|
|
|
ldr.CopySym(dup, s)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2018-08-23 14:01:59 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2017-09-30 12:36:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// typeSymbolMangle mangles the given symbol name into something shorter.
|
2018-08-23 14:01:59 +02:00
|
|
|
|
//
|
2021-05-08 00:45:06 +07:00
|
|
|
|
// Keep the type:. prefix, which parts of the linker (like the
|
2018-08-23 14:01:59 +02:00
|
|
|
|
// DWARF generator) know means the symbol is not decodable.
|
2021-05-08 00:45:06 +07:00
|
|
|
|
// Leave type:runtime. symbols alone, because other parts of
|
2018-08-23 14:01:59 +02:00
|
|
|
|
// the linker manipulates them.
|
2017-10-09 10:11:00 +01:00
|
|
|
|
func typeSymbolMangle(name string) string {
|
2023-06-01 17:35:28 -04:00
|
|
|
|
isType := strings.HasPrefix(name, "type:")
|
|
|
|
|
|
if !isType && !strings.Contains(name, "@") {
|
|
|
|
|
|
// Issue 58800: instantiated symbols may include a type name, which may contain "@"
|
2017-09-30 12:36:34 +00:00
|
|
|
|
return name
|
|
|
|
|
|
}
|
2021-05-08 00:45:06 +07:00
|
|
|
|
if strings.HasPrefix(name, "type:runtime.") {
|
2017-09-30 12:36:34 +00:00
|
|
|
|
return name
|
|
|
|
|
|
}
|
2023-08-18 11:10:23 -04:00
|
|
|
|
if strings.HasPrefix(name, "go:string.") {
|
|
|
|
|
|
// String symbols will be grouped to a single go:string.* symbol.
|
|
|
|
|
|
// No need to mangle individual symbol names.
|
|
|
|
|
|
return name
|
|
|
|
|
|
}
|
2017-09-30 12:36:34 +00:00
|
|
|
|
if len(name) <= 14 && !strings.Contains(name, "@") { // Issue 19529
|
|
|
|
|
|
return name
|
|
|
|
|
|
}
|
2023-06-01 17:35:28 -04:00
|
|
|
|
if isType {
|
2025-01-07 11:28:44 -05:00
|
|
|
|
hb := hash.Sum32([]byte(name[5:]))
|
2023-06-01 17:35:28 -04:00
|
|
|
|
prefix := "type:"
|
|
|
|
|
|
if name[5] == '.' {
|
|
|
|
|
|
prefix = "type:."
|
|
|
|
|
|
}
|
2024-09-04 18:30:35 +07:00
|
|
|
|
return prefix + base64.StdEncoding.EncodeToString(hb[:6])
|
2023-06-01 17:35:28 -04:00
|
|
|
|
}
|
|
|
|
|
|
// instantiated symbol, replace type name in []
|
|
|
|
|
|
i := strings.IndexByte(name, '[')
|
|
|
|
|
|
j := strings.LastIndexByte(name, ']')
|
2023-08-18 11:10:23 -04:00
|
|
|
|
if j == -1 || j <= i {
|
2023-06-01 17:35:28 -04:00
|
|
|
|
j = len(name)
|
2017-09-30 12:36:34 +00:00
|
|
|
|
}
|
2025-01-07 11:28:44 -05:00
|
|
|
|
hb := hash.Sum32([]byte(name[i+1 : j]))
|
2024-09-04 18:30:35 +07:00
|
|
|
|
return name[:i+1] + base64.StdEncoding.EncodeToString(hb[:6]) + name[j:]
|
2017-09-30 12:36:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2015-02-27 22:57:28 -05:00
|
|
|
|
/*
|
|
|
|
|
|
* look for the next file in an archive.
|
|
|
|
|
|
* adapted from libmach.
|
|
|
|
|
|
*/
|
2016-04-08 19:14:03 +10:00
|
|
|
|
func nextar(bp *bio.Reader, off int64, a *ArHdr) int64 {
|
2015-02-27 22:57:28 -05:00
|
|
|
|
if off&1 != 0 {
|
|
|
|
|
|
off++
|
|
|
|
|
|
}
|
2019-05-08 18:46:04 -04:00
|
|
|
|
bp.MustSeek(off, 0)
|
2016-04-08 18:19:10 +02:00
|
|
|
|
var buf [SAR_HDR]byte
|
|
|
|
|
|
if n, err := io.ReadFull(bp, buf[:]); err != nil {
|
|
|
|
|
|
if n == 0 && err != io.EOF {
|
|
|
|
|
|
return -1
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
2016-04-08 18:19:10 +02:00
|
|
|
|
return 0
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
a.name = artrim(buf[0:16])
|
|
|
|
|
|
a.date = artrim(buf[16:28])
|
|
|
|
|
|
a.uid = artrim(buf[28:34])
|
|
|
|
|
|
a.gid = artrim(buf[34:40])
|
|
|
|
|
|
a.mode = artrim(buf[40:48])
|
|
|
|
|
|
a.size = artrim(buf[48:58])
|
|
|
|
|
|
a.fmag = artrim(buf[58:60])
|
|
|
|
|
|
|
|
|
|
|
|
arsize := atolwhex(a.size)
|
|
|
|
|
|
if arsize&1 != 0 {
|
|
|
|
|
|
arsize++
|
|
|
|
|
|
}
|
2016-04-14 19:04:45 -07:00
|
|
|
|
return arsize + SAR_HDR
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-09-30 17:28:05 +00:00
|
|
|
|
func loadobjfile(ctxt *Link, lib *sym.Library) {
|
2017-04-17 18:46:09 -05:00
|
|
|
|
pkg := objabi.PathToPrefix(lib.Pkg)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
2016-08-21 18:25:28 -04:00
|
|
|
|
if ctxt.Debugvlog > 1 {
|
2019-04-13 16:42:48 +03:00
|
|
|
|
ctxt.Logf("ldobj: %s (%s)\n", lib.File, pkg)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
2016-04-06 21:45:29 -07:00
|
|
|
|
f, err := bio.Open(lib.File)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
if err != nil {
|
2015-04-11 12:05:21 +08:00
|
|
|
|
Exitf("cannot open file %s: %v", lib.File, err)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
2018-03-23 10:28:39 -07:00
|
|
|
|
defer f.Close()
|
|
|
|
|
|
defer func() {
|
|
|
|
|
|
if pkg == "main" && !lib.Main {
|
|
|
|
|
|
Exitf("%s: not package main", lib.File)
|
|
|
|
|
|
}
|
|
|
|
|
|
}()
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
2016-04-08 18:19:10 +02:00
|
|
|
|
for i := 0; i < len(ARMAG); i++ {
|
|
|
|
|
|
if c, err := f.ReadByte(); err == nil && c == ARMAG[i] {
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-02-27 22:57:28 -05:00
|
|
|
|
/* load it as a regular file */
|
2019-05-08 18:46:04 -04:00
|
|
|
|
l := f.MustSeek(0, 2)
|
|
|
|
|
|
f.MustSeek(0, 0)
|
2018-03-23 10:28:39 -07:00
|
|
|
|
ldobj(ctxt, f, lib, l, lib.File, lib.File)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* load all the object files from the archive now.
|
|
|
|
|
|
* this gives us sequential file access and keeps us
|
|
|
|
|
|
* from needing to come back later to pick up more
|
|
|
|
|
|
* objects. it breaks the usual C archive model, but
|
|
|
|
|
|
* this is Go, not C. the common case in Go is that
|
|
|
|
|
|
* we need to load all the objects, and then we throw away
|
|
|
|
|
|
* the individual symbols that are unused.
|
|
|
|
|
|
*
|
|
|
|
|
|
* loading every object will also make it possible to
|
2016-02-25 14:58:03 -08:00
|
|
|
|
* load foreign objects not referenced by __.PKGDEF.
|
2015-02-27 22:57:28 -05:00
|
|
|
|
*/
|
2018-03-23 10:28:39 -07:00
|
|
|
|
var arhdr ArHdr
|
|
|
|
|
|
off := f.Offset()
|
2015-02-27 22:57:28 -05:00
|
|
|
|
for {
|
2018-03-23 10:28:39 -07:00
|
|
|
|
l := nextar(f, off, &arhdr)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
if l == 0 {
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
if l < 0 {
|
2015-04-11 12:05:21 +08:00
|
|
|
|
Exitf("%s: malformed archive", lib.File)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
off += l
|
|
|
|
|
|
|
2018-03-23 10:28:39 -07:00
|
|
|
|
// __.PKGDEF isn't a real Go object file, and it's
|
|
|
|
|
|
// absent in -linkobj builds anyway. Skipping it
|
|
|
|
|
|
// ensures consistency between -linkobj and normal
|
|
|
|
|
|
// build modes.
|
|
|
|
|
|
if arhdr.name == pkgdef {
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-06-21 18:11:32 -07:00
|
|
|
|
if arhdr.name == "dynimportfail" {
|
|
|
|
|
|
dynimportfail = append(dynimportfail, lib.Pkg)
|
|
|
|
|
|
}
|
2023-03-10 10:29:38 -05:00
|
|
|
|
if arhdr.name == "preferlinkext" {
|
|
|
|
|
|
// Ignore this directive if -linkmode has been
|
|
|
|
|
|
// set explicitly.
|
|
|
|
|
|
if ctxt.LinkMode == LinkAuto {
|
|
|
|
|
|
preferlinkext = append(preferlinkext, lib.Pkg)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-06-21 18:11:32 -07:00
|
|
|
|
|
2018-10-31 13:18:17 -04:00
|
|
|
|
// Skip other special (non-object-file) sections that
|
|
|
|
|
|
// build tools may have added. Such sections must have
|
|
|
|
|
|
// short names so that the suffix is not truncated.
|
2018-12-13 23:55:22 -05:00
|
|
|
|
if len(arhdr.name) < 16 {
|
|
|
|
|
|
if ext := filepath.Ext(arhdr.name); ext != ".o" && ext != ".syso" {
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
2018-10-31 13:18:17 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-03-23 10:28:39 -07:00
|
|
|
|
pname := fmt.Sprintf("%s(%s)", lib.File, arhdr.name)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
l = atolwhex(arhdr.size)
|
2018-03-23 10:28:39 -07:00
|
|
|
|
ldobj(ctxt, f, lib, l, pname, lib.File)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type Hostobj struct {
|
2016-08-19 22:40:38 -04:00
|
|
|
|
ld func(*Link, *bio.Reader, string, int64, string)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
pkg string
|
|
|
|
|
|
pn string
|
|
|
|
|
|
file string
|
|
|
|
|
|
off int64
|
|
|
|
|
|
length int64
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var hostobj []Hostobj
|
|
|
|
|
|
|
|
|
|
|
|
// These packages can use internal linking mode.
|
|
|
|
|
|
// Others trigger external mode.
|
|
|
|
|
|
var internalpkg = []string{
|
2017-08-22 22:52:15 -04:00
|
|
|
|
"crypto/internal/boring",
|
2022-04-27 09:02:52 -04:00
|
|
|
|
"crypto/internal/boring/syso",
|
2023-02-23 20:17:09 +00:00
|
|
|
|
"crypto/x509",
|
|
|
|
|
|
"net",
|
|
|
|
|
|
"os/user",
|
2015-02-27 22:57:28 -05:00
|
|
|
|
"runtime/cgo",
|
|
|
|
|
|
"runtime/race",
|
2022-09-30 14:25:29 +00:00
|
|
|
|
"runtime/race/internal/amd64v1",
|
|
|
|
|
|
"runtime/race/internal/amd64v3",
|
2015-10-21 07:11:01 -07:00
|
|
|
|
"runtime/msan",
|
2021-01-04 16:23:01 +08:00
|
|
|
|
"runtime/asan",
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-10-07 13:49:44 -04:00
|
|
|
|
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 {
|
2015-03-02 11:31:29 -08:00
|
|
|
|
isinternal := false
|
2018-04-06 21:41:06 +01:00
|
|
|
|
for _, intpkg := range internalpkg {
|
|
|
|
|
|
if pkg == intpkg {
|
2015-03-02 11:31:29 -08:00
|
|
|
|
isinternal = true
|
2015-02-27 22:57:28 -05:00
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// DragonFly declares errno with __thread, which results in a symbol
|
|
|
|
|
|
// type of R_386_TLS_GD or R_X86_64_TLSGD. The Go linker does not
|
|
|
|
|
|
// currently know how to handle TLS relocations, hence we have to
|
|
|
|
|
|
// force external linking for any libraries that link in code that
|
|
|
|
|
|
// uses errno. This can be removed if the Go linker ever supports
|
|
|
|
|
|
// these relocation types.
|
2017-10-07 13:49:44 -04:00
|
|
|
|
if headType == objabi.Hdragonfly {
|
2015-02-27 22:57:28 -05:00
|
|
|
|
if pkg == "net" || pkg == "os/user" {
|
2015-03-02 11:31:29 -08:00
|
|
|
|
isinternal = false
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-03-02 11:31:29 -08:00
|
|
|
|
if !isinternal {
|
|
|
|
|
|
externalobj = true
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
hostobj = append(hostobj, Hostobj{})
|
2015-03-02 12:35:15 -05:00
|
|
|
|
h := &hostobj[len(hostobj)-1]
|
2015-02-27 22:57:28 -05:00
|
|
|
|
h.ld = ld
|
|
|
|
|
|
h.pkg = pkg
|
|
|
|
|
|
h.pn = pn
|
|
|
|
|
|
h.file = file
|
2016-04-08 19:14:03 +10:00
|
|
|
|
h.off = f.Offset()
|
2015-02-27 22:57:28 -05:00
|
|
|
|
h.length = length
|
2015-11-04 11:14:19 -08:00
|
|
|
|
return h
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-08-19 22:40:38 -04:00
|
|
|
|
func hostobjs(ctxt *Link) {
|
2019-10-17 11:06:11 -04:00
|
|
|
|
if ctxt.LinkMode != LinkInternal {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
|
var h *Hostobj
|
|
|
|
|
|
|
2015-03-02 12:35:15 -05:00
|
|
|
|
for i := 0; i < len(hostobj); i++ {
|
2015-02-27 22:57:28 -05:00
|
|
|
|
h = &hostobj[i]
|
2016-04-08 19:14:03 +10:00
|
|
|
|
f, err := bio.Open(h.file)
|
|
|
|
|
|
if err != nil {
|
2015-04-09 07:37:17 -04:00
|
|
|
|
Exitf("cannot reopen %s: %v", h.pn, err)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
2019-05-08 18:46:04 -04:00
|
|
|
|
f.MustSeek(h.off, 0)
|
2021-05-25 16:31:41 -07:00
|
|
|
|
if h.ld == nil {
|
2024-11-01 14:56:25 -04:00
|
|
|
|
Errorf("%s: unrecognized object file format", h.pn)
|
2021-05-25 16:31:41 -07:00
|
|
|
|
continue
|
|
|
|
|
|
}
|
2016-08-19 22:40:38 -04:00
|
|
|
|
h.ld(ctxt, f, h.pkg, h.length, h.pn)
|
2022-11-01 11:08:00 -04:00
|
|
|
|
if *flagCaptureHostObjs != "" {
|
|
|
|
|
|
captureHostObj(h)
|
|
|
|
|
|
}
|
2016-04-06 21:45:29 -07:00
|
|
|
|
f.Close()
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-10-01 02:37:20 +00:00
|
|
|
|
func hostlinksetup(ctxt *Link) {
|
2017-10-05 10:20:17 -04:00
|
|
|
|
if ctxt.LinkMode != LinkExternal {
|
2015-02-27 22:57:28 -05:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-06-29 13:12:10 -04:00
|
|
|
|
// For external link, record that we need to tell the external linker -s,
|
|
|
|
|
|
// and turn off -s internally: the external linker needs the symbol
|
|
|
|
|
|
// information for its final link.
|
2016-08-21 18:34:24 -04:00
|
|
|
|
debug_s = *FlagS
|
|
|
|
|
|
*FlagS = false
|
2015-06-29 13:12:10 -04:00
|
|
|
|
|
2015-02-27 22:57:28 -05:00
|
|
|
|
// create temporary directory and arrange cleanup
|
2016-08-21 18:34:24 -04:00
|
|
|
|
if *flagTmpdir == "" {
|
2022-08-28 03:38:00 +08:00
|
|
|
|
dir, err := os.MkdirTemp("", "go-link-")
|
2015-02-27 22:57:28 -05:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
|
}
|
2016-08-21 18:34:24 -04:00
|
|
|
|
*flagTmpdir = dir
|
2019-10-28 11:51:13 -04:00
|
|
|
|
ownTmpDir = true
|
2018-05-20 14:53:00 +10:00
|
|
|
|
AtExit(func() {
|
|
|
|
|
|
os.RemoveAll(*flagTmpdir)
|
|
|
|
|
|
})
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// change our output to temporary object file
|
2020-03-17 10:24:40 -04:00
|
|
|
|
if err := ctxt.Out.Close(); err != nil {
|
|
|
|
|
|
Exitf("error closing output file")
|
|
|
|
|
|
}
|
2015-07-15 09:05:33 -07:00
|
|
|
|
mayberemoveoutfile()
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
2016-08-21 18:34:24 -04:00
|
|
|
|
p := filepath.Join(*flagTmpdir, "go.o")
|
2020-03-17 10:24:40 -04:00
|
|
|
|
if err := ctxt.Out.Open(p); err != nil {
|
2015-04-09 07:37:17 -04:00
|
|
|
|
Exitf("cannot create %s: %v", p, err)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-05-14 14:59:03 +00:00
|
|
|
|
// cleanTimeStamps resets the timestamps for the specified list of
|
|
|
|
|
|
// existing files to the Unix epoch (1970-01-01 00:00:00 +0000 UTC).
|
|
|
|
|
|
// We take this step in order to help preserve reproducible builds;
|
2024-08-19 00:07:37 +03:00
|
|
|
|
// this seems to be primarily needed for external linking on Darwin
|
2024-05-14 14:59:03 +00:00
|
|
|
|
// with later versions of xcode, which (unfortunately) seem to want to
|
|
|
|
|
|
// incorporate object file times into the final output file's build
|
|
|
|
|
|
// ID. See issue 64947 for the unpleasant details.
|
|
|
|
|
|
func cleanTimeStamps(files []string) {
|
|
|
|
|
|
epocht := time.Unix(0, 0)
|
|
|
|
|
|
for _, f := range files {
|
|
|
|
|
|
if err := os.Chtimes(f, epocht, epocht); err != nil {
|
|
|
|
|
|
Exitf("cannot chtimes %s: %v", f, err)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-04-09 10:44:05 -04:00
|
|
|
|
// hostobjCopy creates a copy of the object files in hostobj in a
|
|
|
|
|
|
// temporary directory.
|
2022-12-20 19:31:40 -05:00
|
|
|
|
func (ctxt *Link) hostobjCopy() (paths []string) {
|
2015-10-28 14:41:58 -04:00
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
|
|
sema := make(chan struct{}, runtime.NumCPU()) // limit open file descriptors
|
2015-04-09 10:44:05 -04:00
|
|
|
|
for i, h := range hostobj {
|
2015-10-28 14:41:58 -04:00
|
|
|
|
h := h
|
2016-08-21 18:34:24 -04:00
|
|
|
|
dst := filepath.Join(*flagTmpdir, fmt.Sprintf("%06d.o", i))
|
2015-10-28 14:41:58 -04:00
|
|
|
|
paths = append(paths, dst)
|
2022-12-20 19:31:40 -05:00
|
|
|
|
if ctxt.Debugvlog != 0 {
|
|
|
|
|
|
ctxt.Logf("host obj copy: %s from pkg %s -> %s\n", h.pn, h.pkg, dst)
|
|
|
|
|
|
}
|
2015-10-28 14:41:58 -04:00
|
|
|
|
|
|
|
|
|
|
wg.Add(1)
|
|
|
|
|
|
go func() {
|
|
|
|
|
|
sema <- struct{}{}
|
|
|
|
|
|
defer func() {
|
|
|
|
|
|
<-sema
|
|
|
|
|
|
wg.Done()
|
|
|
|
|
|
}()
|
|
|
|
|
|
f, err := os.Open(h.file)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
Exitf("cannot reopen %s: %v", h.pn, err)
|
|
|
|
|
|
}
|
2018-12-05 09:52:19 -08:00
|
|
|
|
defer f.Close()
|
2015-10-28 14:41:58 -04:00
|
|
|
|
if _, err := f.Seek(h.off, 0); err != nil {
|
|
|
|
|
|
Exitf("cannot seek %s: %v", h.pn, err)
|
|
|
|
|
|
}
|
2015-04-09 10:44:05 -04:00
|
|
|
|
|
2015-10-28 14:41:58 -04:00
|
|
|
|
w, err := os.Create(dst)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
Exitf("cannot create %s: %v", dst, err)
|
|
|
|
|
|
}
|
|
|
|
|
|
if _, err := io.CopyN(w, f, h.length); err != nil {
|
|
|
|
|
|
Exitf("cannot write %s: %v", dst, err)
|
|
|
|
|
|
}
|
|
|
|
|
|
if err := w.Close(); err != nil {
|
|
|
|
|
|
Exitf("cannot close %s: %v", dst, err)
|
|
|
|
|
|
}
|
|
|
|
|
|
}()
|
2015-04-09 10:44:05 -04:00
|
|
|
|
}
|
2015-10-28 14:41:58 -04:00
|
|
|
|
wg.Wait()
|
2015-04-09 10:44:05 -04:00
|
|
|
|
return paths
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-05-11 11:55:59 +10:00
|
|
|
|
// writeGDBLinkerScript creates gcc linker script file in temp
|
|
|
|
|
|
// directory. writeGDBLinkerScript returns created file path.
|
|
|
|
|
|
// The script is used to work around gcc bug
|
|
|
|
|
|
// (see https://golang.org/issue/20183 for details).
|
|
|
|
|
|
func writeGDBLinkerScript() string {
|
|
|
|
|
|
name := "fix_debug_gdb_scripts.ld"
|
|
|
|
|
|
path := filepath.Join(*flagTmpdir, name)
|
|
|
|
|
|
src := `SECTIONS
|
|
|
|
|
|
{
|
|
|
|
|
|
.debug_gdb_scripts BLOCK(__section_alignment__) (NOLOAD) :
|
|
|
|
|
|
{
|
|
|
|
|
|
*(.debug_gdb_scripts)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
INSERT AFTER .debug_types;
|
|
|
|
|
|
`
|
2022-08-28 03:38:00 +08:00
|
|
|
|
err := os.WriteFile(path, []byte(src), 0666)
|
2017-05-11 11:55:59 +10:00
|
|
|
|
if err != nil {
|
2024-11-01 14:56:25 -04:00
|
|
|
|
Errorf("WriteFile %s failed: %v", name, err)
|
2017-05-11 11:55:59 +10:00
|
|
|
|
}
|
|
|
|
|
|
return path
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-05-20 14:52:57 +00:00
|
|
|
|
type machoUpdateFunc func(ctxt *Link, exef *os.File, exem *macho.File, outexe string) error
|
|
|
|
|
|
|
2015-04-09 10:44:05 -04:00
|
|
|
|
// archive builds a .a archive from the hostobj object files.
|
2016-08-21 13:52:23 -04:00
|
|
|
|
func (ctxt *Link) archive() {
|
2017-10-05 10:20:17 -04:00
|
|
|
|
if ctxt.BuildMode != BuildModeCArchive {
|
2015-04-09 10:44:05 -04:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-10-28 11:51:13 -04:00
|
|
|
|
exitIfErrors()
|
|
|
|
|
|
|
2016-08-21 18:34:24 -04:00
|
|
|
|
if *flagExtar == "" {
|
2023-03-28 09:17:27 -04:00
|
|
|
|
const printProgName = "--print-prog-name=ar"
|
|
|
|
|
|
cc := ctxt.extld()
|
2016-08-21 18:34:24 -04:00
|
|
|
|
*flagExtar = "ar"
|
2023-03-28 09:17:27 -04:00
|
|
|
|
if linkerFlagSupported(ctxt.Arch, cc[0], "", printProgName) {
|
|
|
|
|
|
*flagExtar = ctxt.findExtLinkTool("ar")
|
|
|
|
|
|
}
|
2016-01-25 11:44:02 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
2015-07-15 09:05:33 -07:00
|
|
|
|
mayberemoveoutfile()
|
2015-12-13 08:02:29 -05:00
|
|
|
|
|
|
|
|
|
|
// Force the buffer to flush here so that external
|
|
|
|
|
|
// tools will see a complete file.
|
2020-03-17 10:24:40 -04:00
|
|
|
|
if err := ctxt.Out.Close(); err != nil {
|
|
|
|
|
|
Exitf("error closing %v", *flagOutfile)
|
2015-12-13 08:02:29 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-03-25 10:33:49 +01:00
|
|
|
|
argv := []string{*flagExtar, "-q", "-c", "-s"}
|
|
|
|
|
|
if ctxt.HeadType == objabi.Haix {
|
|
|
|
|
|
argv = append(argv, "-X64")
|
|
|
|
|
|
}
|
2024-05-14 14:59:03 +00:00
|
|
|
|
godotopath := filepath.Join(*flagTmpdir, "go.o")
|
|
|
|
|
|
cleanTimeStamps([]string{godotopath})
|
|
|
|
|
|
hostObjCopyPaths := ctxt.hostobjCopy()
|
|
|
|
|
|
cleanTimeStamps(hostObjCopyPaths)
|
|
|
|
|
|
|
2019-03-25 10:33:49 +01:00
|
|
|
|
argv = append(argv, *flagOutfile)
|
2024-05-14 14:59:03 +00:00
|
|
|
|
argv = append(argv, godotopath)
|
|
|
|
|
|
argv = append(argv, hostObjCopyPaths...)
|
2015-04-09 10:44:05 -04:00
|
|
|
|
|
2016-08-21 18:25:28 -04:00
|
|
|
|
if ctxt.Debugvlog != 0 {
|
2016-08-25 12:32:42 +10:00
|
|
|
|
ctxt.Logf("archive: %s\n", strings.Join(argv, " "))
|
2015-04-09 10:44:05 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-10-28 11:51:13 -04:00
|
|
|
|
// If supported, use syscall.Exec() to invoke the archive command,
|
|
|
|
|
|
// which should be the final remaining step needed for the link.
|
|
|
|
|
|
// This will reduce peak RSS for the link (and speed up linking of
|
|
|
|
|
|
// large applications), since when the archive command runs we
|
|
|
|
|
|
// won't be holding onto all of the linker's live memory.
|
|
|
|
|
|
if syscallExecSupported && !ownTmpDir {
|
|
|
|
|
|
runAtExitFuncs()
|
|
|
|
|
|
ctxt.execArchive(argv)
|
|
|
|
|
|
panic("should not get here")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Otherwise invoke 'ar' in the usual way (fork + exec).
|
2015-04-09 10:44:05 -04:00
|
|
|
|
if out, err := exec.Command(argv[0], argv[1:]...).CombinedOutput(); err != nil {
|
2015-04-09 07:37:17 -04:00
|
|
|
|
Exitf("running %s failed: %v\n%s", argv[0], err, out)
|
2015-04-09 10:44:05 -04:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-10-05 10:20:17 -04:00
|
|
|
|
func (ctxt *Link) hostlink() {
|
|
|
|
|
|
if ctxt.LinkMode != LinkExternal || nerrors > 0 {
|
2015-02-27 22:57:28 -05:00
|
|
|
|
return
|
|
|
|
|
|
}
|
2017-10-05 10:20:17 -04:00
|
|
|
|
if ctxt.BuildMode == BuildModeCArchive {
|
2015-04-09 10:44:05 -04:00
|
|
|
|
return
|
|
|
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
2015-03-02 12:35:15 -05:00
|
|
|
|
var argv []string
|
cmd: support space and quotes in CC and CXX
The CC and CXX environment variables now support spaces and quotes
(both double and single). This fixes two issues: first, if CC is a
single path that contains spaces (like 'c:\Program
Files\gcc\bin\gcc.exe'), that should now work if the space is quoted
or escaped (#41400). Second, if CC or CXX has multiple arguments (like
'gcc -O2'), they are now split correctly, and the arguments are passed
before other arguments when invoking the C compiler. Previously,
strings.Fields was used to split arguments, and the arguments were
placed later in the command line. (#43078).
Fixes golang/go#41400
Fixes golang/go#43078
NOTE: This change also includes a fix (CL 341929) for a test that was
broken by the original CL. Commit message for the fix is below.
[dev.cmdgo] cmd/link: fix TestBuildForTvOS
This test was broken in CL 334732 on darwin.
The test invokes 'go build' with a CC containing the arguments
-framework CoreFoundation. Previously, the go command split CC on
whitespace, and inserted the arguments after the command line when
running CC directly. Those arguments weren't passed to cgo though,
so cgo ran CC without -framework CoreFoundation (or any of the other
flags).
In CL 334732, we pass CC through to cgo, and cgo splits arguments
using str.SplitQuotedFields. So -framework CoreFoundation actually
gets passed to the C compiler. It appears that -framework flags are
only meant to be used in linking operations, so when cgo invokes clang
with -E (run preprocessor only), clang emits an error that -framework
is unused.
This change fixes the test by moving -framework CoreFoundation out of
CC and into CGO_LDFLAGS.
Change-Id: I2d5d89ddb19c94adef65982a8137b01f037d5c11
Reviewed-on: https://go-review.googlesource.com/c/go/+/334732
Trust: Jay Conrod <jayconrod@google.com>
Trust: Michael Matloob <matloob@golang.org>
Run-TryBot: Jay Conrod <jayconrod@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Michael Matloob <matloob@golang.org>
Reviewed-on: https://go-review.googlesource.com/c/go/+/341936
Reviewed-by: Bryan C. Mills <bcmills@google.com>
2021-07-14 16:57:24 -07:00
|
|
|
|
argv = append(argv, ctxt.extld()...)
|
2017-10-05 10:20:17 -04:00
|
|
|
|
argv = append(argv, hostlinkArchArgs(ctxt.Arch)...)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
2017-10-26 10:15:29 -04:00
|
|
|
|
if *FlagS || debug_s {
|
|
|
|
|
|
if ctxt.HeadType == objabi.Hdarwin {
|
|
|
|
|
|
// Recent versions of macOS print
|
|
|
|
|
|
// ld: warning: option -s is obsolete and being ignored
|
2023-05-05 18:52:39 -04:00
|
|
|
|
// so do not pass any arguments (but we strip symbols below).
|
2017-10-26 10:15:29 -04:00
|
|
|
|
} else {
|
|
|
|
|
|
argv = append(argv, "-s")
|
|
|
|
|
|
}
|
2025-09-16 13:34:19 -04:00
|
|
|
|
} else if *FlagW {
|
2025-09-26 09:56:12 -04:00
|
|
|
|
if !ctxt.IsAIX() { // The AIX linker's -S has different meaning
|
|
|
|
|
|
argv = append(argv, "-Wl,-S") // suppress debugging symbols
|
|
|
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
cmd/link: strip STAB (symbolic debugging) symbols on darwin
On darwin, with external linking, the system linker produces STAB
(symbolic debugging) symbols in the binary's symbol table. These
include paths of the intermediate object files, like
<tmpdir>/go.o, which changes from run to run, making the build
non-reproducible.
Since we run dsymutil to produce debug info and combine them
back into the binary, we don't need those STAB symbols anymore.
Strip them after running dsymutil.
If DWARF is not enabled, we don't run dsymutil. We can pass
"-Wl,-S" to let the system linker not generate those symbols.
While here, also make it more consistent about DWARF combining.
Currently we only do DWARF combining on macOS/AMD64, when DWARF
is enabled. On ARM64, we run dsymutil, but then throw the result
away. This CL changes it to not run dsymutil (and strip) on
ARM64.
TODO: add a test. We don't do it here as it fails on some
(non-darwin) platforms.
Fixes #40979.
Change-Id: If770f7828cdb858857d6079e0585bf067f8f7a92
Reviewed-on: https://go-review.googlesource.com/c/go/+/250944
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
2020-08-26 18:19:03 -04:00
|
|
|
|
// On darwin, whether to combine DWARF into executable.
|
|
|
|
|
|
// Only macOS supports unmapped segments such as our __DWARF segment.
|
2023-05-05 18:52:39 -04:00
|
|
|
|
combineDwarf := ctxt.IsDarwin() && !*FlagW && machoPlatform == PLATFORM_MACOS
|
cmd/link: strip STAB (symbolic debugging) symbols on darwin
On darwin, with external linking, the system linker produces STAB
(symbolic debugging) symbols in the binary's symbol table. These
include paths of the intermediate object files, like
<tmpdir>/go.o, which changes from run to run, making the build
non-reproducible.
Since we run dsymutil to produce debug info and combine them
back into the binary, we don't need those STAB symbols anymore.
Strip them after running dsymutil.
If DWARF is not enabled, we don't run dsymutil. We can pass
"-Wl,-S" to let the system linker not generate those symbols.
While here, also make it more consistent about DWARF combining.
Currently we only do DWARF combining on macOS/AMD64, when DWARF
is enabled. On ARM64, we run dsymutil, but then throw the result
away. This CL changes it to not run dsymutil (and strip) on
ARM64.
TODO: add a test. We don't do it here as it fails on some
(non-darwin) platforms.
Fixes #40979.
Change-Id: If770f7828cdb858857d6079e0585bf067f8f7a92
Reviewed-on: https://go-review.googlesource.com/c/go/+/250944
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
2020-08-26 18:19:03 -04:00
|
|
|
|
|
cmd/link: support MSVC clang
Currently on Windows, for cgo, we support MinGW-based C toolchain,
that is, with a -windows-gnu target. This CL makes it work with
clang with a -windows-msvc target. The LLVM toolchain bundled in
MSVC (https://learn.microsoft.com/en-us/cpp/build/clang-support-msbuild)
is such an example.
Currently it is expecting lld-link as the C linker, which is also
bundled in MSVC, can be requested with -fuse-ld=lld, but is not
the default.
This is the first step, which makes it generate a working cgo
binary. There are still more work to do, e.g. there are some
linker warnings, and the binary doesn't have symbol table.
all.bat doesn't pass with this setting.
Change-Id: I54d33f7dd5f5eeeafa0735cd52f4127fe4865636
Reviewed-on: https://go-review.googlesource.com/c/go/+/703055
Reviewed-by: Than McIntosh <thanm@golang.org>
Reviewed-by: Florian Zenker <floriank@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2025-09-11 17:42:30 -04:00
|
|
|
|
var isMSVC bool // used on Windows
|
|
|
|
|
|
wlPrefix := "-Wl,--"
|
|
|
|
|
|
|
2017-10-07 13:49:44 -04:00
|
|
|
|
switch ctxt.HeadType {
|
2017-04-18 12:53:25 -07:00
|
|
|
|
case objabi.Hdarwin:
|
2020-09-04 14:35:57 -04:00
|
|
|
|
if combineDwarf {
|
2020-09-02 21:04:12 -04:00
|
|
|
|
// Leave room for DWARF combining.
|
2019-10-16 10:20:12 +02:00
|
|
|
|
// -headerpad is incompatible with -fembed-bitcode.
|
|
|
|
|
|
argv = append(argv, "-Wl,-headerpad,1144")
|
|
|
|
|
|
}
|
2021-04-15 23:05:49 -04:00
|
|
|
|
if ctxt.DynlinkingGo() && buildcfg.GOOS != "ios" {
|
2020-10-03 16:26:37 -04:00
|
|
|
|
// -flat_namespace is deprecated on iOS.
|
|
|
|
|
|
// It is useful for supporting plugins. We don't support plugins on iOS.
|
2021-12-16 14:33:13 -05:00
|
|
|
|
// -flat_namespace may cause the dynamic linker to hang at forkExec when
|
|
|
|
|
|
// resolving a lazy binding. See issue 38824.
|
|
|
|
|
|
// Force eager resolution to work around.
|
|
|
|
|
|
argv = append(argv, "-Wl,-flat_namespace", "-Wl,-bind_at_load")
|
2017-08-27 19:09:18 +09:00
|
|
|
|
}
|
cmd/link: strip STAB (symbolic debugging) symbols on darwin
On darwin, with external linking, the system linker produces STAB
(symbolic debugging) symbols in the binary's symbol table. These
include paths of the intermediate object files, like
<tmpdir>/go.o, which changes from run to run, making the build
non-reproducible.
Since we run dsymutil to produce debug info and combine them
back into the binary, we don't need those STAB symbols anymore.
Strip them after running dsymutil.
If DWARF is not enabled, we don't run dsymutil. We can pass
"-Wl,-S" to let the system linker not generate those symbols.
While here, also make it more consistent about DWARF combining.
Currently we only do DWARF combining on macOS/AMD64, when DWARF
is enabled. On ARM64, we run dsymutil, but then throw the result
away. This CL changes it to not run dsymutil (and strip) on
ARM64.
TODO: add a test. We don't do it here as it fails on some
(non-darwin) platforms.
Fixes #40979.
Change-Id: If770f7828cdb858857d6079e0585bf067f8f7a92
Reviewed-on: https://go-review.googlesource.com/c/go/+/250944
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
2020-08-26 18:19:03 -04:00
|
|
|
|
if !combineDwarf {
|
|
|
|
|
|
argv = append(argv, "-Wl,-S") // suppress STAB (symbolic debugging) symbols
|
2023-05-05 18:52:39 -04:00
|
|
|
|
if debug_s {
|
|
|
|
|
|
// We are generating a binary with symbol table suppressed.
|
|
|
|
|
|
// Suppress local symbols. We need to keep dynamically exported
|
|
|
|
|
|
// and referenced symbols so the dynamic linker can resolve them.
|
|
|
|
|
|
argv = append(argv, "-Wl,-x")
|
|
|
|
|
|
}
|
cmd/link: strip STAB (symbolic debugging) symbols on darwin
On darwin, with external linking, the system linker produces STAB
(symbolic debugging) symbols in the binary's symbol table. These
include paths of the intermediate object files, like
<tmpdir>/go.o, which changes from run to run, making the build
non-reproducible.
Since we run dsymutil to produce debug info and combine them
back into the binary, we don't need those STAB symbols anymore.
Strip them after running dsymutil.
If DWARF is not enabled, we don't run dsymutil. We can pass
"-Wl,-S" to let the system linker not generate those symbols.
While here, also make it more consistent about DWARF combining.
Currently we only do DWARF combining on macOS/AMD64, when DWARF
is enabled. On ARM64, we run dsymutil, but then throw the result
away. This CL changes it to not run dsymutil (and strip) on
ARM64.
TODO: add a test. We don't do it here as it fails on some
(non-darwin) platforms.
Fixes #40979.
Change-Id: If770f7828cdb858857d6079e0585bf067f8f7a92
Reviewed-on: https://go-review.googlesource.com/c/go/+/250944
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
2020-08-26 18:19:03 -04:00
|
|
|
|
}
|
2024-10-08 13:17:47 -04:00
|
|
|
|
if *flagHostBuildid == "none" {
|
|
|
|
|
|
argv = append(argv, "-Wl,-no_uuid")
|
|
|
|
|
|
}
|
2017-04-18 12:53:25 -07:00
|
|
|
|
case objabi.Hopenbsd:
|
2024-03-02 19:53:20 +11:00
|
|
|
|
argv = append(argv, "-pthread")
|
|
|
|
|
|
if ctxt.BuildMode != BuildModePIE {
|
|
|
|
|
|
argv = append(argv, "-Wl,-nopie")
|
|
|
|
|
|
}
|
2024-02-21 23:29:12 +11:00
|
|
|
|
if linkerFlagSupported(ctxt.Arch, argv[0], "", "-Wl,-z,nobtcfi") {
|
|
|
|
|
|
// -Wl,-z,nobtcfi is only supported on OpenBSD 7.4+, remove guard
|
|
|
|
|
|
// when OpenBSD 7.5 is released and 7.3 is no longer supported.
|
|
|
|
|
|
argv = append(argv, "-Wl,-z,nobtcfi")
|
|
|
|
|
|
}
|
2023-04-14 05:47:36 +10:00
|
|
|
|
if ctxt.Arch.InFamily(sys.ARM64) {
|
|
|
|
|
|
// Disable execute-only on openbsd/arm64 - the Go arm64 assembler
|
|
|
|
|
|
// currently stores constants in the text section rather than in rodata.
|
|
|
|
|
|
// See issue #59615.
|
|
|
|
|
|
argv = append(argv, "-Wl,--no-execute-only")
|
|
|
|
|
|
}
|
2017-04-18 12:53:25 -07:00
|
|
|
|
case objabi.Hwindows:
|
cmd/link: support MSVC clang
Currently on Windows, for cgo, we support MinGW-based C toolchain,
that is, with a -windows-gnu target. This CL makes it work with
clang with a -windows-msvc target. The LLVM toolchain bundled in
MSVC (https://learn.microsoft.com/en-us/cpp/build/clang-support-msbuild)
is such an example.
Currently it is expecting lld-link as the C linker, which is also
bundled in MSVC, can be requested with -fuse-ld=lld, but is not
the default.
This is the first step, which makes it generate a working cgo
binary. There are still more work to do, e.g. there are some
linker warnings, and the binary doesn't have symbol table.
all.bat doesn't pass with this setting.
Change-Id: I54d33f7dd5f5eeeafa0735cd52f4127fe4865636
Reviewed-on: https://go-review.googlesource.com/c/go/+/703055
Reviewed-by: Than McIntosh <thanm@golang.org>
Reviewed-by: Florian Zenker <floriank@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2025-09-11 17:42:30 -04:00
|
|
|
|
isMSVC = ctxt.isMSVC()
|
|
|
|
|
|
if isMSVC {
|
|
|
|
|
|
// For various options, MSVC lld-link only accepts one dash.
|
|
|
|
|
|
// TODO: It seems mingw clang supports one or two dashes,
|
|
|
|
|
|
// maybe we can always use one dash, but I'm not sure about
|
|
|
|
|
|
// legacy compilers that currently work.
|
|
|
|
|
|
wlPrefix = "-Wl,-"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-03-27 15:58:14 +11:00
|
|
|
|
if windowsgui {
|
|
|
|
|
|
argv = append(argv, "-mwindows")
|
|
|
|
|
|
} else {
|
|
|
|
|
|
argv = append(argv, "-mconsole")
|
|
|
|
|
|
}
|
2019-08-26 07:08:51 -06:00
|
|
|
|
// Mark as having awareness of terminal services, to avoid
|
|
|
|
|
|
// ancient compatibility hacks.
|
cmd/link: support MSVC clang
Currently on Windows, for cgo, we support MinGW-based C toolchain,
that is, with a -windows-gnu target. This CL makes it work with
clang with a -windows-msvc target. The LLVM toolchain bundled in
MSVC (https://learn.microsoft.com/en-us/cpp/build/clang-support-msbuild)
is such an example.
Currently it is expecting lld-link as the C linker, which is also
bundled in MSVC, can be requested with -fuse-ld=lld, but is not
the default.
This is the first step, which makes it generate a working cgo
binary. There are still more work to do, e.g. there are some
linker warnings, and the binary doesn't have symbol table.
all.bat doesn't pass with this setting.
Change-Id: I54d33f7dd5f5eeeafa0735cd52f4127fe4865636
Reviewed-on: https://go-review.googlesource.com/c/go/+/703055
Reviewed-by: Than McIntosh <thanm@golang.org>
Reviewed-by: Florian Zenker <floriank@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2025-09-11 17:42:30 -04:00
|
|
|
|
|
|
|
|
|
|
argv = append(argv, wlPrefix+"tsaware")
|
2019-08-26 07:21:36 -06:00
|
|
|
|
|
2019-10-26 22:41:31 +02:00
|
|
|
|
// Enable DEP
|
cmd/link: support MSVC clang
Currently on Windows, for cgo, we support MinGW-based C toolchain,
that is, with a -windows-gnu target. This CL makes it work with
clang with a -windows-msvc target. The LLVM toolchain bundled in
MSVC (https://learn.microsoft.com/en-us/cpp/build/clang-support-msbuild)
is such an example.
Currently it is expecting lld-link as the C linker, which is also
bundled in MSVC, can be requested with -fuse-ld=lld, but is not
the default.
This is the first step, which makes it generate a working cgo
binary. There are still more work to do, e.g. there are some
linker warnings, and the binary doesn't have symbol table.
all.bat doesn't pass with this setting.
Change-Id: I54d33f7dd5f5eeeafa0735cd52f4127fe4865636
Reviewed-on: https://go-review.googlesource.com/c/go/+/703055
Reviewed-by: Than McIntosh <thanm@golang.org>
Reviewed-by: Florian Zenker <floriank@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2025-09-11 17:42:30 -04:00
|
|
|
|
argv = append(argv, wlPrefix+"nxcompat")
|
2019-10-26 22:41:31 +02:00
|
|
|
|
|
cmd/link: support MSVC clang
Currently on Windows, for cgo, we support MinGW-based C toolchain,
that is, with a -windows-gnu target. This CL makes it work with
clang with a -windows-msvc target. The LLVM toolchain bundled in
MSVC (https://learn.microsoft.com/en-us/cpp/build/clang-support-msbuild)
is such an example.
Currently it is expecting lld-link as the C linker, which is also
bundled in MSVC, can be requested with -fuse-ld=lld, but is not
the default.
This is the first step, which makes it generate a working cgo
binary. There are still more work to do, e.g. there are some
linker warnings, and the binary doesn't have symbol table.
all.bat doesn't pass with this setting.
Change-Id: I54d33f7dd5f5eeeafa0735cd52f4127fe4865636
Reviewed-on: https://go-review.googlesource.com/c/go/+/703055
Reviewed-by: Than McIntosh <thanm@golang.org>
Reviewed-by: Florian Zenker <floriank@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2025-09-11 17:42:30 -04:00
|
|
|
|
if !isMSVC {
|
|
|
|
|
|
argv = append(argv, fmt.Sprintf("-Wl,--major-os-version=%d", PeMinimumTargetMajorVersion))
|
|
|
|
|
|
argv = append(argv, fmt.Sprintf("-Wl,--minor-os-version=%d", PeMinimumTargetMinorVersion))
|
|
|
|
|
|
argv = append(argv, fmt.Sprintf("-Wl,--major-subsystem-version=%d", PeMinimumTargetMajorVersion))
|
|
|
|
|
|
argv = append(argv, fmt.Sprintf("-Wl,--minor-subsystem-version=%d", PeMinimumTargetMinorVersion))
|
|
|
|
|
|
}
|
2019-02-20 16:16:38 +01:00
|
|
|
|
case objabi.Haix:
|
|
|
|
|
|
argv = append(argv, "-pthread")
|
|
|
|
|
|
// prevent ld to reorder .text functions to keep the same
|
|
|
|
|
|
// first/last functions for moduledata.
|
|
|
|
|
|
argv = append(argv, "-Wl,-bnoobjreorder")
|
2019-02-20 16:42:11 +01:00
|
|
|
|
// mcmodel=large is needed for every gcc generated files, but
|
|
|
|
|
|
// ld still need -bbigtoc in order to allow larger TOC.
|
|
|
|
|
|
argv = append(argv, "-mcmodel=large")
|
|
|
|
|
|
argv = append(argv, "-Wl,-bbigtoc")
|
2015-03-09 03:05:40 -04:00
|
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
2023-02-20 09:21:32 -06:00
|
|
|
|
// On PPC64, verify the external toolchain supports Power10. This is needed when
|
|
|
|
|
|
// PC relative relocations might be generated by Go. Only targets compiling ELF
|
|
|
|
|
|
// binaries might generate these relocations.
|
|
|
|
|
|
if ctxt.IsPPC64() && ctxt.IsElf() && buildcfg.GOPPC64 >= 10 {
|
|
|
|
|
|
if !linkerFlagSupported(ctxt.Arch, argv[0], "", "-mcpu=power10") {
|
|
|
|
|
|
Exitf("The external toolchain does not support -mcpu=power10. " +
|
|
|
|
|
|
" This is required to externally link GOPPC64 >= power10")
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-02-08 12:41:26 -05:00
|
|
|
|
// Enable/disable ASLR on Windows.
|
|
|
|
|
|
addASLRargs := func(argv []string, val bool) []string {
|
|
|
|
|
|
// Old/ancient versions of GCC support "--dynamicbase" and
|
|
|
|
|
|
// "--high-entropy-va" but don't enable it by default. In
|
|
|
|
|
|
// addition, they don't accept "--disable-dynamicbase" or
|
|
|
|
|
|
// "--no-dynamicbase", so the only way to disable ASLR is to
|
|
|
|
|
|
// not pass any flags at all.
|
|
|
|
|
|
//
|
|
|
|
|
|
// More modern versions of GCC (and also clang) enable ASLR
|
|
|
|
|
|
// by default. With these compilers, however you can turn it
|
|
|
|
|
|
// off if you want using "--disable-dynamicbase" or
|
|
|
|
|
|
// "--no-dynamicbase".
|
|
|
|
|
|
//
|
|
|
|
|
|
// The strategy below is to try using "--disable-dynamicbase";
|
|
|
|
|
|
// if this succeeds, then assume we're working with more
|
|
|
|
|
|
// modern compilers and act accordingly. If it fails, assume
|
|
|
|
|
|
// an ancient compiler with ancient defaults.
|
|
|
|
|
|
var dbopt string
|
|
|
|
|
|
var heopt string
|
cmd/link: support MSVC clang
Currently on Windows, for cgo, we support MinGW-based C toolchain,
that is, with a -windows-gnu target. This CL makes it work with
clang with a -windows-msvc target. The LLVM toolchain bundled in
MSVC (https://learn.microsoft.com/en-us/cpp/build/clang-support-msbuild)
is such an example.
Currently it is expecting lld-link as the C linker, which is also
bundled in MSVC, can be requested with -fuse-ld=lld, but is not
the default.
This is the first step, which makes it generate a working cgo
binary. There are still more work to do, e.g. there are some
linker warnings, and the binary doesn't have symbol table.
all.bat doesn't pass with this setting.
Change-Id: I54d33f7dd5f5eeeafa0735cd52f4127fe4865636
Reviewed-on: https://go-review.googlesource.com/c/go/+/703055
Reviewed-by: Than McIntosh <thanm@golang.org>
Reviewed-by: Florian Zenker <floriank@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2025-09-11 17:42:30 -04:00
|
|
|
|
dbon := wlPrefix + "dynamicbase"
|
|
|
|
|
|
heon := wlPrefix + "high-entropy-va"
|
|
|
|
|
|
dboff := wlPrefix + "disable-dynamicbase"
|
|
|
|
|
|
heoff := wlPrefix + "disable-high-entropy-va"
|
|
|
|
|
|
if isMSVC {
|
|
|
|
|
|
heon = wlPrefix + "highentropyva"
|
|
|
|
|
|
heoff = wlPrefix + "highentropyva:no"
|
|
|
|
|
|
dboff = wlPrefix + "dynamicbase:no"
|
|
|
|
|
|
}
|
2022-02-08 12:41:26 -05:00
|
|
|
|
if val {
|
|
|
|
|
|
dbopt = dbon
|
|
|
|
|
|
heopt = heon
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// Test to see whether "--disable-dynamicbase" works.
|
cmd/link: support MSVC clang
Currently on Windows, for cgo, we support MinGW-based C toolchain,
that is, with a -windows-gnu target. This CL makes it work with
clang with a -windows-msvc target. The LLVM toolchain bundled in
MSVC (https://learn.microsoft.com/en-us/cpp/build/clang-support-msbuild)
is such an example.
Currently it is expecting lld-link as the C linker, which is also
bundled in MSVC, can be requested with -fuse-ld=lld, but is not
the default.
This is the first step, which makes it generate a working cgo
binary. There are still more work to do, e.g. there are some
linker warnings, and the binary doesn't have symbol table.
all.bat doesn't pass with this setting.
Change-Id: I54d33f7dd5f5eeeafa0735cd52f4127fe4865636
Reviewed-on: https://go-review.googlesource.com/c/go/+/703055
Reviewed-by: Than McIntosh <thanm@golang.org>
Reviewed-by: Florian Zenker <floriank@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2025-09-11 17:42:30 -04:00
|
|
|
|
newer := linkerFlagSupported(ctxt.Arch, argv[0], "", dboff)
|
2022-02-08 12:41:26 -05:00
|
|
|
|
if newer {
|
|
|
|
|
|
// Newer compiler, which supports both on/off options.
|
|
|
|
|
|
dbopt = dboff
|
|
|
|
|
|
heopt = heoff
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// older toolchain: we have to say nothing in order to
|
|
|
|
|
|
// get a no-ASLR binary.
|
|
|
|
|
|
dbopt = ""
|
|
|
|
|
|
heopt = ""
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if dbopt != "" {
|
cmd/link: support MSVC clang
Currently on Windows, for cgo, we support MinGW-based C toolchain,
that is, with a -windows-gnu target. This CL makes it work with
clang with a -windows-msvc target. The LLVM toolchain bundled in
MSVC (https://learn.microsoft.com/en-us/cpp/build/clang-support-msbuild)
is such an example.
Currently it is expecting lld-link as the C linker, which is also
bundled in MSVC, can be requested with -fuse-ld=lld, but is not
the default.
This is the first step, which makes it generate a working cgo
binary. There are still more work to do, e.g. there are some
linker warnings, and the binary doesn't have symbol table.
all.bat doesn't pass with this setting.
Change-Id: I54d33f7dd5f5eeeafa0735cd52f4127fe4865636
Reviewed-on: https://go-review.googlesource.com/c/go/+/703055
Reviewed-by: Than McIntosh <thanm@golang.org>
Reviewed-by: Florian Zenker <floriank@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2025-09-11 17:42:30 -04:00
|
|
|
|
argv = append(argv, dbopt)
|
2022-02-08 12:41:26 -05:00
|
|
|
|
}
|
2020-09-17 01:59:14 +02:00
|
|
|
|
// enable high-entropy ASLR on 64-bit.
|
2022-02-08 12:41:26 -05:00
|
|
|
|
if ctxt.Arch.PtrSize >= 8 && heopt != "" {
|
cmd/link: support MSVC clang
Currently on Windows, for cgo, we support MinGW-based C toolchain,
that is, with a -windows-gnu target. This CL makes it work with
clang with a -windows-msvc target. The LLVM toolchain bundled in
MSVC (https://learn.microsoft.com/en-us/cpp/build/clang-support-msbuild)
is such an example.
Currently it is expecting lld-link as the C linker, which is also
bundled in MSVC, can be requested with -fuse-ld=lld, but is not
the default.
This is the first step, which makes it generate a working cgo
binary. There are still more work to do, e.g. there are some
linker warnings, and the binary doesn't have symbol table.
all.bat doesn't pass with this setting.
Change-Id: I54d33f7dd5f5eeeafa0735cd52f4127fe4865636
Reviewed-on: https://go-review.googlesource.com/c/go/+/703055
Reviewed-by: Than McIntosh <thanm@golang.org>
Reviewed-by: Florian Zenker <floriank@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2025-09-11 17:42:30 -04:00
|
|
|
|
argv = append(argv, heopt)
|
2020-09-17 01:59:14 +02:00
|
|
|
|
}
|
|
|
|
|
|
return argv
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-10-05 10:20:17 -04:00
|
|
|
|
switch ctxt.BuildMode {
|
|
|
|
|
|
case BuildModeExe:
|
2017-10-07 13:49:44 -04:00
|
|
|
|
if ctxt.HeadType == objabi.Hdarwin {
|
2020-09-02 21:04:12 -04:00
|
|
|
|
if machoPlatform == PLATFORM_MACOS && ctxt.IsAMD64() {
|
2019-11-03 17:04:28 -05:00
|
|
|
|
argv = append(argv, "-Wl,-no_pie")
|
2017-10-24 21:14:39 -04:00
|
|
|
|
}
|
2015-06-16 10:07:45 -07:00
|
|
|
|
}
|
2022-07-01 08:39:12 -04:00
|
|
|
|
if *flagRace && ctxt.HeadType == objabi.Hwindows {
|
|
|
|
|
|
// Current windows/amd64 race detector tsan support
|
|
|
|
|
|
// library can't handle PIE mode (see #53539 for more details).
|
|
|
|
|
|
// For now, explicitly disable PIE (since some compilers
|
|
|
|
|
|
// default to it) if -race is in effect.
|
|
|
|
|
|
argv = addASLRargs(argv, false)
|
|
|
|
|
|
}
|
2017-10-05 10:20:17 -04:00
|
|
|
|
case BuildModePIE:
|
2020-02-25 18:42:24 +11:00
|
|
|
|
switch ctxt.HeadType {
|
|
|
|
|
|
case objabi.Hdarwin, objabi.Haix:
|
|
|
|
|
|
case objabi.Hwindows:
|
2022-07-01 08:39:12 -04:00
|
|
|
|
if *flagAslr && *flagRace {
|
|
|
|
|
|
// Current windows/amd64 race detector tsan support
|
|
|
|
|
|
// library can't handle PIE mode (see #53539 for more details).
|
|
|
|
|
|
// Disable alsr if -race in effect.
|
|
|
|
|
|
*flagAslr = false
|
|
|
|
|
|
}
|
2022-02-08 12:41:26 -05:00
|
|
|
|
argv = addASLRargs(argv, *flagAslr)
|
2020-02-25 18:42:24 +11:00
|
|
|
|
default:
|
|
|
|
|
|
// ELF.
|
2017-10-05 10:20:17 -04:00
|
|
|
|
if ctxt.UseRelro() {
|
2017-08-05 18:25:26 +09:00
|
|
|
|
argv = append(argv, "-Wl,-z,relro")
|
|
|
|
|
|
}
|
|
|
|
|
|
argv = append(argv, "-pie")
|
2016-05-02 13:58:48 +12:00
|
|
|
|
}
|
2017-10-05 10:20:17 -04:00
|
|
|
|
case BuildModeCShared:
|
2017-10-07 13:49:44 -04:00
|
|
|
|
if ctxt.HeadType == objabi.Hdarwin {
|
2017-05-04 17:36:20 -04:00
|
|
|
|
argv = append(argv, "-dynamiclib")
|
2015-06-16 10:07:45 -07:00
|
|
|
|
} else {
|
2017-10-05 10:20:17 -04:00
|
|
|
|
if ctxt.UseRelro() {
|
2015-05-21 13:07:19 +12:00
|
|
|
|
argv = append(argv, "-Wl,-z,relro")
|
|
|
|
|
|
}
|
2017-10-05 17:36:13 +11:00
|
|
|
|
argv = append(argv, "-shared")
|
2020-09-17 01:59:14 +02:00
|
|
|
|
if ctxt.HeadType == objabi.Hwindows {
|
2022-02-08 12:41:26 -05:00
|
|
|
|
argv = addASLRargs(argv, *flagAslr)
|
2020-09-17 01:59:14 +02:00
|
|
|
|
} else {
|
2017-10-05 17:36:13 +11:00
|
|
|
|
// Pass -z nodelete to mark the shared library as
|
|
|
|
|
|
// non-closeable: a dlclose will do nothing.
|
|
|
|
|
|
argv = append(argv, "-Wl,-z,nodelete")
|
2021-02-14 14:44:14 +01:00
|
|
|
|
// Only pass Bsymbolic on non-Windows.
|
|
|
|
|
|
argv = append(argv, "-Wl,-Bsymbolic")
|
2017-10-05 17:36:13 +11:00
|
|
|
|
}
|
2015-06-16 10:07:45 -07:00
|
|
|
|
}
|
2017-10-05 10:20:17 -04:00
|
|
|
|
case BuildModeShared:
|
|
|
|
|
|
if ctxt.UseRelro() {
|
2015-09-16 22:06:16 +12:00
|
|
|
|
argv = append(argv, "-Wl,-z,relro")
|
2015-05-21 13:07:19 +12:00
|
|
|
|
}
|
2015-09-16 22:06:16 +12:00
|
|
|
|
argv = append(argv, "-shared")
|
2017-10-05 10:20:17 -04:00
|
|
|
|
case BuildModePlugin:
|
2017-10-07 13:49:44 -04:00
|
|
|
|
if ctxt.HeadType == objabi.Hdarwin {
|
2016-09-19 14:13:07 -04:00
|
|
|
|
argv = append(argv, "-dynamiclib")
|
|
|
|
|
|
} else {
|
2017-10-05 10:20:17 -04:00
|
|
|
|
if ctxt.UseRelro() {
|
2016-09-19 14:13:07 -04:00
|
|
|
|
argv = append(argv, "-Wl,-z,relro")
|
|
|
|
|
|
}
|
|
|
|
|
|
argv = append(argv, "-shared")
|
|
|
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-05-25 15:27:05 +02:00
|
|
|
|
var altLinker string
|
2024-03-13 17:49:32 +00:00
|
|
|
|
if ctxt.IsELF && (ctxt.DynlinkingGo() || *flagBindNow) {
|
|
|
|
|
|
// For ELF targets, when producing dynamically linked Go code
|
|
|
|
|
|
// or when immediate binding is explicitly requested,
|
|
|
|
|
|
// we force all symbol resolution to be done at program startup
|
2015-04-01 14:57:34 +13:00
|
|
|
|
// because lazy PLT resolution can use large amounts of stack at
|
|
|
|
|
|
// times we cannot allow it to do so.
|
cmd/link: specify -Wl,-z params as documented
Both GNU and LLVM linkers de facto accept `-zPARAM`, and Go sometimes
does it. Inconsistently: there are more uses of `-z PARAM` than
`-zPARAM`:
$ git grep -E -- '-Wl,-z[^,]' master | wc -l
4
$ git grep -E -- '-Wl,-z,' master | wc -l
7
However, not adding a space between `-z` and the param is not
documented:
llvm-13:
$ man ld.lld-13 | grep -E -A1 -w -- "^ +-z"
-z option
Linker option extensions.
gnu ld:
$ man ld | grep -E -A1 -w -- "^ +-z"
-z keyword
The recognized keywords are:
--
-z defs
Report unresolved symbol references from regular object files. This is done even if the linker is creating a non-symbolic
--
-z muldefs
Normally when a symbol is defined multiple times, the linker will report a fatal error. These options allow multiple definitions
--
-z
--imagic
... and thus should be avoided.
`zig cc`, when used as the C compiler (`CC="zig cc" go build ...`), will
bark, because `zig cc` accepts only `-z PARAM`, as documented.
Closes ziglang/zig#11669
Change-Id: I758054ecaa3ce01a72600bf65d7f7b5c3ec46d09
GitHub-Last-Rev: e068e007da9f2b0441ee0aa8b198a7ba3cd93ed3
GitHub-Pull-Request: golang/go#53030
Reviewed-on: https://go-review.googlesource.com/c/go/+/407834
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Alan Donovan <adonovan@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Run-TryBot: Cherry Mui <cherryyz@google.com>
2022-06-07 05:55:40 +00:00
|
|
|
|
argv = append(argv, "-Wl,-z,now")
|
2024-03-13 17:49:32 +00:00
|
|
|
|
}
|
2016-04-16 11:08:41 -04:00
|
|
|
|
|
2024-03-13 17:49:32 +00:00
|
|
|
|
if ctxt.IsELF && ctxt.DynlinkingGo() {
|
2016-04-16 11:08:41 -04:00
|
|
|
|
// Do not let the host linker generate COPY relocations. These
|
|
|
|
|
|
// can move symbols out of sections that rely on stable offsets
|
2017-10-04 17:54:04 -04:00
|
|
|
|
// from the beginning of the section (like sym.STYPE).
|
cmd/link: specify -Wl,-z params as documented
Both GNU and LLVM linkers de facto accept `-zPARAM`, and Go sometimes
does it. Inconsistently: there are more uses of `-z PARAM` than
`-zPARAM`:
$ git grep -E -- '-Wl,-z[^,]' master | wc -l
4
$ git grep -E -- '-Wl,-z,' master | wc -l
7
However, not adding a space between `-z` and the param is not
documented:
llvm-13:
$ man ld.lld-13 | grep -E -A1 -w -- "^ +-z"
-z option
Linker option extensions.
gnu ld:
$ man ld | grep -E -A1 -w -- "^ +-z"
-z keyword
The recognized keywords are:
--
-z defs
Report unresolved symbol references from regular object files. This is done even if the linker is creating a non-symbolic
--
-z muldefs
Normally when a symbol is defined multiple times, the linker will report a fatal error. These options allow multiple definitions
--
-z
--imagic
... and thus should be avoided.
`zig cc`, when used as the C compiler (`CC="zig cc" go build ...`), will
bark, because `zig cc` accepts only `-z PARAM`, as documented.
Closes ziglang/zig#11669
Change-Id: I758054ecaa3ce01a72600bf65d7f7b5c3ec46d09
GitHub-Last-Rev: e068e007da9f2b0441ee0aa8b198a7ba3cd93ed3
GitHub-Pull-Request: golang/go#53030
Reviewed-on: https://go-review.googlesource.com/c/go/+/407834
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Alan Donovan <adonovan@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Run-TryBot: Cherry Mui <cherryyz@google.com>
2022-06-07 05:55:40 +00:00
|
|
|
|
argv = append(argv, "-Wl,-z,nocopyreloc")
|
2016-04-16 11:08:41 -04:00
|
|
|
|
|
2021-04-15 23:05:49 -04:00
|
|
|
|
if buildcfg.GOOS == "android" {
|
2020-05-26 07:00:30 +00:00
|
|
|
|
// Use lld to avoid errors from default linker (issue #38838)
|
|
|
|
|
|
altLinker = "lld"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-02-15 14:05:22 -08:00
|
|
|
|
if ctxt.Arch.InFamily(sys.ARM64) && buildcfg.GOOS == "linux" {
|
|
|
|
|
|
// On ARM64, the GNU linker will fail with
|
|
|
|
|
|
// -znocopyreloc if it thinks a COPY relocation is
|
|
|
|
|
|
// required. Switch to gold.
|
2016-04-16 11:08:41 -04:00
|
|
|
|
// https://sourceware.org/bugzilla/show_bug.cgi?id=19962
|
2023-02-15 14:05:22 -08:00
|
|
|
|
// https://go.dev/issue/22040
|
2020-05-25 15:27:05 +02:00
|
|
|
|
altLinker = "gold"
|
2016-05-24 13:40:02 -04:00
|
|
|
|
|
|
|
|
|
|
// If gold is not installed, gcc will silently switch
|
|
|
|
|
|
// back to ld.bfd. So we parse the version information
|
|
|
|
|
|
// and provide a useful error if gold is missing.
|
cmd: support space and quotes in CC and CXX
The CC and CXX environment variables now support spaces and quotes
(both double and single). This fixes two issues: first, if CC is a
single path that contains spaces (like 'c:\Program
Files\gcc\bin\gcc.exe'), that should now work if the space is quoted
or escaped (#41400). Second, if CC or CXX has multiple arguments (like
'gcc -O2'), they are now split correctly, and the arguments are passed
before other arguments when invoking the C compiler. Previously,
strings.Fields was used to split arguments, and the arguments were
placed later in the command line. (#43078).
Fixes golang/go#41400
Fixes golang/go#43078
NOTE: This change also includes a fix (CL 341929) for a test that was
broken by the original CL. Commit message for the fix is below.
[dev.cmdgo] cmd/link: fix TestBuildForTvOS
This test was broken in CL 334732 on darwin.
The test invokes 'go build' with a CC containing the arguments
-framework CoreFoundation. Previously, the go command split CC on
whitespace, and inserted the arguments after the command line when
running CC directly. Those arguments weren't passed to cgo though,
so cgo ran CC without -framework CoreFoundation (or any of the other
flags).
In CL 334732, we pass CC through to cgo, and cgo splits arguments
using str.SplitQuotedFields. So -framework CoreFoundation actually
gets passed to the C compiler. It appears that -framework flags are
only meant to be used in linking operations, so when cgo invokes clang
with -E (run preprocessor only), clang emits an error that -framework
is unused.
This change fixes the test by moving -framework CoreFoundation out of
CC and into CGO_LDFLAGS.
Change-Id: I2d5d89ddb19c94adef65982a8137b01f037d5c11
Reviewed-on: https://go-review.googlesource.com/c/go/+/334732
Trust: Jay Conrod <jayconrod@google.com>
Trust: Michael Matloob <matloob@golang.org>
Run-TryBot: Jay Conrod <jayconrod@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Michael Matloob <matloob@golang.org>
Reviewed-on: https://go-review.googlesource.com/c/go/+/341936
Reviewed-by: Bryan C. Mills <bcmills@google.com>
2021-07-14 16:57:24 -07:00
|
|
|
|
name, args := flagExtld[0], flagExtld[1:]
|
|
|
|
|
|
args = append(args, "-fuse-ld=gold", "-Wl,--version")
|
|
|
|
|
|
cmd := exec.Command(name, args...)
|
2016-05-25 13:24:36 +02:00
|
|
|
|
if out, err := cmd.CombinedOutput(); err == nil {
|
2016-05-24 13:40:02 -04:00
|
|
|
|
if !bytes.Contains(out, []byte("GNU gold")) {
|
2023-02-15 14:05:22 -08:00
|
|
|
|
log.Fatalf("ARM64 external linker must be gold (issue #15696, 22040), but is not: %s", out)
|
2016-05-24 13:40:02 -04:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-04-16 11:08:41 -04:00
|
|
|
|
}
|
2015-04-01 14:57:34 +13:00
|
|
|
|
}
|
2021-04-15 23:05:49 -04:00
|
|
|
|
if ctxt.Arch.Family == sys.ARM64 && buildcfg.GOOS == "freebsd" {
|
2019-10-27 12:22:02 -05:00
|
|
|
|
// Switch to ld.bfd on freebsd/arm64.
|
2020-05-25 15:27:05 +02:00
|
|
|
|
altLinker = "bfd"
|
2019-10-27 12:22:02 -05:00
|
|
|
|
|
|
|
|
|
|
// Provide a useful error if ld.bfd is missing.
|
cmd: support space and quotes in CC and CXX
The CC and CXX environment variables now support spaces and quotes
(both double and single). This fixes two issues: first, if CC is a
single path that contains spaces (like 'c:\Program
Files\gcc\bin\gcc.exe'), that should now work if the space is quoted
or escaped (#41400). Second, if CC or CXX has multiple arguments (like
'gcc -O2'), they are now split correctly, and the arguments are passed
before other arguments when invoking the C compiler. Previously,
strings.Fields was used to split arguments, and the arguments were
placed later in the command line. (#43078).
Fixes golang/go#41400
Fixes golang/go#43078
NOTE: This change also includes a fix (CL 341929) for a test that was
broken by the original CL. Commit message for the fix is below.
[dev.cmdgo] cmd/link: fix TestBuildForTvOS
This test was broken in CL 334732 on darwin.
The test invokes 'go build' with a CC containing the arguments
-framework CoreFoundation. Previously, the go command split CC on
whitespace, and inserted the arguments after the command line when
running CC directly. Those arguments weren't passed to cgo though,
so cgo ran CC without -framework CoreFoundation (or any of the other
flags).
In CL 334732, we pass CC through to cgo, and cgo splits arguments
using str.SplitQuotedFields. So -framework CoreFoundation actually
gets passed to the C compiler. It appears that -framework flags are
only meant to be used in linking operations, so when cgo invokes clang
with -E (run preprocessor only), clang emits an error that -framework
is unused.
This change fixes the test by moving -framework CoreFoundation out of
CC and into CGO_LDFLAGS.
Change-Id: I2d5d89ddb19c94adef65982a8137b01f037d5c11
Reviewed-on: https://go-review.googlesource.com/c/go/+/334732
Trust: Jay Conrod <jayconrod@google.com>
Trust: Michael Matloob <matloob@golang.org>
Run-TryBot: Jay Conrod <jayconrod@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Michael Matloob <matloob@golang.org>
Reviewed-on: https://go-review.googlesource.com/c/go/+/341936
Reviewed-by: Bryan C. Mills <bcmills@google.com>
2021-07-14 16:57:24 -07:00
|
|
|
|
name, args := flagExtld[0], flagExtld[1:]
|
|
|
|
|
|
args = append(args, "-fuse-ld=bfd", "-Wl,--version")
|
|
|
|
|
|
cmd := exec.Command(name, args...)
|
2019-10-27 12:22:02 -05:00
|
|
|
|
if out, err := cmd.CombinedOutput(); err == nil {
|
|
|
|
|
|
if !bytes.Contains(out, []byte("GNU ld")) {
|
|
|
|
|
|
log.Fatalf("ARM64 external linker must be ld.bfd (issue #35197), please install devel/binutils")
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2020-05-25 15:27:05 +02:00
|
|
|
|
if altLinker != "" {
|
|
|
|
|
|
argv = append(argv, "-fuse-ld="+altLinker)
|
|
|
|
|
|
}
|
2019-10-27 12:22:02 -05:00
|
|
|
|
|
2024-10-22 12:02:02 -04:00
|
|
|
|
if ctxt.IsELF && linkerFlagSupported(ctxt.Arch, argv[0], "", "-Wl,--build-id=0x1234567890abcdef") { // Solaris ld doesn't support --build-id.
|
2024-10-08 17:59:29 -04:00
|
|
|
|
if len(buildinfo) > 0 {
|
|
|
|
|
|
argv = append(argv, fmt.Sprintf("-Wl,--build-id=0x%x", buildinfo))
|
|
|
|
|
|
} else if *flagHostBuildid == "none" {
|
|
|
|
|
|
argv = append(argv, "-Wl,--build-id=none")
|
|
|
|
|
|
}
|
2015-07-15 00:18:51 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2015-07-15 09:05:33 -07:00
|
|
|
|
// On Windows, given -o foo, GCC will append ".exe" to produce
|
|
|
|
|
|
// "foo.exe". We have decided that we want to honor the -o
|
2016-03-01 23:21:55 +00:00
|
|
|
|
// option. To make this work, we append a '.' so that GCC
|
|
|
|
|
|
// will decide that the file already has an extension. We
|
2015-07-15 09:05:33 -07:00
|
|
|
|
// only want to do this when producing a Windows output file
|
|
|
|
|
|
// on a Windows host.
|
2016-08-21 18:34:24 -04:00
|
|
|
|
outopt := *flagOutfile
|
2021-04-15 23:05:49 -04:00
|
|
|
|
if buildcfg.GOOS == "windows" && runtime.GOOS == "windows" && filepath.Ext(outopt) == "" {
|
2015-07-15 09:05:33 -07:00
|
|
|
|
outopt += "."
|
|
|
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
|
argv = append(argv, "-o")
|
2015-07-15 09:05:33 -07:00
|
|
|
|
argv = append(argv, outopt)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
2015-04-12 02:31:28 +02:00
|
|
|
|
if rpath.val != "" {
|
|
|
|
|
|
argv = append(argv, fmt.Sprintf("-Wl,-rpath,%s", rpath.val))
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-04-15 15:50:41 +12:00
|
|
|
|
if *flagInterpreter != "" {
|
|
|
|
|
|
// Many linkers support both -I and the --dynamic-linker flags
|
|
|
|
|
|
// to set the ELF interpreter, but lld only supports
|
|
|
|
|
|
// --dynamic-linker so prefer that (ld on very old Solaris only
|
|
|
|
|
|
// supports -I but that seems less important).
|
|
|
|
|
|
argv = append(argv, fmt.Sprintf("-Wl,--dynamic-linker,%s", *flagInterpreter))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-02-27 22:57:28 -05:00
|
|
|
|
// Force global symbols to be exported for dlopen, etc.
|
2017-10-07 13:43:38 -04:00
|
|
|
|
if ctxt.IsELF {
|
2022-06-27 14:58:58 -07:00
|
|
|
|
if ctxt.DynlinkingGo() || ctxt.BuildMode == BuildModeCShared || !linkerFlagSupported(ctxt.Arch, argv[0], altLinker, "-Wl,--export-dynamic-symbol=main") {
|
|
|
|
|
|
argv = append(argv, "-rdynamic")
|
|
|
|
|
|
} else {
|
2023-07-12 16:54:32 -04:00
|
|
|
|
var exports []string
|
2022-06-27 14:58:58 -07:00
|
|
|
|
ctxt.loader.ForAllCgoExportDynamic(func(s loader.Sym) {
|
2023-07-12 16:54:32 -04:00
|
|
|
|
exports = append(exports, "-Wl,--export-dynamic-symbol="+ctxt.loader.SymExtname(s))
|
2022-06-27 14:58:58 -07:00
|
|
|
|
})
|
2023-07-12 16:54:32 -04:00
|
|
|
|
sort.Strings(exports)
|
|
|
|
|
|
argv = append(argv, exports...)
|
2022-06-27 14:58:58 -07:00
|
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
2019-02-20 16:26:54 +01:00
|
|
|
|
if ctxt.HeadType == objabi.Haix {
|
|
|
|
|
|
fileName := xcoffCreateExportFile(ctxt)
|
|
|
|
|
|
argv = append(argv, "-Wl,-bE:"+fileName)
|
|
|
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
2021-03-26 11:00:40 +01:00
|
|
|
|
const unusedArguments = "-Qunused-arguments"
|
|
|
|
|
|
if linkerFlagSupported(ctxt.Arch, argv[0], altLinker, unusedArguments) {
|
|
|
|
|
|
argv = append(argv, unusedArguments)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-12-06 10:22:09 -05:00
|
|
|
|
if ctxt.IsWindows() {
|
|
|
|
|
|
// Suppress generation of the PE file header timestamp,
|
|
|
|
|
|
// so as to avoid spurious build ID differences between
|
|
|
|
|
|
// linked binaries that are otherwise identical other than
|
|
|
|
|
|
// the date/time they were linked.
|
|
|
|
|
|
const noTimeStamp = "-Wl,--no-insert-timestamp"
|
|
|
|
|
|
if linkerFlagSupported(ctxt.Arch, argv[0], altLinker, noTimeStamp) {
|
|
|
|
|
|
argv = append(argv, noTimeStamp)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-01-26 10:23:48 +08:00
|
|
|
|
const compressDWARF = "-Wl,--compress-debug-sections=zlib"
|
2020-12-15 18:31:21 -05:00
|
|
|
|
if ctxt.compressDWARF && linkerFlagSupported(ctxt.Arch, argv[0], altLinker, compressDWARF) {
|
2018-05-07 13:44:22 -04:00
|
|
|
|
argv = append(argv, compressDWARF)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-05-14 14:59:03 +00:00
|
|
|
|
hostObjCopyPaths := ctxt.hostobjCopy()
|
|
|
|
|
|
cleanTimeStamps(hostObjCopyPaths)
|
|
|
|
|
|
godotopath := filepath.Join(*flagTmpdir, "go.o")
|
|
|
|
|
|
cleanTimeStamps([]string{godotopath})
|
|
|
|
|
|
|
|
|
|
|
|
argv = append(argv, godotopath)
|
|
|
|
|
|
argv = append(argv, hostObjCopyPaths...)
|
2019-02-20 16:52:35 +01:00
|
|
|
|
if ctxt.HeadType == objabi.Haix {
|
|
|
|
|
|
// We want to have C files after Go files to remove
|
|
|
|
|
|
// trampolines csects made by ld.
|
|
|
|
|
|
argv = append(argv, "-nostartfiles")
|
|
|
|
|
|
argv = append(argv, "/lib/crt0_64.o")
|
|
|
|
|
|
|
|
|
|
|
|
extld := ctxt.extld()
|
cmd: support space and quotes in CC and CXX
The CC and CXX environment variables now support spaces and quotes
(both double and single). This fixes two issues: first, if CC is a
single path that contains spaces (like 'c:\Program
Files\gcc\bin\gcc.exe'), that should now work if the space is quoted
or escaped (#41400). Second, if CC or CXX has multiple arguments (like
'gcc -O2'), they are now split correctly, and the arguments are passed
before other arguments when invoking the C compiler. Previously,
strings.Fields was used to split arguments, and the arguments were
placed later in the command line. (#43078).
Fixes golang/go#41400
Fixes golang/go#43078
NOTE: This change also includes a fix (CL 341929) for a test that was
broken by the original CL. Commit message for the fix is below.
[dev.cmdgo] cmd/link: fix TestBuildForTvOS
This test was broken in CL 334732 on darwin.
The test invokes 'go build' with a CC containing the arguments
-framework CoreFoundation. Previously, the go command split CC on
whitespace, and inserted the arguments after the command line when
running CC directly. Those arguments weren't passed to cgo though,
so cgo ran CC without -framework CoreFoundation (or any of the other
flags).
In CL 334732, we pass CC through to cgo, and cgo splits arguments
using str.SplitQuotedFields. So -framework CoreFoundation actually
gets passed to the C compiler. It appears that -framework flags are
only meant to be used in linking operations, so when cgo invokes clang
with -E (run preprocessor only), clang emits an error that -framework
is unused.
This change fixes the test by moving -framework CoreFoundation out of
CC and into CGO_LDFLAGS.
Change-Id: I2d5d89ddb19c94adef65982a8137b01f037d5c11
Reviewed-on: https://go-review.googlesource.com/c/go/+/334732
Trust: Jay Conrod <jayconrod@google.com>
Trust: Michael Matloob <matloob@golang.org>
Run-TryBot: Jay Conrod <jayconrod@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Michael Matloob <matloob@golang.org>
Reviewed-on: https://go-review.googlesource.com/c/go/+/341936
Reviewed-by: Bryan C. Mills <bcmills@google.com>
2021-07-14 16:57:24 -07:00
|
|
|
|
name, args := extld[0], extld[1:]
|
2019-02-20 16:52:35 +01:00
|
|
|
|
// Get starting files.
|
|
|
|
|
|
getPathFile := func(file string) string {
|
cmd: support space and quotes in CC and CXX
The CC and CXX environment variables now support spaces and quotes
(both double and single). This fixes two issues: first, if CC is a
single path that contains spaces (like 'c:\Program
Files\gcc\bin\gcc.exe'), that should now work if the space is quoted
or escaped (#41400). Second, if CC or CXX has multiple arguments (like
'gcc -O2'), they are now split correctly, and the arguments are passed
before other arguments when invoking the C compiler. Previously,
strings.Fields was used to split arguments, and the arguments were
placed later in the command line. (#43078).
Fixes golang/go#41400
Fixes golang/go#43078
NOTE: This change also includes a fix (CL 341929) for a test that was
broken by the original CL. Commit message for the fix is below.
[dev.cmdgo] cmd/link: fix TestBuildForTvOS
This test was broken in CL 334732 on darwin.
The test invokes 'go build' with a CC containing the arguments
-framework CoreFoundation. Previously, the go command split CC on
whitespace, and inserted the arguments after the command line when
running CC directly. Those arguments weren't passed to cgo though,
so cgo ran CC without -framework CoreFoundation (or any of the other
flags).
In CL 334732, we pass CC through to cgo, and cgo splits arguments
using str.SplitQuotedFields. So -framework CoreFoundation actually
gets passed to the C compiler. It appears that -framework flags are
only meant to be used in linking operations, so when cgo invokes clang
with -E (run preprocessor only), clang emits an error that -framework
is unused.
This change fixes the test by moving -framework CoreFoundation out of
CC and into CGO_LDFLAGS.
Change-Id: I2d5d89ddb19c94adef65982a8137b01f037d5c11
Reviewed-on: https://go-review.googlesource.com/c/go/+/334732
Trust: Jay Conrod <jayconrod@google.com>
Trust: Michael Matloob <matloob@golang.org>
Run-TryBot: Jay Conrod <jayconrod@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Michael Matloob <matloob@golang.org>
Reviewed-on: https://go-review.googlesource.com/c/go/+/341936
Reviewed-by: Bryan C. Mills <bcmills@google.com>
2021-07-14 16:57:24 -07:00
|
|
|
|
args := append(args, "-maix64", "--print-file-name="+file)
|
|
|
|
|
|
out, err := exec.Command(name, args...).CombinedOutput()
|
2019-02-20 16:52:35 +01:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
log.Fatalf("running %s failed: %v\n%s", extld, err, out)
|
|
|
|
|
|
}
|
|
|
|
|
|
return strings.Trim(string(out), "\n")
|
|
|
|
|
|
}
|
2021-11-09 10:01:05 +01:00
|
|
|
|
// Since GCC version 11, the 64-bit version of GCC starting files
|
|
|
|
|
|
// are now suffixed by "_64". Even under "-maix64" multilib directory
|
|
|
|
|
|
// "crtcxa.o" is 32-bit.
|
|
|
|
|
|
crtcxa := getPathFile("crtcxa_64.o")
|
|
|
|
|
|
if !filepath.IsAbs(crtcxa) {
|
|
|
|
|
|
crtcxa = getPathFile("crtcxa.o")
|
|
|
|
|
|
}
|
|
|
|
|
|
crtdbase := getPathFile("crtdbase_64.o")
|
|
|
|
|
|
if !filepath.IsAbs(crtdbase) {
|
|
|
|
|
|
crtdbase = getPathFile("crtdbase.o")
|
|
|
|
|
|
}
|
|
|
|
|
|
argv = append(argv, crtcxa)
|
|
|
|
|
|
argv = append(argv, crtdbase)
|
2019-02-20 16:52:35 +01:00
|
|
|
|
}
|
2015-04-01 14:57:34 +13:00
|
|
|
|
|
2017-10-07 13:28:51 -04:00
|
|
|
|
if ctxt.linkShared {
|
2015-05-25 14:51:02 +12:00
|
|
|
|
seenDirs := make(map[string]bool)
|
|
|
|
|
|
seenLibs := make(map[string]bool)
|
|
|
|
|
|
addshlib := func(path string) {
|
|
|
|
|
|
dir, base := filepath.Split(path)
|
|
|
|
|
|
if !seenDirs[dir] {
|
|
|
|
|
|
argv = append(argv, "-L"+dir)
|
|
|
|
|
|
if !rpath.set {
|
|
|
|
|
|
argv = append(argv, "-Wl,-rpath="+dir)
|
|
|
|
|
|
}
|
|
|
|
|
|
seenDirs[dir] = true
|
2015-04-12 02:31:28 +02:00
|
|
|
|
}
|
2015-04-01 14:57:34 +13:00
|
|
|
|
base = strings.TrimSuffix(base, ".so")
|
|
|
|
|
|
base = strings.TrimPrefix(base, "lib")
|
2015-05-25 14:51:02 +12:00
|
|
|
|
if !seenLibs[base] {
|
|
|
|
|
|
argv = append(argv, "-l"+base)
|
|
|
|
|
|
seenLibs[base] = true
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2017-10-05 10:20:17 -04:00
|
|
|
|
for _, shlib := range ctxt.Shlibs {
|
2015-05-25 14:51:02 +12:00
|
|
|
|
addshlib(shlib.Path)
|
|
|
|
|
|
for _, dep := range shlib.Deps {
|
|
|
|
|
|
if dep == "" {
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
2017-10-05 10:20:17 -04:00
|
|
|
|
libpath := findshlib(ctxt, dep)
|
2015-05-25 14:51:02 +12:00
|
|
|
|
if libpath != "" {
|
|
|
|
|
|
addshlib(libpath)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2015-04-01 14:57:34 +13:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-07-03 10:16:03 -07:00
|
|
|
|
// clang, unlike GCC, passes -rdynamic to the linker
|
|
|
|
|
|
// even when linking with -static, causing a linker
|
|
|
|
|
|
// error when using GNU ld. So take out -rdynamic if
|
|
|
|
|
|
// we added it. We do it in this order, rather than
|
2021-04-27 21:56:46 -07:00
|
|
|
|
// only adding -rdynamic later, so that -extldflags
|
2018-07-03 10:16:03 -07:00
|
|
|
|
// can override -rdynamic without using -static.
|
2021-04-27 21:56:46 -07:00
|
|
|
|
// Similarly for -Wl,--dynamic-linker.
|
2018-07-03 10:16:03 -07:00
|
|
|
|
checkStatic := func(arg string) {
|
|
|
|
|
|
if ctxt.IsELF && arg == "-static" {
|
|
|
|
|
|
for i := range argv {
|
2021-04-27 21:56:46 -07:00
|
|
|
|
if argv[i] == "-rdynamic" || strings.HasPrefix(argv[i], "-Wl,--dynamic-linker,") {
|
2018-07-03 10:16:03 -07:00
|
|
|
|
argv[i] = "-static"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for _, p := range ldflag {
|
|
|
|
|
|
argv = append(argv, p)
|
|
|
|
|
|
checkStatic(p)
|
|
|
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
2016-11-10 22:08:51 -08:00
|
|
|
|
// When building a program with the default -buildmode=exe the
|
|
|
|
|
|
// gc compiler generates code requires DT_TEXTREL in a
|
|
|
|
|
|
// position independent executable (PIE). On systems where the
|
|
|
|
|
|
// toolchain creates PIEs by default, and where DT_TEXTREL
|
|
|
|
|
|
// does not work, the resulting programs will not run. See
|
|
|
|
|
|
// issue #17847. To avoid this problem pass -no-pie to the
|
|
|
|
|
|
// toolchain if it is supported.
|
2020-09-02 21:04:12 -04:00
|
|
|
|
if ctxt.BuildMode == BuildModeExe && !ctxt.linkShared && !(ctxt.IsDarwin() && ctxt.IsARM64()) {
|
2017-07-18 13:15:05 -07:00
|
|
|
|
// GCC uses -no-pie, clang uses -nopie.
|
|
|
|
|
|
for _, nopie := range []string{"-no-pie", "-nopie"} {
|
2020-12-15 18:31:21 -05:00
|
|
|
|
if linkerFlagSupported(ctxt.Arch, argv[0], altLinker, nopie) {
|
2017-07-18 13:15:05 -07:00
|
|
|
|
argv = append(argv, nopie)
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
2016-04-26 21:37:49 +12:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
cmd: support space and quotes in CC and CXX
The CC and CXX environment variables now support spaces and quotes
(both double and single). This fixes two issues: first, if CC is a
single path that contains spaces (like 'c:\Program
Files\gcc\bin\gcc.exe'), that should now work if the space is quoted
or escaped (#41400). Second, if CC or CXX has multiple arguments (like
'gcc -O2'), they are now split correctly, and the arguments are passed
before other arguments when invoking the C compiler. Previously,
strings.Fields was used to split arguments, and the arguments were
placed later in the command line. (#43078).
Fixes golang/go#41400
Fixes golang/go#43078
NOTE: This change also includes a fix (CL 341929) for a test that was
broken by the original CL. Commit message for the fix is below.
[dev.cmdgo] cmd/link: fix TestBuildForTvOS
This test was broken in CL 334732 on darwin.
The test invokes 'go build' with a CC containing the arguments
-framework CoreFoundation. Previously, the go command split CC on
whitespace, and inserted the arguments after the command line when
running CC directly. Those arguments weren't passed to cgo though,
so cgo ran CC without -framework CoreFoundation (or any of the other
flags).
In CL 334732, we pass CC through to cgo, and cgo splits arguments
using str.SplitQuotedFields. So -framework CoreFoundation actually
gets passed to the C compiler. It appears that -framework flags are
only meant to be used in linking operations, so when cgo invokes clang
with -E (run preprocessor only), clang emits an error that -framework
is unused.
This change fixes the test by moving -framework CoreFoundation out of
CC and into CGO_LDFLAGS.
Change-Id: I2d5d89ddb19c94adef65982a8137b01f037d5c11
Reviewed-on: https://go-review.googlesource.com/c/go/+/334732
Trust: Jay Conrod <jayconrod@google.com>
Trust: Michael Matloob <matloob@golang.org>
Run-TryBot: Jay Conrod <jayconrod@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Michael Matloob <matloob@golang.org>
Reviewed-on: https://go-review.googlesource.com/c/go/+/341936
Reviewed-by: Bryan C. Mills <bcmills@google.com>
2021-07-14 16:57:24 -07:00
|
|
|
|
for _, p := range flagExtldflags {
|
2015-02-27 22:57:28 -05:00
|
|
|
|
argv = append(argv, p)
|
2018-07-03 10:16:03 -07:00
|
|
|
|
checkStatic(p)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
2017-10-07 13:49:44 -04:00
|
|
|
|
if ctxt.HeadType == objabi.Hwindows {
|
2020-12-14 13:03:06 -05:00
|
|
|
|
// Determine which linker we're using. Add in the extldflags in
|
|
|
|
|
|
// case used has specified "-fuse-ld=...".
|
cmd: support space and quotes in CC and CXX
The CC and CXX environment variables now support spaces and quotes
(both double and single). This fixes two issues: first, if CC is a
single path that contains spaces (like 'c:\Program
Files\gcc\bin\gcc.exe'), that should now work if the space is quoted
or escaped (#41400). Second, if CC or CXX has multiple arguments (like
'gcc -O2'), they are now split correctly, and the arguments are passed
before other arguments when invoking the C compiler. Previously,
strings.Fields was used to split arguments, and the arguments were
placed later in the command line. (#43078).
Fixes golang/go#41400
Fixes golang/go#43078
NOTE: This change also includes a fix (CL 341929) for a test that was
broken by the original CL. Commit message for the fix is below.
[dev.cmdgo] cmd/link: fix TestBuildForTvOS
This test was broken in CL 334732 on darwin.
The test invokes 'go build' with a CC containing the arguments
-framework CoreFoundation. Previously, the go command split CC on
whitespace, and inserted the arguments after the command line when
running CC directly. Those arguments weren't passed to cgo though,
so cgo ran CC without -framework CoreFoundation (or any of the other
flags).
In CL 334732, we pass CC through to cgo, and cgo splits arguments
using str.SplitQuotedFields. So -framework CoreFoundation actually
gets passed to the C compiler. It appears that -framework flags are
only meant to be used in linking operations, so when cgo invokes clang
with -E (run preprocessor only), clang emits an error that -framework
is unused.
This change fixes the test by moving -framework CoreFoundation out of
CC and into CGO_LDFLAGS.
Change-Id: I2d5d89ddb19c94adef65982a8137b01f037d5c11
Reviewed-on: https://go-review.googlesource.com/c/go/+/334732
Trust: Jay Conrod <jayconrod@google.com>
Trust: Michael Matloob <matloob@golang.org>
Run-TryBot: Jay Conrod <jayconrod@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Michael Matloob <matloob@golang.org>
Reviewed-on: https://go-review.googlesource.com/c/go/+/341936
Reviewed-by: Bryan C. Mills <bcmills@google.com>
2021-07-14 16:57:24 -07:00
|
|
|
|
extld := ctxt.extld()
|
|
|
|
|
|
name, args := extld[0], extld[1:]
|
2022-06-27 14:58:58 -07:00
|
|
|
|
args = append(args, trimLinkerArgv(flagExtldflags)...)
|
cmd: support space and quotes in CC and CXX
The CC and CXX environment variables now support spaces and quotes
(both double and single). This fixes two issues: first, if CC is a
single path that contains spaces (like 'c:\Program
Files\gcc\bin\gcc.exe'), that should now work if the space is quoted
or escaped (#41400). Second, if CC or CXX has multiple arguments (like
'gcc -O2'), they are now split correctly, and the arguments are passed
before other arguments when invoking the C compiler. Previously,
strings.Fields was used to split arguments, and the arguments were
placed later in the command line. (#43078).
Fixes golang/go#41400
Fixes golang/go#43078
NOTE: This change also includes a fix (CL 341929) for a test that was
broken by the original CL. Commit message for the fix is below.
[dev.cmdgo] cmd/link: fix TestBuildForTvOS
This test was broken in CL 334732 on darwin.
The test invokes 'go build' with a CC containing the arguments
-framework CoreFoundation. Previously, the go command split CC on
whitespace, and inserted the arguments after the command line when
running CC directly. Those arguments weren't passed to cgo though,
so cgo ran CC without -framework CoreFoundation (or any of the other
flags).
In CL 334732, we pass CC through to cgo, and cgo splits arguments
using str.SplitQuotedFields. So -framework CoreFoundation actually
gets passed to the C compiler. It appears that -framework flags are
only meant to be used in linking operations, so when cgo invokes clang
with -E (run preprocessor only), clang emits an error that -framework
is unused.
This change fixes the test by moving -framework CoreFoundation out of
CC and into CGO_LDFLAGS.
Change-Id: I2d5d89ddb19c94adef65982a8137b01f037d5c11
Reviewed-on: https://go-review.googlesource.com/c/go/+/334732
Trust: Jay Conrod <jayconrod@google.com>
Trust: Michael Matloob <matloob@golang.org>
Run-TryBot: Jay Conrod <jayconrod@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Michael Matloob <matloob@golang.org>
Reviewed-on: https://go-review.googlesource.com/c/go/+/341936
Reviewed-by: Bryan C. Mills <bcmills@google.com>
2021-07-14 16:57:24 -07:00
|
|
|
|
args = append(args, "-Wl,--version")
|
|
|
|
|
|
cmd := exec.Command(name, args...)
|
2020-12-14 13:03:06 -05:00
|
|
|
|
usingLLD := false
|
|
|
|
|
|
if out, err := cmd.CombinedOutput(); err == nil {
|
|
|
|
|
|
if bytes.Contains(out, []byte("LLD ")) {
|
|
|
|
|
|
usingLLD = true
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-05-11 11:55:59 +10:00
|
|
|
|
// use gcc linker script to work around gcc bug
|
|
|
|
|
|
// (see https://golang.org/issue/20183 for details).
|
2020-12-14 13:03:06 -05:00
|
|
|
|
if !usingLLD {
|
|
|
|
|
|
p := writeGDBLinkerScript()
|
|
|
|
|
|
argv = append(argv, "-Wl,-T,"+p)
|
|
|
|
|
|
}
|
2022-06-24 15:31:35 -04:00
|
|
|
|
if *flagRace {
|
2025-09-12 13:46:31 -04:00
|
|
|
|
// Apparently --print-file-name doesn't work with -msvc clang.
|
|
|
|
|
|
// (The library name is synchronization.lib, but even with that
|
|
|
|
|
|
// name it still doesn't print the full path.) Assume it always
|
|
|
|
|
|
// it.
|
|
|
|
|
|
if isMSVC || ctxt.findLibPath("libsynchronization.a") != "libsynchronization.a" {
|
2022-06-24 15:31:35 -04:00
|
|
|
|
argv = append(argv, "-lsynchronization")
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
cmd/link: support MSVC clang
Currently on Windows, for cgo, we support MinGW-based C toolchain,
that is, with a -windows-gnu target. This CL makes it work with
clang with a -windows-msvc target. The LLVM toolchain bundled in
MSVC (https://learn.microsoft.com/en-us/cpp/build/clang-support-msbuild)
is such an example.
Currently it is expecting lld-link as the C linker, which is also
bundled in MSVC, can be requested with -fuse-ld=lld, but is not
the default.
This is the first step, which makes it generate a working cgo
binary. There are still more work to do, e.g. there are some
linker warnings, and the binary doesn't have symbol table.
all.bat doesn't pass with this setting.
Change-Id: I54d33f7dd5f5eeeafa0735cd52f4127fe4865636
Reviewed-on: https://go-review.googlesource.com/c/go/+/703055
Reviewed-by: Than McIntosh <thanm@golang.org>
Reviewed-by: Florian Zenker <floriank@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2025-09-11 17:42:30 -04:00
|
|
|
|
if !isMSVC {
|
|
|
|
|
|
// libmingw32 and libmingwex have some inter-dependencies,
|
|
|
|
|
|
// so must use linker groups.
|
|
|
|
|
|
argv = append(argv, "-Wl,--start-group", "-lmingwex", "-lmingw32", "-Wl,--end-group")
|
|
|
|
|
|
}
|
2015-03-09 03:05:40 -04:00
|
|
|
|
argv = append(argv, peimporteddlls()...)
|
|
|
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
2022-06-27 14:58:58 -07:00
|
|
|
|
argv = ctxt.passLongArgsInResponseFile(argv, altLinker)
|
|
|
|
|
|
|
2017-10-05 10:20:17 -04:00
|
|
|
|
if ctxt.Debugvlog != 0 {
|
2019-04-13 16:42:48 +03:00
|
|
|
|
ctxt.Logf("host link:")
|
2015-04-08 16:49:43 -04:00
|
|
|
|
for _, v := range argv {
|
2017-10-05 10:20:17 -04:00
|
|
|
|
ctxt.Logf(" %q", v)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
2017-10-05 10:20:17 -04:00
|
|
|
|
ctxt.Logf("\n")
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-01-26 12:08:00 -05:00
|
|
|
|
cmd := exec.Command(argv[0], argv[1:]...)
|
|
|
|
|
|
out, err := cmd.CombinedOutput()
|
2018-10-24 12:01:13 -04:00
|
|
|
|
if err != nil {
|
2024-01-26 12:08:00 -05:00
|
|
|
|
Exitf("running %s failed: %v\n%s\n%s", argv[0], err, cmd, out)
|
2018-10-24 12:01:13 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Filter out useless linker warnings caused by bugs outside Go.
|
|
|
|
|
|
// See also cmd/go/internal/work/exec.go's gccld method.
|
|
|
|
|
|
var save [][]byte
|
2019-02-20 16:42:11 +01:00
|
|
|
|
var skipLines int
|
2018-10-24 12:01:13 -04:00
|
|
|
|
for _, line := range bytes.SplitAfter(out, []byte("\n")) {
|
|
|
|
|
|
// golang.org/issue/26073 - Apple Xcode bug
|
|
|
|
|
|
if bytes.Contains(line, []byte("ld: warning: text-based stub file")) {
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
2019-02-20 16:42:11 +01:00
|
|
|
|
|
|
|
|
|
|
if skipLines > 0 {
|
|
|
|
|
|
skipLines--
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Remove TOC overflow warning on AIX.
|
|
|
|
|
|
if bytes.Contains(line, []byte("ld: 0711-783")) {
|
|
|
|
|
|
skipLines = 2
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-10-24 12:01:13 -04:00
|
|
|
|
save = append(save, line)
|
|
|
|
|
|
}
|
|
|
|
|
|
out = bytes.Join(save, nil)
|
|
|
|
|
|
|
|
|
|
|
|
if len(out) > 0 {
|
2016-11-16 01:05:34 -05:00
|
|
|
|
// always print external output even if the command is successful, so that we don't
|
|
|
|
|
|
// swallow linker warnings (see https://golang.org/issue/17935).
|
2022-09-14 21:01:04 -04:00
|
|
|
|
if ctxt.IsDarwin() && ctxt.IsAMD64() {
|
|
|
|
|
|
const noPieWarning = "ld: warning: -no_pie is deprecated when targeting new OS versions\n"
|
|
|
|
|
|
if i := bytes.Index(out, []byte(noPieWarning)); i >= 0 {
|
|
|
|
|
|
// swallow -no_pie deprecation warning, issue 54482
|
|
|
|
|
|
out = append(out[:i], out[i+len(noPieWarning):]...)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-07-10 18:50:06 -04:00
|
|
|
|
if ctxt.IsDarwin() {
|
|
|
|
|
|
const bindAtLoadWarning = "ld: warning: -bind_at_load is deprecated on macOS\n"
|
|
|
|
|
|
if i := bytes.Index(out, []byte(bindAtLoadWarning)); i >= 0 {
|
|
|
|
|
|
// -bind_at_load is deprecated with ld-prime, but needed for
|
|
|
|
|
|
// correctness with older versions of ld64. Swallow the warning.
|
|
|
|
|
|
// TODO: maybe pass -bind_at_load conditionally based on C
|
|
|
|
|
|
// linker version.
|
|
|
|
|
|
out = append(out[:i], out[i+len(bindAtLoadWarning):]...)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2017-10-05 10:20:17 -04:00
|
|
|
|
ctxt.Logf("%s", out)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
2015-04-08 12:55:34 -07:00
|
|
|
|
|
2024-05-20 14:52:57 +00:00
|
|
|
|
// Helper for updating a Macho binary in some way (shared between
|
|
|
|
|
|
// dwarf combining and UUID update).
|
|
|
|
|
|
updateMachoOutFile := func(op string, updateFunc machoUpdateFunc) {
|
|
|
|
|
|
// For os.Rename to work reliably, must be in same directory as outfile.
|
|
|
|
|
|
rewrittenOutput := *flagOutfile + "~"
|
|
|
|
|
|
exef, err := os.Open(*flagOutfile)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
Exitf("%s: %s failed: %v", os.Args[0], op, err)
|
|
|
|
|
|
}
|
|
|
|
|
|
defer exef.Close()
|
|
|
|
|
|
exem, err := macho.NewFile(exef)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
Exitf("%s: parsing Mach-O header failed: %v", os.Args[0], err)
|
|
|
|
|
|
}
|
|
|
|
|
|
if err := updateFunc(ctxt, exef, exem, rewrittenOutput); err != nil {
|
|
|
|
|
|
Exitf("%s: %s failed: %v", os.Args[0], op, err)
|
|
|
|
|
|
}
|
|
|
|
|
|
os.Remove(*flagOutfile)
|
|
|
|
|
|
if err := os.Rename(rewrittenOutput, *flagOutfile); err != nil {
|
|
|
|
|
|
Exitf("%s: %v", os.Args[0], err)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uuidUpdated := false
|
cmd/link: strip STAB (symbolic debugging) symbols on darwin
On darwin, with external linking, the system linker produces STAB
(symbolic debugging) symbols in the binary's symbol table. These
include paths of the intermediate object files, like
<tmpdir>/go.o, which changes from run to run, making the build
non-reproducible.
Since we run dsymutil to produce debug info and combine them
back into the binary, we don't need those STAB symbols anymore.
Strip them after running dsymutil.
If DWARF is not enabled, we don't run dsymutil. We can pass
"-Wl,-S" to let the system linker not generate those symbols.
While here, also make it more consistent about DWARF combining.
Currently we only do DWARF combining on macOS/AMD64, when DWARF
is enabled. On ARM64, we run dsymutil, but then throw the result
away. This CL changes it to not run dsymutil (and strip) on
ARM64.
TODO: add a test. We don't do it here as it fails on some
(non-darwin) platforms.
Fixes #40979.
Change-Id: If770f7828cdb858857d6079e0585bf067f8f7a92
Reviewed-on: https://go-review.googlesource.com/c/go/+/250944
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
2020-08-26 18:19:03 -04:00
|
|
|
|
if combineDwarf {
|
2021-07-22 18:57:52 -04:00
|
|
|
|
// Find "dsymutils" and "strip" tools using CC --print-prog-name.
|
2023-03-28 09:17:27 -04:00
|
|
|
|
dsymutilCmd := ctxt.findExtLinkTool("dsymutil")
|
|
|
|
|
|
stripCmd := ctxt.findExtLinkTool("strip")
|
2021-07-22 18:57:52 -04:00
|
|
|
|
|
2018-04-19 15:09:34 -04:00
|
|
|
|
dsym := filepath.Join(*flagTmpdir, "go.dwarf")
|
2023-05-01 12:47:15 -04:00
|
|
|
|
cmd := exec.Command(dsymutilCmd, "-f", *flagOutfile, "-o", dsym)
|
|
|
|
|
|
// dsymutil may not clean up its temp directory at exit.
|
|
|
|
|
|
// Set DSYMUTIL_REPRODUCER_PATH to work around. see issue 59026.
|
2024-06-21 11:56:45 -04:00
|
|
|
|
// dsymutil (Apple LLVM version 16.0.0) deletes the directory
|
|
|
|
|
|
// even if it is not empty. We still need our tmpdir, so give a
|
|
|
|
|
|
// subdirectory to dsymutil.
|
|
|
|
|
|
dsymDir := filepath.Join(*flagTmpdir, "dsymutil")
|
|
|
|
|
|
err := os.MkdirAll(dsymDir, 0777)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
Exitf("fail to create temp dir: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
cmd.Env = append(os.Environ(), "DSYMUTIL_REPRODUCER_PATH="+dsymDir)
|
2023-06-16 16:03:29 -04:00
|
|
|
|
if ctxt.Debugvlog != 0 {
|
|
|
|
|
|
ctxt.Logf("host link dsymutil:")
|
|
|
|
|
|
for _, v := range cmd.Args {
|
|
|
|
|
|
ctxt.Logf(" %q", v)
|
|
|
|
|
|
}
|
|
|
|
|
|
ctxt.Logf("\n")
|
|
|
|
|
|
}
|
2023-05-01 12:47:15 -04:00
|
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
2024-01-26 12:08:00 -05:00
|
|
|
|
Exitf("%s: running dsymutil failed: %v\n%s\n%s", os.Args[0], err, cmd, out)
|
2018-04-19 15:09:34 -04:00
|
|
|
|
}
|
cmd/link: strip STAB (symbolic debugging) symbols on darwin
On darwin, with external linking, the system linker produces STAB
(symbolic debugging) symbols in the binary's symbol table. These
include paths of the intermediate object files, like
<tmpdir>/go.o, which changes from run to run, making the build
non-reproducible.
Since we run dsymutil to produce debug info and combine them
back into the binary, we don't need those STAB symbols anymore.
Strip them after running dsymutil.
If DWARF is not enabled, we don't run dsymutil. We can pass
"-Wl,-S" to let the system linker not generate those symbols.
While here, also make it more consistent about DWARF combining.
Currently we only do DWARF combining on macOS/AMD64, when DWARF
is enabled. On ARM64, we run dsymutil, but then throw the result
away. This CL changes it to not run dsymutil (and strip) on
ARM64.
TODO: add a test. We don't do it here as it fails on some
(non-darwin) platforms.
Fixes #40979.
Change-Id: If770f7828cdb858857d6079e0585bf067f8f7a92
Reviewed-on: https://go-review.googlesource.com/c/go/+/250944
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
2020-08-26 18:19:03 -04:00
|
|
|
|
// Remove STAB (symbolic debugging) symbols after we are done with them (by dsymutil).
|
|
|
|
|
|
// They contain temporary file paths and make the build not reproducible.
|
2023-05-05 18:52:39 -04:00
|
|
|
|
var stripArgs = []string{"-S"}
|
|
|
|
|
|
if debug_s {
|
|
|
|
|
|
// We are generating a binary with symbol table suppressed.
|
|
|
|
|
|
// Suppress local symbols. We need to keep dynamically exported
|
|
|
|
|
|
// and referenced symbols so the dynamic linker can resolve them.
|
|
|
|
|
|
stripArgs = append(stripArgs, "-x")
|
|
|
|
|
|
}
|
|
|
|
|
|
stripArgs = append(stripArgs, *flagOutfile)
|
2023-06-16 16:03:29 -04:00
|
|
|
|
if ctxt.Debugvlog != 0 {
|
|
|
|
|
|
ctxt.Logf("host link strip: %q", stripCmd)
|
|
|
|
|
|
for _, v := range stripArgs {
|
|
|
|
|
|
ctxt.Logf(" %q", v)
|
|
|
|
|
|
}
|
|
|
|
|
|
ctxt.Logf("\n")
|
|
|
|
|
|
}
|
2024-01-26 12:08:00 -05:00
|
|
|
|
cmd = exec.Command(stripCmd, stripArgs...)
|
|
|
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
|
|
|
|
Exitf("%s: running strip failed: %v\n%s\n%s", os.Args[0], err, cmd, out)
|
cmd/link: strip STAB (symbolic debugging) symbols on darwin
On darwin, with external linking, the system linker produces STAB
(symbolic debugging) symbols in the binary's symbol table. These
include paths of the intermediate object files, like
<tmpdir>/go.o, which changes from run to run, making the build
non-reproducible.
Since we run dsymutil to produce debug info and combine them
back into the binary, we don't need those STAB symbols anymore.
Strip them after running dsymutil.
If DWARF is not enabled, we don't run dsymutil. We can pass
"-Wl,-S" to let the system linker not generate those symbols.
While here, also make it more consistent about DWARF combining.
Currently we only do DWARF combining on macOS/AMD64, when DWARF
is enabled. On ARM64, we run dsymutil, but then throw the result
away. This CL changes it to not run dsymutil (and strip) on
ARM64.
TODO: add a test. We don't do it here as it fails on some
(non-darwin) platforms.
Fixes #40979.
Change-Id: If770f7828cdb858857d6079e0585bf067f8f7a92
Reviewed-on: https://go-review.googlesource.com/c/go/+/250944
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
2020-08-26 18:19:03 -04:00
|
|
|
|
}
|
2018-04-19 15:09:34 -04:00
|
|
|
|
// Skip combining if `dsymutil` didn't generate a file. See #11994.
|
2024-06-21 12:20:38 -04:00
|
|
|
|
if _, err := os.Stat(dsym); err == nil {
|
|
|
|
|
|
updateMachoOutFile("combining dwarf",
|
|
|
|
|
|
func(ctxt *Link, exef *os.File, exem *macho.File, outexe string) error {
|
|
|
|
|
|
return machoCombineDwarf(ctxt, exef, exem, dsym, outexe)
|
|
|
|
|
|
})
|
|
|
|
|
|
uuidUpdated = true
|
2018-04-19 15:09:34 -04:00
|
|
|
|
}
|
2024-05-20 14:52:57 +00:00
|
|
|
|
}
|
2024-10-08 13:17:47 -04:00
|
|
|
|
if ctxt.IsDarwin() && !uuidUpdated && len(buildinfo) > 0 {
|
2024-05-20 14:52:57 +00:00
|
|
|
|
updateMachoOutFile("rewriting uuid",
|
|
|
|
|
|
func(ctxt *Link, exef *os.File, exem *macho.File, outexe string) error {
|
|
|
|
|
|
return machoRewriteUuid(ctxt, exef, exem, outexe)
|
|
|
|
|
|
})
|
2015-04-08 12:55:34 -07:00
|
|
|
|
}
|
2024-11-05 13:51:32 -05:00
|
|
|
|
hostlinkfips(ctxt, *flagOutfile, *flagFipso)
|
2020-11-21 20:11:03 -05:00
|
|
|
|
if ctxt.NeedCodeSign() {
|
|
|
|
|
|
err := machoCodeSign(ctxt, *flagOutfile)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
Exitf("%s: code signing failed: %v", os.Args[0], err)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-06-27 14:58:58 -07:00
|
|
|
|
// passLongArgsInResponseFile writes the arguments into a file if they
|
|
|
|
|
|
// are very long.
|
|
|
|
|
|
func (ctxt *Link) passLongArgsInResponseFile(argv []string, altLinker string) []string {
|
|
|
|
|
|
c := 0
|
|
|
|
|
|
for _, arg := range argv {
|
|
|
|
|
|
c += len(arg)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if c < sys.ExecArgLengthLimit {
|
|
|
|
|
|
return argv
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Only use response files if they are supported.
|
|
|
|
|
|
response := filepath.Join(*flagTmpdir, "response")
|
|
|
|
|
|
if err := os.WriteFile(response, nil, 0644); err != nil {
|
|
|
|
|
|
log.Fatalf("failed while testing response file: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
if !linkerFlagSupported(ctxt.Arch, argv[0], altLinker, "@"+response) {
|
|
|
|
|
|
if ctxt.Debugvlog != 0 {
|
|
|
|
|
|
ctxt.Logf("not using response file because linker does not support one")
|
|
|
|
|
|
}
|
|
|
|
|
|
return argv
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
|
for _, arg := range argv[1:] {
|
|
|
|
|
|
// The external linker response file supports quoted strings.
|
|
|
|
|
|
fmt.Fprintf(&buf, "%q\n", arg)
|
|
|
|
|
|
}
|
|
|
|
|
|
if err := os.WriteFile(response, buf.Bytes(), 0644); err != nil {
|
|
|
|
|
|
log.Fatalf("failed while writing response file: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
if ctxt.Debugvlog != 0 {
|
|
|
|
|
|
ctxt.Logf("response file %s contents:\n%s", response, buf.Bytes())
|
|
|
|
|
|
}
|
|
|
|
|
|
return []string{
|
|
|
|
|
|
argv[0],
|
|
|
|
|
|
"@" + response,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-05-07 13:44:22 -04:00
|
|
|
|
var createTrivialCOnce sync.Once
|
|
|
|
|
|
|
2020-12-15 18:31:21 -05:00
|
|
|
|
func linkerFlagSupported(arch *sys.Arch, linker, altLinker, flag string) bool {
|
2018-05-07 13:44:22 -04:00
|
|
|
|
createTrivialCOnce.Do(func() {
|
|
|
|
|
|
src := filepath.Join(*flagTmpdir, "trivial.c")
|
2022-08-28 03:38:00 +08:00
|
|
|
|
if err := os.WriteFile(src, []byte("int main() { return 0; }"), 0666); err != nil {
|
2024-11-01 14:56:25 -04:00
|
|
|
|
Errorf("WriteFile trivial.c failed: %v", err)
|
2018-05-07 13:44:22 -04:00
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
|
2022-06-27 14:58:58 -07:00
|
|
|
|
flags := hostlinkArchArgs(arch)
|
|
|
|
|
|
|
2024-09-18 15:05:40 -07:00
|
|
|
|
moreFlags := trimLinkerArgv(append(ldflag, flagExtldflags...))
|
2022-06-27 14:58:58 -07:00
|
|
|
|
flags = append(flags, moreFlags...)
|
|
|
|
|
|
|
|
|
|
|
|
if altLinker != "" {
|
|
|
|
|
|
flags = append(flags, "-fuse-ld="+altLinker)
|
|
|
|
|
|
}
|
2023-05-03 18:27:05 +00:00
|
|
|
|
trivialPath := filepath.Join(*flagTmpdir, "trivial.c")
|
|
|
|
|
|
outPath := filepath.Join(*flagTmpdir, "a.out")
|
|
|
|
|
|
flags = append(flags, "-o", outPath, flag, trivialPath)
|
2022-06-27 14:58:58 -07:00
|
|
|
|
|
|
|
|
|
|
cmd := exec.Command(linker, flags...)
|
|
|
|
|
|
cmd.Env = append([]string{"LC_ALL=C"}, os.Environ()...)
|
|
|
|
|
|
out, err := cmd.CombinedOutput()
|
|
|
|
|
|
// GCC says "unrecognized command line option ‘-no-pie’"
|
|
|
|
|
|
// clang says "unknown argument: '-no-pie'"
|
|
|
|
|
|
return err == nil && !bytes.Contains(out, []byte("unrecognized")) && !bytes.Contains(out, []byte("unknown"))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// trimLinkerArgv returns a new copy of argv that does not include flags
|
|
|
|
|
|
// that are not relevant for testing whether some linker option works.
|
|
|
|
|
|
func trimLinkerArgv(argv []string) []string {
|
2018-09-07 12:53:52 -07:00
|
|
|
|
flagsWithNextArgSkip := []string{
|
|
|
|
|
|
"-F",
|
|
|
|
|
|
"-l",
|
|
|
|
|
|
"-L",
|
|
|
|
|
|
"-framework",
|
|
|
|
|
|
"-Wl,-framework",
|
|
|
|
|
|
"-Wl,-rpath",
|
|
|
|
|
|
"-Wl,-undefined",
|
|
|
|
|
|
}
|
|
|
|
|
|
flagsWithNextArgKeep := []string{
|
|
|
|
|
|
"-arch",
|
|
|
|
|
|
"-isysroot",
|
|
|
|
|
|
"--sysroot",
|
|
|
|
|
|
"-target",
|
cmd/link: support MSVC clang
Currently on Windows, for cgo, we support MinGW-based C toolchain,
that is, with a -windows-gnu target. This CL makes it work with
clang with a -windows-msvc target. The LLVM toolchain bundled in
MSVC (https://learn.microsoft.com/en-us/cpp/build/clang-support-msbuild)
is such an example.
Currently it is expecting lld-link as the C linker, which is also
bundled in MSVC, can be requested with -fuse-ld=lld, but is not
the default.
This is the first step, which makes it generate a working cgo
binary. There are still more work to do, e.g. there are some
linker warnings, and the binary doesn't have symbol table.
all.bat doesn't pass with this setting.
Change-Id: I54d33f7dd5f5eeeafa0735cd52f4127fe4865636
Reviewed-on: https://go-review.googlesource.com/c/go/+/703055
Reviewed-by: Than McIntosh <thanm@golang.org>
Reviewed-by: Florian Zenker <floriank@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2025-09-11 17:42:30 -04:00
|
|
|
|
"--target",
|
2018-09-07 12:53:52 -07:00
|
|
|
|
}
|
|
|
|
|
|
prefixesToKeep := []string{
|
|
|
|
|
|
"-f",
|
|
|
|
|
|
"-m",
|
|
|
|
|
|
"-p",
|
|
|
|
|
|
"-Wl,",
|
|
|
|
|
|
"-arch",
|
|
|
|
|
|
"-isysroot",
|
|
|
|
|
|
"--sysroot",
|
|
|
|
|
|
"-target",
|
cmd/link: support MSVC clang
Currently on Windows, for cgo, we support MinGW-based C toolchain,
that is, with a -windows-gnu target. This CL makes it work with
clang with a -windows-msvc target. The LLVM toolchain bundled in
MSVC (https://learn.microsoft.com/en-us/cpp/build/clang-support-msbuild)
is such an example.
Currently it is expecting lld-link as the C linker, which is also
bundled in MSVC, can be requested with -fuse-ld=lld, but is not
the default.
This is the first step, which makes it generate a working cgo
binary. There are still more work to do, e.g. there are some
linker warnings, and the binary doesn't have symbol table.
all.bat doesn't pass with this setting.
Change-Id: I54d33f7dd5f5eeeafa0735cd52f4127fe4865636
Reviewed-on: https://go-review.googlesource.com/c/go/+/703055
Reviewed-by: Than McIntosh <thanm@golang.org>
Reviewed-by: Florian Zenker <floriank@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2025-09-11 17:42:30 -04:00
|
|
|
|
"--target",
|
2018-09-07 12:53:52 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-06-27 14:58:58 -07:00
|
|
|
|
var flags []string
|
2018-09-07 12:53:52 -07:00
|
|
|
|
keep := false
|
|
|
|
|
|
skip := false
|
2022-06-27 14:58:58 -07:00
|
|
|
|
for _, f := range argv {
|
2018-09-07 12:53:52 -07:00
|
|
|
|
if keep {
|
|
|
|
|
|
flags = append(flags, f)
|
|
|
|
|
|
keep = false
|
|
|
|
|
|
} else if skip {
|
|
|
|
|
|
skip = false
|
|
|
|
|
|
} else if f == "" || f[0] != '-' {
|
2024-09-12 14:47:32 +02:00
|
|
|
|
} else if slices.Contains(flagsWithNextArgSkip, f) {
|
2018-09-07 12:53:52 -07:00
|
|
|
|
skip = true
|
2024-09-12 14:47:32 +02:00
|
|
|
|
} else if slices.Contains(flagsWithNextArgKeep, f) {
|
2018-09-07 12:53:52 -07:00
|
|
|
|
flags = append(flags, f)
|
|
|
|
|
|
keep = true
|
|
|
|
|
|
} else {
|
|
|
|
|
|
for _, p := range prefixesToKeep {
|
|
|
|
|
|
if strings.HasPrefix(f, p) {
|
|
|
|
|
|
flags = append(flags, f)
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-06-27 14:58:58 -07:00
|
|
|
|
return flags
|
2018-05-07 13:44:22 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
2015-11-16 18:11:35 -08:00
|
|
|
|
// hostlinkArchArgs returns arguments to pass to the external linker
|
|
|
|
|
|
// based on the architecture.
|
2017-09-30 21:10:49 +00:00
|
|
|
|
func hostlinkArchArgs(arch *sys.Arch) []string {
|
|
|
|
|
|
switch arch.Family {
|
2016-04-06 12:01:40 -07:00
|
|
|
|
case sys.I386:
|
2015-11-16 18:11:35 -08:00
|
|
|
|
return []string{"-m32"}
|
2021-01-14 12:29:16 -05:00
|
|
|
|
case sys.AMD64:
|
2021-04-15 23:05:49 -04:00
|
|
|
|
if buildcfg.GOOS == "darwin" {
|
2021-01-14 12:29:16 -05:00
|
|
|
|
return []string{"-arch", "x86_64", "-m64"}
|
|
|
|
|
|
}
|
|
|
|
|
|
return []string{"-m64"}
|
|
|
|
|
|
case sys.S390X:
|
2015-11-16 18:11:35 -08:00
|
|
|
|
return []string{"-m64"}
|
2016-04-06 12:01:40 -07:00
|
|
|
|
case sys.ARM:
|
2015-11-16 18:11:35 -08:00
|
|
|
|
return []string{"-marm"}
|
2016-04-06 12:01:40 -07:00
|
|
|
|
case sys.ARM64:
|
2021-04-15 23:05:49 -04:00
|
|
|
|
if buildcfg.GOOS == "darwin" {
|
2021-01-14 12:29:16 -05:00
|
|
|
|
return []string{"-arch", "arm64"}
|
|
|
|
|
|
}
|
2021-08-15 16:25:46 +08:00
|
|
|
|
case sys.Loong64:
|
|
|
|
|
|
return []string{"-mabi=lp64d"}
|
2016-05-04 21:38:45 -07:00
|
|
|
|
case sys.MIPS64:
|
2016-04-27 22:18:09 -04:00
|
|
|
|
return []string{"-mabi=64"}
|
2016-12-13 21:23:39 +01:00
|
|
|
|
case sys.MIPS:
|
|
|
|
|
|
return []string{"-mabi=32"}
|
2019-02-20 16:16:38 +01:00
|
|
|
|
case sys.PPC64:
|
2021-04-15 23:05:49 -04:00
|
|
|
|
if buildcfg.GOOS == "aix" {
|
2019-02-20 16:16:38 +01:00
|
|
|
|
return []string{"-maix64"}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return []string{"-m64"}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-11-16 18:11:35 -08:00
|
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-04-20 14:08:58 -04:00
|
|
|
|
var wantHdr = objabi.HeaderString()
|
|
|
|
|
|
|
2016-03-01 23:21:55 +00:00
|
|
|
|
// ldobj loads an input object. If it is a host object (an object
|
|
|
|
|
|
// compiled by a non-Go compiler) it returns the Hostobj pointer. If
|
2015-11-04 11:14:19 -08:00
|
|
|
|
// it is a Go object, it returns nil.
|
2018-03-23 10:28:39 -07:00
|
|
|
|
func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string, file string) *Hostobj {
|
2017-04-17 18:46:09 -05:00
|
|
|
|
pkg := objabi.PathToPrefix(lib.Pkg)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
2016-09-14 14:47:12 -04:00
|
|
|
|
eof := f.Offset() + length
|
2016-04-08 19:14:03 +10:00
|
|
|
|
start := f.Offset()
|
2016-04-08 20:44:56 +10:00
|
|
|
|
c1 := bgetc(f)
|
|
|
|
|
|
c2 := bgetc(f)
|
|
|
|
|
|
c3 := bgetc(f)
|
|
|
|
|
|
c4 := bgetc(f)
|
2019-05-08 18:46:04 -04:00
|
|
|
|
f.MustSeek(start, 0)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
2019-08-09 11:36:03 -04:00
|
|
|
|
unit := &sym.CompilationUnit{Lib: lib}
|
|
|
|
|
|
lib.Units = append(lib.Units, unit)
|
|
|
|
|
|
|
2015-03-02 12:35:15 -05:00
|
|
|
|
magic := uint32(c1)<<24 | uint32(c2)<<16 | uint32(c3)<<8 | uint32(c4)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
if magic == 0x7f454c46 { // \x7F E L F
|
2020-01-23 10:39:13 -05:00
|
|
|
|
ldelf := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
2020-10-27 14:18:13 +08:00
|
|
|
|
textp, flags, err := loadelf.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn, ehdr.Flags)
|
2020-01-23 10:39:13 -05:00
|
|
|
|
if err != nil {
|
2024-11-01 14:56:25 -04:00
|
|
|
|
Errorf("%v", err)
|
2020-01-23 10:39:13 -05:00
|
|
|
|
return
|
2019-12-06 20:11:36 -05:00
|
|
|
|
}
|
2020-10-27 14:18:13 +08:00
|
|
|
|
ehdr.Flags = flags
|
2020-05-15 18:35:05 -04:00
|
|
|
|
ctxt.Textp = append(ctxt.Textp, textp...)
|
2017-10-06 16:01:02 -04:00
|
|
|
|
}
|
2020-01-23 10:39:13 -05:00
|
|
|
|
return ldhostobj(ldelf, ctxt.HeadType, f, pkg, length, pn, file)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if magic&^1 == 0xfeedface || magic&^0x01000000 == 0xcefaedfe {
|
2019-11-11 14:32:30 -05:00
|
|
|
|
ldmacho := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
2020-05-21 16:35:24 -04:00
|
|
|
|
textp, err := loadmacho.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn)
|
2019-11-11 14:32:30 -05:00
|
|
|
|
if err != nil {
|
2024-11-01 14:56:25 -04:00
|
|
|
|
Errorf("%v", err)
|
2019-11-11 14:32:30 -05:00
|
|
|
|
return
|
2017-10-06 11:53:52 -04:00
|
|
|
|
}
|
2020-05-15 18:35:05 -04:00
|
|
|
|
ctxt.Textp = append(ctxt.Textp, textp...)
|
2017-10-06 11:53:52 -04:00
|
|
|
|
}
|
2019-11-11 14:32:30 -05:00
|
|
|
|
return ldhostobj(ldmacho, ctxt.HeadType, f, pkg, length, pn, file)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-02-04 00:11:12 +01:00
|
|
|
|
switch c1<<8 | c2 {
|
|
|
|
|
|
case 0x4c01, // 386
|
|
|
|
|
|
0x6486, // amd64
|
|
|
|
|
|
0xc401, // arm
|
|
|
|
|
|
0x64aa: // arm64
|
2019-11-11 14:32:30 -05:00
|
|
|
|
ldpe := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
2023-10-11 16:52:40 +02:00
|
|
|
|
ls, err := loadpe.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn)
|
2019-11-11 14:32:30 -05:00
|
|
|
|
if err != nil {
|
2024-11-01 14:56:25 -04:00
|
|
|
|
Errorf("%v", err)
|
2019-11-11 14:32:30 -05:00
|
|
|
|
return
|
2017-10-12 13:38:45 -04:00
|
|
|
|
}
|
2023-10-11 16:52:40 +02:00
|
|
|
|
if len(ls.Resources) != 0 {
|
|
|
|
|
|
setpersrc(ctxt, ls.Resources)
|
2017-10-12 13:38:45 -04:00
|
|
|
|
}
|
2023-10-11 16:52:40 +02:00
|
|
|
|
if ls.PData != 0 {
|
|
|
|
|
|
sehp.pdata = append(sehp.pdata, ls.PData)
|
|
|
|
|
|
}
|
|
|
|
|
|
if ls.XData != 0 {
|
|
|
|
|
|
sehp.xdata = append(sehp.xdata, ls.XData)
|
|
|
|
|
|
}
|
|
|
|
|
|
ctxt.Textp = append(ctxt.Textp, ls.Textp...)
|
2017-10-12 13:38:45 -04:00
|
|
|
|
}
|
2019-11-11 14:32:30 -05:00
|
|
|
|
return ldhostobj(ldpe, ctxt.HeadType, f, pkg, length, pn, file)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-09-28 17:02:16 +02:00
|
|
|
|
if c1 == 0x01 && (c2 == 0xD7 || c2 == 0xF7) {
|
2019-11-11 14:32:30 -05:00
|
|
|
|
ldxcoff := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
2020-05-21 16:35:24 -04:00
|
|
|
|
textp, err := loadxcoff.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn)
|
2019-11-11 14:32:30 -05:00
|
|
|
|
if err != nil {
|
2024-11-01 14:56:25 -04:00
|
|
|
|
Errorf("%v", err)
|
2019-11-11 14:32:30 -05:00
|
|
|
|
return
|
2018-09-28 17:02:16 +02:00
|
|
|
|
}
|
2020-05-15 18:35:05 -04:00
|
|
|
|
ctxt.Textp = append(ctxt.Textp, textp...)
|
2018-09-28 17:02:16 +02:00
|
|
|
|
}
|
2019-11-11 14:32:30 -05:00
|
|
|
|
return ldhostobj(ldxcoff, ctxt.HeadType, f, pkg, length, pn, file)
|
2018-09-28 17:02:16 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-05-25 16:31:41 -07:00
|
|
|
|
if c1 != 'g' || c2 != 'o' || c3 != ' ' || c4 != 'o' {
|
|
|
|
|
|
// An unrecognized object is just passed to the external linker.
|
|
|
|
|
|
// If we try to read symbols from this object, we will
|
|
|
|
|
|
// report an error at that time.
|
|
|
|
|
|
unknownObjFormat = true
|
|
|
|
|
|
return ldhostobj(nil, ctxt.HeadType, f, pkg, length, pn, file)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-02-27 22:57:28 -05:00
|
|
|
|
/* check the header */
|
2016-04-08 20:44:56 +10:00
|
|
|
|
line, err := f.ReadString('\n')
|
|
|
|
|
|
if err != nil {
|
2024-11-01 14:56:25 -04:00
|
|
|
|
Errorf("truncated object file: %s: %v", pn, err)
|
2015-11-04 11:14:19 -08:00
|
|
|
|
return nil
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if !strings.HasPrefix(line, "go object ") {
|
|
|
|
|
|
if strings.HasSuffix(pn, ".go") {
|
2016-04-06 18:54:17 -07:00
|
|
|
|
Exitf("%s: uncompiled .go source file", pn)
|
|
|
|
|
|
return nil
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-09-30 21:10:49 +00:00
|
|
|
|
if line == ctxt.Arch.Name {
|
2015-02-27 22:57:28 -05:00
|
|
|
|
// old header format: just $GOOS
|
2024-11-01 14:56:25 -04:00
|
|
|
|
Errorf("%s: stale object file", pn)
|
2015-11-04 11:14:19 -08:00
|
|
|
|
return nil
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-11-01 14:56:25 -04:00
|
|
|
|
Errorf("%s: not an object file: @%d %q", pn, start, line)
|
2015-11-04 11:14:19 -08:00
|
|
|
|
return nil
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-09-09 08:13:16 -04:00
|
|
|
|
// First, check that the basic GOOS, GOARCH, and Version match.
|
2021-04-20 14:08:58 -04:00
|
|
|
|
if line != wantHdr {
|
2024-11-01 14:56:25 -04:00
|
|
|
|
Errorf("%s: linked object header mismatch:\nhave %q\nwant %q\n", pn, line, wantHdr)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-11-21 11:27:20 -08:00
|
|
|
|
// Skip over exports and other info -- ends with \n!\n.
|
|
|
|
|
|
//
|
|
|
|
|
|
// Note: It's possible for "\n!\n" to appear within the binary
|
|
|
|
|
|
// package export data format. To avoid truncating the package
|
2018-10-06 06:10:25 +00:00
|
|
|
|
// definition prematurely (issue 21703), we keep track of
|
2017-11-21 11:27:20 -08:00
|
|
|
|
// how many "$$" delimiters we've seen.
|
|
|
|
|
|
|
2016-04-08 19:14:03 +10:00
|
|
|
|
import0 := f.Offset()
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
|
|
|
|
|
c1 = '\n' // the last line ended in \n
|
2016-04-08 20:44:56 +10:00
|
|
|
|
c2 = bgetc(f)
|
|
|
|
|
|
c3 = bgetc(f)
|
2017-11-21 11:27:20 -08:00
|
|
|
|
markers := 0
|
|
|
|
|
|
for {
|
|
|
|
|
|
if c1 == '\n' {
|
|
|
|
|
|
if markers%2 == 0 && c2 == '!' && c3 == '\n' {
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
if c2 == '$' && c3 == '$' {
|
|
|
|
|
|
markers++
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-02-27 22:57:28 -05:00
|
|
|
|
c1 = c2
|
|
|
|
|
|
c2 = c3
|
2016-04-08 20:44:56 +10:00
|
|
|
|
c3 = bgetc(f)
|
|
|
|
|
|
if c3 == -1 {
|
2024-11-01 14:56:25 -04:00
|
|
|
|
Errorf("truncated object file: %s", pn)
|
2015-11-04 11:14:19 -08:00
|
|
|
|
return nil
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-04-08 19:14:03 +10:00
|
|
|
|
import1 := f.Offset()
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
2019-05-08 18:46:04 -04:00
|
|
|
|
f.MustSeek(import0, 0)
|
2018-03-23 10:28:39 -07:00
|
|
|
|
ldpkg(ctxt, f, lib, import1-import0-2, pn) // -2 for !\n
|
2019-05-08 18:46:04 -04:00
|
|
|
|
f.MustSeek(import1, 0)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
2020-05-21 16:35:24 -04:00
|
|
|
|
fingerprint := ctxt.loader.Preload(ctxt.IncVersion(), f, lib, unit, eof-f.Offset())
|
2020-04-22 22:20:44 -04:00
|
|
|
|
if !fingerprint.IsZero() { // Assembly objects don't have fingerprints. Ignore them.
|
|
|
|
|
|
// Check fingerprint, to ensure the importing and imported packages
|
|
|
|
|
|
// have consistent view of symbol indices.
|
|
|
|
|
|
// Normally the go command should ensure this. But in case something
|
|
|
|
|
|
// goes wrong, it could lead to obscure bugs like run-time crash.
|
|
|
|
|
|
// Check it here to be sure.
|
|
|
|
|
|
if lib.Fingerprint.IsZero() { // Not yet imported. Update its fingerprint.
|
|
|
|
|
|
lib.Fingerprint = fingerprint
|
|
|
|
|
|
}
|
|
|
|
|
|
checkFingerprint(lib, fingerprint, lib.Srcref, lib.Fingerprint)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-10-04 18:13:35 -04:00
|
|
|
|
addImports(ctxt, lib, pn)
|
2015-11-04 11:14:19 -08:00
|
|
|
|
return nil
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-02-03 08:23:10 -05:00
|
|
|
|
// symbolsAreUnresolved scans through the loader's list of unresolved
|
|
|
|
|
|
// symbols and checks to see whether any of them match the names of the
|
|
|
|
|
|
// symbols in 'want'. Return value is a list of bools, with list[K] set
|
|
|
|
|
|
// to true if there is an unresolved reference to the symbol in want[K].
|
|
|
|
|
|
func symbolsAreUnresolved(ctxt *Link, want []string) []bool {
|
|
|
|
|
|
returnAllUndefs := -1
|
2022-11-01 10:27:18 -04:00
|
|
|
|
undefs, _ := ctxt.loader.UndefinedRelocTargets(returnAllUndefs)
|
2022-02-03 08:23:10 -05:00
|
|
|
|
seen := make(map[loader.Sym]struct{})
|
|
|
|
|
|
rval := make([]bool, len(want))
|
|
|
|
|
|
wantm := make(map[string]int)
|
|
|
|
|
|
for k, w := range want {
|
|
|
|
|
|
wantm[w] = k
|
|
|
|
|
|
}
|
|
|
|
|
|
count := 0
|
|
|
|
|
|
for _, s := range undefs {
|
|
|
|
|
|
if _, ok := seen[s]; ok {
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
seen[s] = struct{}{}
|
|
|
|
|
|
if k, ok := wantm[ctxt.loader.SymName(s)]; ok {
|
|
|
|
|
|
rval[k] = true
|
|
|
|
|
|
count++
|
|
|
|
|
|
if count == len(want) {
|
|
|
|
|
|
return rval
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return rval
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// hostObject reads a single host object file (compare to "hostArchive").
|
|
|
|
|
|
// This is used as part of internal linking when we need to pull in
|
|
|
|
|
|
// files such as "crt?.o".
|
|
|
|
|
|
func hostObject(ctxt *Link, objname string, path string) {
|
|
|
|
|
|
if ctxt.Debugvlog > 1 {
|
|
|
|
|
|
ctxt.Logf("hostObject(%s)\n", path)
|
|
|
|
|
|
}
|
|
|
|
|
|
objlib := sym.Library{
|
|
|
|
|
|
Pkg: objname,
|
|
|
|
|
|
}
|
|
|
|
|
|
f, err := bio.Open(path)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
Exitf("cannot open host object %q file %s: %v", objname, path, err)
|
|
|
|
|
|
}
|
|
|
|
|
|
defer f.Close()
|
|
|
|
|
|
h := ldobj(ctxt, f, &objlib, 0, path, path)
|
|
|
|
|
|
if h.ld == nil {
|
|
|
|
|
|
Exitf("unrecognized object file format in %s", path)
|
|
|
|
|
|
}
|
2022-11-01 11:08:00 -04:00
|
|
|
|
h.file = path
|
|
|
|
|
|
h.length = f.MustSeek(0, 2)
|
2022-02-03 08:23:10 -05:00
|
|
|
|
f.MustSeek(h.off, 0)
|
|
|
|
|
|
h.ld(ctxt, f, h.pkg, h.length, h.pn)
|
2022-11-01 11:08:00 -04:00
|
|
|
|
if *flagCaptureHostObjs != "" {
|
|
|
|
|
|
captureHostObj(h)
|
|
|
|
|
|
}
|
2022-02-03 08:23:10 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-08-02 19:36:28 -04:00
|
|
|
|
func checkFingerprint(lib *sym.Library, libfp goobj.FingerprintType, src string, srcfp goobj.FingerprintType) {
|
2020-04-22 22:20:44 -04:00
|
|
|
|
if libfp != srcfp {
|
|
|
|
|
|
Exitf("fingerprint mismatch: %s has %x, import from %s expecting %x", lib, libfp, src, srcfp)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-08-19 22:40:38 -04:00
|
|
|
|
func readelfsymboldata(ctxt *Link, f *elf.File, sym *elf.Symbol) []byte {
|
2015-04-11 12:05:21 +08:00
|
|
|
|
data := make([]byte, sym.Size)
|
|
|
|
|
|
sect := f.Sections[sym.Section]
|
2015-05-25 13:59:08 +12:00
|
|
|
|
if sect.Type != elf.SHT_PROGBITS && sect.Type != elf.SHT_NOTE {
|
2024-11-01 14:56:25 -04:00
|
|
|
|
Errorf("reading %s from non-data section", sym.Name)
|
2015-04-11 12:05:21 +08:00
|
|
|
|
}
|
2015-05-25 16:13:50 +12:00
|
|
|
|
n, err := sect.ReadAt(data, int64(sym.Value-sect.Addr))
|
2015-04-11 12:05:21 +08:00
|
|
|
|
if uint64(n) != sym.Size {
|
2024-11-01 14:56:25 -04:00
|
|
|
|
Errorf("reading contents of %s: %v", sym.Name, err)
|
2015-04-11 12:05:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
return data
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-05-25 13:59:08 +12:00
|
|
|
|
func readwithpad(r io.Reader, sz int32) ([]byte, error) {
|
|
|
|
|
|
data := make([]byte, Rnd(int64(sz), 4))
|
|
|
|
|
|
_, err := io.ReadFull(r, data)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
data = data[:sz]
|
|
|
|
|
|
return data, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func readnote(f *elf.File, name []byte, typ int32) ([]byte, error) {
|
|
|
|
|
|
for _, sect := range f.Sections {
|
|
|
|
|
|
if sect.Type != elf.SHT_NOTE {
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
r := sect.Open()
|
|
|
|
|
|
for {
|
|
|
|
|
|
var namesize, descsize, noteType int32
|
|
|
|
|
|
err := binary.Read(r, f.ByteOrder, &namesize)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
if err == io.EOF {
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
2015-10-30 16:25:29 +01:00
|
|
|
|
return nil, fmt.Errorf("read namesize failed: %v", err)
|
2015-05-25 13:59:08 +12:00
|
|
|
|
}
|
|
|
|
|
|
err = binary.Read(r, f.ByteOrder, &descsize)
|
|
|
|
|
|
if err != nil {
|
2015-10-30 16:25:29 +01:00
|
|
|
|
return nil, fmt.Errorf("read descsize failed: %v", err)
|
2015-05-25 13:59:08 +12:00
|
|
|
|
}
|
|
|
|
|
|
err = binary.Read(r, f.ByteOrder, ¬eType)
|
|
|
|
|
|
if err != nil {
|
2015-10-30 16:25:29 +01:00
|
|
|
|
return nil, fmt.Errorf("read type failed: %v", err)
|
2015-05-25 13:59:08 +12:00
|
|
|
|
}
|
|
|
|
|
|
noteName, err := readwithpad(r, namesize)
|
|
|
|
|
|
if err != nil {
|
2015-10-30 16:25:29 +01:00
|
|
|
|
return nil, fmt.Errorf("read name failed: %v", err)
|
2015-05-25 13:59:08 +12:00
|
|
|
|
}
|
|
|
|
|
|
desc, err := readwithpad(r, descsize)
|
|
|
|
|
|
if err != nil {
|
2015-10-30 16:25:29 +01:00
|
|
|
|
return nil, fmt.Errorf("read desc failed: %v", err)
|
2015-05-25 13:59:08 +12:00
|
|
|
|
}
|
|
|
|
|
|
if string(name) == string(noteName) && typ == noteType {
|
|
|
|
|
|
return desc, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return nil, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-08-19 22:40:38 -04:00
|
|
|
|
func findshlib(ctxt *Link, shlib string) string {
|
2017-06-09 11:15:53 -04:00
|
|
|
|
if filepath.IsAbs(shlib) {
|
|
|
|
|
|
return shlib
|
|
|
|
|
|
}
|
2016-08-19 22:40:38 -04:00
|
|
|
|
for _, libdir := range ctxt.Libdir {
|
2015-05-25 14:51:02 +12:00
|
|
|
|
libpath := filepath.Join(libdir, shlib)
|
2015-04-01 14:57:34 +13:00
|
|
|
|
if _, err := os.Stat(libpath); err == nil {
|
2015-05-25 14:51:02 +12:00
|
|
|
|
return libpath
|
2015-04-01 14:57:34 +13:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-11-01 14:56:25 -04:00
|
|
|
|
Errorf("cannot find shared library: %s", shlib)
|
2015-05-25 14:51:02 +12:00
|
|
|
|
return ""
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-08-19 22:40:38 -04:00
|
|
|
|
func ldshlibsyms(ctxt *Link, shlib string) {
|
2017-06-09 11:15:53 -04:00
|
|
|
|
var libpath string
|
|
|
|
|
|
if filepath.IsAbs(shlib) {
|
|
|
|
|
|
libpath = shlib
|
|
|
|
|
|
shlib = filepath.Base(shlib)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
libpath = findshlib(ctxt, shlib)
|
|
|
|
|
|
if libpath == "" {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2015-04-01 14:57:34 +13:00
|
|
|
|
}
|
2016-08-19 22:40:38 -04:00
|
|
|
|
for _, processedlib := range ctxt.Shlibs {
|
2015-04-11 12:05:21 +08:00
|
|
|
|
if processedlib.Path == libpath {
|
2015-04-01 14:57:34 +13:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2016-08-25 12:32:42 +10:00
|
|
|
|
if ctxt.Debugvlog > 1 {
|
2019-04-13 16:42:48 +03:00
|
|
|
|
ctxt.Logf("ldshlibsyms: found library with name %s at %s\n", shlib, libpath)
|
2015-04-01 14:57:34 +13:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
f, err := elf.Open(libpath)
|
|
|
|
|
|
if err != nil {
|
2024-11-01 14:56:25 -04:00
|
|
|
|
Errorf("cannot open shared library: %s", libpath)
|
2015-04-01 14:57:34 +13:00
|
|
|
|
return
|
|
|
|
|
|
}
|
cmd/link: fix GC data reading from shared library (attempt 2)
When linking against a Go shared library, when a global variable
in the main module has a type defined in the shared library, the
linker needs to pull the GC data from the shared library to build
the GC program for the global variable. Currently, this fails
silently, as the shared library file is closed too early and the
read failed (with no error check), causing a zero GC map emitted
for the variable, which in turn causes the runtime to treat the
variable as pointerless.
For now, fix this by keeping the file open. In the future we may
want to use mmap to read from the shared library instead.
Also add error checking. And fix a (mostly harmless) mistake in
size caluculation.
Also remove an erroneous condition for ARM64. ARM64 used to have
a special case to get the addend from the relocation on the
gcdata field. That was removed, but the new code accidentally
returned 0 unconditionally. It's no longer necessary to have any
special case, since the addend is now applied directly to the
gcdata field on ARM64, like on all the other platforms.
Fixes #39927.
This is the second attempt of CL 240462. And this reverts
CL 240616.
Change-Id: I01c82422b9f67e872d833336885935bc509bc91b
Reviewed-on: https://go-review.googlesource.com/c/go/+/240621
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
2020-06-29 17:07:17 -04:00
|
|
|
|
// Keep the file open as decodetypeGcprog needs to read from it.
|
|
|
|
|
|
// TODO: fix. Maybe mmap the file.
|
|
|
|
|
|
//defer f.Close()
|
2015-05-25 13:59:08 +12:00
|
|
|
|
|
|
|
|
|
|
hash, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GOABIHASH_TAG)
|
|
|
|
|
|
if err != nil {
|
2024-11-01 14:56:25 -04:00
|
|
|
|
Errorf("cannot read ABI hash from shared library %s: %v", libpath, err)
|
2015-05-25 13:59:08 +12:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-05-25 14:51:02 +12:00
|
|
|
|
depsbytes, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GODEPS_TAG)
|
|
|
|
|
|
if err != nil {
|
2024-11-01 14:56:25 -04:00
|
|
|
|
Errorf("cannot read dep list from shared library %s: %v", libpath, err)
|
2015-05-25 14:51:02 +12:00
|
|
|
|
return
|
|
|
|
|
|
}
|
2017-06-09 11:15:53 -04:00
|
|
|
|
var deps []string
|
|
|
|
|
|
for _, dep := range strings.Split(string(depsbytes), "\n") {
|
|
|
|
|
|
if dep == "" {
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
if !filepath.IsAbs(dep) {
|
|
|
|
|
|
// If the dep can be interpreted as a path relative to the shlib
|
|
|
|
|
|
// in which it was found, do that. Otherwise, we will leave it
|
|
|
|
|
|
// to be resolved by libdir lookup.
|
|
|
|
|
|
abs := filepath.Join(filepath.Dir(libpath), dep)
|
|
|
|
|
|
if _, err := os.Stat(abs); err == nil {
|
|
|
|
|
|
dep = abs
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
deps = append(deps, dep)
|
|
|
|
|
|
}
|
2015-05-25 14:51:02 +12:00
|
|
|
|
|
2015-05-25 16:13:50 +12:00
|
|
|
|
syms, err := f.DynamicSymbols()
|
2015-04-01 14:57:34 +13:00
|
|
|
|
if err != nil {
|
2024-11-01 14:56:25 -04:00
|
|
|
|
Errorf("cannot read symbols from shared library: %s", libpath)
|
2015-04-01 14:57:34 +13:00
|
|
|
|
return
|
|
|
|
|
|
}
|
2021-02-03 15:07:33 -05:00
|
|
|
|
|
2023-11-29 22:03:22 -08:00
|
|
|
|
symAddr := map[string]uint64{}
|
2015-06-16 13:41:11 +12:00
|
|
|
|
for _, elfsym := range syms {
|
|
|
|
|
|
if elf.ST_TYPE(elfsym.Info) == elf.STT_NOTYPE || elf.ST_TYPE(elfsym.Info) == elf.STT_SECTION {
|
2015-04-01 14:57:34 +13:00
|
|
|
|
continue
|
|
|
|
|
|
}
|
2019-07-13 12:20:43 -07:00
|
|
|
|
|
2021-05-08 00:45:06 +07:00
|
|
|
|
// Symbols whose names start with "type:" are compiler generated,
|
|
|
|
|
|
// so make functions with that prefix internal.
|
2019-07-13 12:20:43 -07:00
|
|
|
|
ver := 0
|
2021-02-03 15:07:33 -05:00
|
|
|
|
symname := elfsym.Name // (unmangled) symbol name
|
2021-05-08 00:45:06 +07:00
|
|
|
|
if elf.ST_TYPE(elfsym.Info) == elf.STT_FUNC && strings.HasPrefix(elfsym.Name, "type:") {
|
2021-09-21 14:35:37 -04:00
|
|
|
|
ver = abiInternalVer
|
2021-04-15 23:05:49 -04:00
|
|
|
|
} else if buildcfg.Experiment.RegabiWrappers && elf.ST_TYPE(elfsym.Info) == elf.STT_FUNC {
|
2021-04-30 17:21:22 -04:00
|
|
|
|
// Demangle the ABI name. Keep in sync with symtab.go:mangleABIName.
|
2021-02-03 15:07:33 -05:00
|
|
|
|
if strings.HasSuffix(elfsym.Name, ".abiinternal") {
|
|
|
|
|
|
ver = sym.SymVerABIInternal
|
|
|
|
|
|
symname = strings.TrimSuffix(elfsym.Name, ".abiinternal")
|
|
|
|
|
|
} else if strings.HasSuffix(elfsym.Name, ".abi0") {
|
|
|
|
|
|
ver = 0
|
|
|
|
|
|
symname = strings.TrimSuffix(elfsym.Name, ".abi0")
|
|
|
|
|
|
}
|
2019-07-13 12:20:43 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-01-23 10:39:13 -05:00
|
|
|
|
l := ctxt.loader
|
2021-02-03 15:07:33 -05:00
|
|
|
|
s := l.LookupOrCreateSym(symname, ver)
|
2019-12-06 20:11:36 -05:00
|
|
|
|
|
2020-01-23 10:39:13 -05:00
|
|
|
|
// Because loadlib above loads all .a files before loading
|
|
|
|
|
|
// any shared libraries, any non-dynimport symbols we find
|
|
|
|
|
|
// that duplicate symbols already loaded should be ignored
|
|
|
|
|
|
// (the symbols from the .a files "win").
|
2020-02-12 17:23:47 -05:00
|
|
|
|
if l.SymType(s) != 0 && l.SymType(s) != sym.SDYNIMPORT {
|
2020-01-23 10:39:13 -05:00
|
|
|
|
continue
|
|
|
|
|
|
}
|
2020-02-12 17:23:47 -05:00
|
|
|
|
su := l.MakeSymbolUpdater(s)
|
2020-01-23 10:39:13 -05:00
|
|
|
|
su.SetType(sym.SDYNIMPORT)
|
|
|
|
|
|
l.SetSymElfType(s, elf.ST_TYPE(elfsym.Info))
|
|
|
|
|
|
su.SetSize(int64(elfsym.Size))
|
|
|
|
|
|
if elfsym.Section != elf.SHN_UNDEF {
|
|
|
|
|
|
// Set .File for the library that actually defines the symbol.
|
2020-04-06 20:56:34 -04:00
|
|
|
|
l.SetSymPkg(s, libpath)
|
2020-01-23 10:39:13 -05:00
|
|
|
|
|
|
|
|
|
|
// The decodetype_* functions in decodetype.go need access to
|
|
|
|
|
|
// the type data.
|
|
|
|
|
|
sname := l.SymName(s)
|
2021-05-08 00:45:06 +07:00
|
|
|
|
if strings.HasPrefix(sname, "type:") && !strings.HasPrefix(sname, "type:.") {
|
2020-01-23 10:39:13 -05:00
|
|
|
|
su.SetData(readelfsymboldata(ctxt, f, &elfsym))
|
2019-12-06 20:11:36 -05:00
|
|
|
|
}
|
2020-01-23 10:39:13 -05:00
|
|
|
|
}
|
2019-12-06 20:11:36 -05:00
|
|
|
|
|
2021-02-03 15:07:33 -05:00
|
|
|
|
if symname != elfsym.Name {
|
|
|
|
|
|
l.SetSymExtname(s, elfsym.Name)
|
|
|
|
|
|
}
|
2023-11-29 22:03:22 -08:00
|
|
|
|
symAddr[elfsym.Name] = elfsym.Value
|
2015-07-02 11:37:51 +12:00
|
|
|
|
}
|
2023-11-29 22:03:22 -08:00
|
|
|
|
|
|
|
|
|
|
// Load relocations.
|
|
|
|
|
|
// We only really need these for grokking the links between type descriptors
|
|
|
|
|
|
// when dynamic linking.
|
|
|
|
|
|
relocTarget := map[uint64]string{}
|
|
|
|
|
|
addends := false
|
|
|
|
|
|
sect := f.SectionByType(elf.SHT_REL)
|
|
|
|
|
|
if sect == nil {
|
|
|
|
|
|
sect = f.SectionByType(elf.SHT_RELA)
|
|
|
|
|
|
if sect == nil {
|
|
|
|
|
|
log.Fatalf("can't find SHT_REL or SHT_RELA section of %s", shlib)
|
|
|
|
|
|
}
|
|
|
|
|
|
addends = true
|
|
|
|
|
|
}
|
|
|
|
|
|
// TODO: Multiple SHT_RELA/SHT_REL sections?
|
|
|
|
|
|
data, err := sect.Data()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
log.Fatalf("can't read relocation section of %s: %v", shlib, err)
|
|
|
|
|
|
}
|
|
|
|
|
|
bo := f.ByteOrder
|
|
|
|
|
|
for len(data) > 0 {
|
|
|
|
|
|
var off, idx uint64
|
|
|
|
|
|
var addend int64
|
|
|
|
|
|
switch f.Class {
|
|
|
|
|
|
case elf.ELFCLASS64:
|
|
|
|
|
|
off = bo.Uint64(data)
|
|
|
|
|
|
info := bo.Uint64(data[8:])
|
|
|
|
|
|
data = data[16:]
|
|
|
|
|
|
if addends {
|
|
|
|
|
|
addend = int64(bo.Uint64(data))
|
|
|
|
|
|
data = data[8:]
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
idx = info >> 32
|
|
|
|
|
|
typ := info & 0xffff
|
|
|
|
|
|
// buildmode=shared is only supported for amd64,arm64,loong64,s390x,ppc64le.
|
|
|
|
|
|
// (List found by looking at the translation of R_ADDR by ../$ARCH/asm.go:elfreloc1)
|
|
|
|
|
|
switch typ {
|
|
|
|
|
|
case uint64(elf.R_X86_64_64):
|
|
|
|
|
|
case uint64(elf.R_AARCH64_ABS64):
|
|
|
|
|
|
case uint64(elf.R_LARCH_64):
|
|
|
|
|
|
case uint64(elf.R_390_64):
|
|
|
|
|
|
case uint64(elf.R_PPC64_ADDR64):
|
|
|
|
|
|
default:
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
case elf.ELFCLASS32:
|
|
|
|
|
|
off = uint64(bo.Uint32(data))
|
|
|
|
|
|
info := bo.Uint32(data[4:])
|
|
|
|
|
|
data = data[8:]
|
|
|
|
|
|
if addends {
|
|
|
|
|
|
addend = int64(int32(bo.Uint32(data)))
|
|
|
|
|
|
data = data[4:]
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
idx = uint64(info >> 8)
|
|
|
|
|
|
typ := info & 0xff
|
|
|
|
|
|
// buildmode=shared is only supported for 386,arm.
|
|
|
|
|
|
switch typ {
|
|
|
|
|
|
case uint32(elf.R_386_32):
|
|
|
|
|
|
case uint32(elf.R_ARM_ABS32):
|
|
|
|
|
|
default:
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
default:
|
|
|
|
|
|
log.Fatalf("unknown bit size %s", f.Class)
|
|
|
|
|
|
}
|
|
|
|
|
|
if addend != 0 {
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
relocTarget[off] = syms[idx-1].Name
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ctxt.Shlibs = append(ctxt.Shlibs, Shlib{Path: libpath, Hash: hash, Deps: deps, File: f, symAddr: symAddr, relocTarget: relocTarget})
|
2015-04-01 14:57:34 +13:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-04-21 18:50:49 -04:00
|
|
|
|
func addsection(ldr *loader.Loader, arch *sys.Arch, seg *sym.Segment, name string, rwx int) *sym.Section {
|
|
|
|
|
|
sect := ldr.NewSection()
|
2015-02-27 22:57:28 -05:00
|
|
|
|
sect.Rwx = uint8(rwx)
|
|
|
|
|
|
sect.Name = name
|
|
|
|
|
|
sect.Seg = seg
|
2017-09-30 21:10:49 +00:00
|
|
|
|
sect.Align = int32(arch.PtrSize) // everything is at least pointer-aligned
|
2017-04-18 21:52:06 +12:00
|
|
|
|
seg.Sections = append(seg.Sections, sect)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
return sect
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func usage() {
|
2015-05-21 13:28:17 -04:00
|
|
|
|
fmt.Fprintf(os.Stderr, "usage: link [options] main.o\n")
|
2017-12-24 16:50:28 +00:00
|
|
|
|
objabi.Flagprint(os.Stderr)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
Exit(2)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-05-11 12:52:37 -04:00
|
|
|
|
type SymbolType int8 // TODO: after genasmsym is gone, maybe rename to plan9typeChar or something
|
2016-09-16 16:22:08 +12:00
|
|
|
|
|
|
|
|
|
|
const (
|
2018-06-01 17:29:59 -03:00
|
|
|
|
// see also https://9p.io/magic/man2html/1/nm
|
2016-09-16 16:22:08 +12:00
|
|
|
|
TextSym SymbolType = 'T'
|
2018-04-06 21:41:06 +01:00
|
|
|
|
DataSym SymbolType = 'D'
|
|
|
|
|
|
BSSSym SymbolType = 'B'
|
|
|
|
|
|
UndefinedSym SymbolType = 'U'
|
|
|
|
|
|
TLSSym SymbolType = 't'
|
|
|
|
|
|
FrameSym SymbolType = 'm'
|
|
|
|
|
|
ParamSym SymbolType = 'p'
|
|
|
|
|
|
AutoSym SymbolType = 'a'
|
2017-12-01 15:23:30 -05:00
|
|
|
|
|
|
|
|
|
|
// Deleted auto (not a real sym, just placeholder for type)
|
|
|
|
|
|
DeletedAutoSym = 'x'
|
2016-09-16 16:22:08 +12:00
|
|
|
|
)
|
|
|
|
|
|
|
2020-07-16 16:18:49 -04:00
|
|
|
|
// defineInternal defines a symbol used internally by the go runtime.
|
|
|
|
|
|
func (ctxt *Link) defineInternal(p string, t sym.SymKind) loader.Sym {
|
|
|
|
|
|
s := ctxt.loader.CreateSymForUpdate(p, 0)
|
2020-04-20 18:42:35 -04:00
|
|
|
|
s.SetType(t)
|
|
|
|
|
|
s.SetSpecial(true)
|
|
|
|
|
|
s.SetLocal(true)
|
2020-06-25 22:22:59 -04:00
|
|
|
|
return s.Sym()
|
2020-04-20 18:42:35 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-07-16 16:18:49 -04:00
|
|
|
|
func (ctxt *Link) xdefine(p string, t sym.SymKind, v int64) loader.Sym {
|
|
|
|
|
|
s := ctxt.defineInternal(p, t)
|
|
|
|
|
|
ctxt.loader.SetSymValue(s, v)
|
|
|
|
|
|
return s
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-05-07 10:06:28 -04:00
|
|
|
|
func datoff(ldr *loader.Loader, s loader.Sym, addr int64) int64 {
|
2015-02-27 22:57:28 -05:00
|
|
|
|
if uint64(addr) >= Segdata.Vaddr {
|
|
|
|
|
|
return int64(uint64(addr) - Segdata.Vaddr + Segdata.Fileoff)
|
|
|
|
|
|
}
|
|
|
|
|
|
if uint64(addr) >= Segtext.Vaddr {
|
|
|
|
|
|
return int64(uint64(addr) - Segtext.Vaddr + Segtext.Fileoff)
|
|
|
|
|
|
}
|
2020-05-07 10:06:28 -04:00
|
|
|
|
ldr.Errorf(s, "invalid datoff %#x", addr)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
return 0
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
|
func Entryvalue(ctxt *Link) int64 {
|
2020-05-06 12:33:36 -04:00
|
|
|
|
a := *flagEntrySymbol
|
|
|
|
|
|
if a[0] >= '0' && a[0] <= '9' {
|
|
|
|
|
|
return atolwhex(a)
|
|
|
|
|
|
}
|
2020-05-07 10:06:28 -04:00
|
|
|
|
ldr := ctxt.loader
|
|
|
|
|
|
s := ldr.Lookup(a, 0)
|
2022-09-13 19:28:58 +10:00
|
|
|
|
if s == 0 {
|
2024-11-01 14:56:25 -04:00
|
|
|
|
Errorf("missing entry symbol %q", a)
|
2022-09-13 19:28:58 +10:00
|
|
|
|
return 0
|
|
|
|
|
|
}
|
2020-05-07 10:06:28 -04:00
|
|
|
|
st := ldr.SymType(s)
|
|
|
|
|
|
if st == 0 {
|
2020-05-06 12:33:36 -04:00
|
|
|
|
return *FlagTextAddr
|
|
|
|
|
|
}
|
2024-10-31 09:49:47 -04:00
|
|
|
|
if !ctxt.IsAIX() && !st.IsText() {
|
2020-05-07 10:06:28 -04:00
|
|
|
|
ldr.Errorf(s, "entry not text")
|
2020-05-06 12:33:36 -04:00
|
|
|
|
}
|
2020-05-07 10:06:28 -04:00
|
|
|
|
return ldr.SymValue(s)
|
2020-05-06 12:33:36 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-08-19 22:40:38 -04:00
|
|
|
|
func (ctxt *Link) callgraph() {
|
2016-08-21 18:34:24 -04:00
|
|
|
|
if !*FlagC {
|
2015-02-27 22:57:28 -05:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-03-27 12:16:07 -04:00
|
|
|
|
ldr := ctxt.loader
|
2020-05-15 18:35:05 -04:00
|
|
|
|
for _, s := range ctxt.Textp {
|
2020-03-27 12:16:07 -04:00
|
|
|
|
relocs := ldr.Relocs(s)
|
2020-03-30 10:04:00 -04:00
|
|
|
|
for i := 0; i < relocs.Count(); i++ {
|
2020-07-29 13:26:50 -04:00
|
|
|
|
r := relocs.At(i)
|
2020-03-27 12:16:07 -04:00
|
|
|
|
rs := r.Sym()
|
|
|
|
|
|
if rs == 0 {
|
2015-02-27 22:57:28 -05:00
|
|
|
|
continue
|
|
|
|
|
|
}
|
2024-10-31 09:49:47 -04:00
|
|
|
|
if r.Type().IsDirectCall() && ldr.SymType(rs).IsText() {
|
2020-03-27 12:16:07 -04:00
|
|
|
|
ctxt.Logf("%s calls %s\n", ldr.SymName(s), ldr.SymName(rs))
|
2015-02-27 22:57:28 -05:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func Rnd(v int64, r int64) int64 {
|
|
|
|
|
|
if r <= 0 {
|
|
|
|
|
|
return v
|
|
|
|
|
|
}
|
|
|
|
|
|
v += r - 1
|
2015-03-02 12:35:15 -05:00
|
|
|
|
c := v % r
|
2015-02-27 22:57:28 -05:00
|
|
|
|
if c < 0 {
|
|
|
|
|
|
c += r
|
|
|
|
|
|
}
|
|
|
|
|
|
v -= c
|
|
|
|
|
|
return v
|
|
|
|
|
|
}
|
2016-04-08 20:44:56 +10:00
|
|
|
|
|
|
|
|
|
|
func bgetc(r *bio.Reader) int {
|
|
|
|
|
|
c, err := r.ReadByte()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
if err != io.EOF {
|
|
|
|
|
|
log.Fatalf("reading input: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
return -1
|
|
|
|
|
|
}
|
|
|
|
|
|
return int(c)
|
|
|
|
|
|
}
|
2016-09-14 14:47:12 -04:00
|
|
|
|
|
|
|
|
|
|
type markKind uint8 // for postorder traversal
|
|
|
|
|
|
const (
|
2018-04-06 21:41:06 +01:00
|
|
|
|
_ markKind = iota
|
2016-09-14 14:47:12 -04:00
|
|
|
|
visiting
|
|
|
|
|
|
visited
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2017-10-04 18:13:35 -04:00
|
|
|
|
func postorder(libs []*sym.Library) []*sym.Library {
|
|
|
|
|
|
order := make([]*sym.Library, 0, len(libs)) // hold the result
|
|
|
|
|
|
mark := make(map[*sym.Library]markKind, len(libs))
|
2016-09-14 14:47:12 -04:00
|
|
|
|
for _, lib := range libs {
|
|
|
|
|
|
dfs(lib, mark, &order)
|
|
|
|
|
|
}
|
|
|
|
|
|
return order
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-10-04 18:13:35 -04:00
|
|
|
|
func dfs(lib *sym.Library, mark map[*sym.Library]markKind, order *[]*sym.Library) {
|
2016-09-14 14:47:12 -04:00
|
|
|
|
if mark[lib] == visited {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
if mark[lib] == visiting {
|
|
|
|
|
|
panic("found import cycle while visiting " + lib.Pkg)
|
|
|
|
|
|
}
|
|
|
|
|
|
mark[lib] = visiting
|
2017-10-04 18:13:35 -04:00
|
|
|
|
for _, i := range lib.Imports {
|
2016-09-14 14:47:12 -04:00
|
|
|
|
dfs(i, mark, order)
|
|
|
|
|
|
}
|
|
|
|
|
|
mark[lib] = visited
|
|
|
|
|
|
*order = append(*order, lib)
|
|
|
|
|
|
}
|
2019-09-17 16:14:37 -04:00
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
|
func ElfSymForReloc(ctxt *Link, s loader.Sym) int32 {
|
2020-04-28 10:51:40 -04:00
|
|
|
|
// If putelfsym created a local version of this symbol, use that in all
|
|
|
|
|
|
// relocations.
|
2020-05-07 10:06:28 -04:00
|
|
|
|
les := ctxt.loader.SymLocalElfSym(s)
|
2020-04-28 10:51:40 -04:00
|
|
|
|
if les != 0 {
|
|
|
|
|
|
return les
|
|
|
|
|
|
} else {
|
2020-05-07 10:06:28 -04:00
|
|
|
|
return ctxt.loader.SymElfSym(s)
|
2020-04-28 10:51:40 -04:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2020-05-26 13:40:12 -04:00
|
|
|
|
|
|
|
|
|
|
func AddGotSym(target *Target, ldr *loader.Loader, syms *ArchSyms, s loader.Sym, elfRelocTyp uint32) {
|
|
|
|
|
|
if ldr.SymGot(s) >= 0 {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Adddynsym(ldr, target, syms, s)
|
|
|
|
|
|
got := ldr.MakeSymbolUpdater(syms.GOT)
|
|
|
|
|
|
ldr.SetGot(s, int32(got.Size()))
|
|
|
|
|
|
got.AddUint(target.Arch, 0)
|
|
|
|
|
|
|
|
|
|
|
|
if target.IsElf() {
|
|
|
|
|
|
if target.Arch.PtrSize == 8 {
|
|
|
|
|
|
rela := ldr.MakeSymbolUpdater(syms.Rela)
|
|
|
|
|
|
rela.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
|
2020-10-27 14:18:13 +08:00
|
|
|
|
rela.AddUint64(target.Arch, elf.R_INFO(uint32(ldr.SymDynid(s)), elfRelocTyp))
|
2020-05-26 13:40:12 -04:00
|
|
|
|
rela.AddUint64(target.Arch, 0)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
rel := ldr.MakeSymbolUpdater(syms.Rel)
|
|
|
|
|
|
rel.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
|
2020-10-27 14:18:13 +08:00
|
|
|
|
rel.AddUint32(target.Arch, elf.R_INFO32(uint32(ldr.SymDynid(s)), elfRelocTyp))
|
2020-05-26 13:40:12 -04:00
|
|
|
|
}
|
|
|
|
|
|
} else if target.IsDarwin() {
|
|
|
|
|
|
leg := ldr.MakeSymbolUpdater(syms.LinkEditGOT)
|
|
|
|
|
|
leg.AddUint32(target.Arch, uint32(ldr.SymDynid(s)))
|
2020-10-11 15:48:22 -04:00
|
|
|
|
if target.IsPIE() && target.IsInternal() {
|
|
|
|
|
|
// Mach-O relocations are a royal pain to lay out.
|
|
|
|
|
|
// They use a compact stateful bytecode representation.
|
|
|
|
|
|
// Here we record what are needed and encode them later.
|
|
|
|
|
|
MachoAddBind(int64(ldr.SymGot(s)), s)
|
|
|
|
|
|
}
|
2020-05-26 13:40:12 -04:00
|
|
|
|
} else {
|
|
|
|
|
|
ldr.Errorf(s, "addgotsym: unsupported binary format")
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-11-01 11:08:00 -04:00
|
|
|
|
|
|
|
|
|
|
var hostobjcounter int
|
|
|
|
|
|
|
|
|
|
|
|
// captureHostObj writes out the content of a host object (pulled from
|
|
|
|
|
|
// an archive or loaded from a *.o file directly) to a directory
|
|
|
|
|
|
// specified via the linker's "-capturehostobjs" debugging flag. This
|
|
|
|
|
|
// is intended to make it easier for a developer to inspect the actual
|
|
|
|
|
|
// object feeding into "CGO internal" link step.
|
|
|
|
|
|
func captureHostObj(h *Hostobj) {
|
|
|
|
|
|
// Form paths for info file and obj file.
|
|
|
|
|
|
ofile := fmt.Sprintf("captured-obj-%d.o", hostobjcounter)
|
|
|
|
|
|
ifile := fmt.Sprintf("captured-obj-%d.txt", hostobjcounter)
|
|
|
|
|
|
hostobjcounter++
|
|
|
|
|
|
opath := filepath.Join(*flagCaptureHostObjs, ofile)
|
|
|
|
|
|
ipath := filepath.Join(*flagCaptureHostObjs, ifile)
|
|
|
|
|
|
|
|
|
|
|
|
// Write the info file.
|
|
|
|
|
|
info := fmt.Sprintf("pkg: %s\npn: %s\nfile: %s\noff: %d\nlen: %d\n",
|
|
|
|
|
|
h.pkg, h.pn, h.file, h.off, h.length)
|
|
|
|
|
|
if err := os.WriteFile(ipath, []byte(info), 0666); err != nil {
|
|
|
|
|
|
log.Fatalf("error writing captured host obj info %s: %v", ipath, err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
readObjData := func() []byte {
|
|
|
|
|
|
inf, err := os.Open(h.file)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
log.Fatalf("capturing host obj: open failed on %s: %v", h.pn, err)
|
|
|
|
|
|
}
|
2024-04-06 06:28:34 +00:00
|
|
|
|
defer inf.Close()
|
2022-11-01 11:08:00 -04:00
|
|
|
|
res := make([]byte, h.length)
|
|
|
|
|
|
if n, err := inf.ReadAt(res, h.off); err != nil || n != int(h.length) {
|
|
|
|
|
|
log.Fatalf("capturing host obj: readat failed on %s: %v", h.pn, err)
|
|
|
|
|
|
}
|
|
|
|
|
|
return res
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Write the object file.
|
|
|
|
|
|
if err := os.WriteFile(opath, readObjData(), 0666); err != nil {
|
|
|
|
|
|
log.Fatalf("error writing captured host object %s: %v", opath, err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fmt.Fprintf(os.Stderr, "link: info: captured host object %s to %s\n",
|
|
|
|
|
|
h.file, opath)
|
|
|
|
|
|
}
|
2023-03-28 09:17:27 -04:00
|
|
|
|
|
|
|
|
|
|
// findExtLinkTool invokes the external linker CC with --print-prog-name
|
|
|
|
|
|
// passing the name of the tool we're interested in, such as "strip",
|
|
|
|
|
|
// "ar", or "dsymutil", and returns the path passed back from the command.
|
|
|
|
|
|
func (ctxt *Link) findExtLinkTool(toolname string) string {
|
|
|
|
|
|
var cc []string
|
|
|
|
|
|
cc = append(cc, ctxt.extld()...)
|
|
|
|
|
|
cc = append(cc, hostlinkArchArgs(ctxt.Arch)...)
|
|
|
|
|
|
cc = append(cc, "--print-prog-name", toolname)
|
|
|
|
|
|
out, err := exec.Command(cc[0], cc[1:]...).CombinedOutput()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
Exitf("%s: finding %s failed: %v\n%s", os.Args[0], toolname, err, out)
|
|
|
|
|
|
}
|
2024-06-21 16:44:44 -07:00
|
|
|
|
cmdpath := strings.TrimRight(string(out), "\r\n")
|
2023-03-28 09:17:27 -04:00
|
|
|
|
return cmdpath
|
|
|
|
|
|
}
|
cmd/link: support MSVC clang
Currently on Windows, for cgo, we support MinGW-based C toolchain,
that is, with a -windows-gnu target. This CL makes it work with
clang with a -windows-msvc target. The LLVM toolchain bundled in
MSVC (https://learn.microsoft.com/en-us/cpp/build/clang-support-msbuild)
is such an example.
Currently it is expecting lld-link as the C linker, which is also
bundled in MSVC, can be requested with -fuse-ld=lld, but is not
the default.
This is the first step, which makes it generate a working cgo
binary. There are still more work to do, e.g. there are some
linker warnings, and the binary doesn't have symbol table.
all.bat doesn't pass with this setting.
Change-Id: I54d33f7dd5f5eeeafa0735cd52f4127fe4865636
Reviewed-on: https://go-review.googlesource.com/c/go/+/703055
Reviewed-by: Than McIntosh <thanm@golang.org>
Reviewed-by: Florian Zenker <floriank@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2025-09-11 17:42:30 -04:00
|
|
|
|
|
|
|
|
|
|
// isMSVC reports whether the C toolchain is clang with a -msvc target,
|
|
|
|
|
|
// e.g. the clang bundled in MSVC.
|
|
|
|
|
|
func (ctxt *Link) isMSVC() bool {
|
|
|
|
|
|
extld := ctxt.extld()
|
|
|
|
|
|
name, args := extld[0], extld[1:]
|
|
|
|
|
|
args = append(args, trimLinkerArgv(flagExtldflags)...)
|
|
|
|
|
|
args = append(args, "--version")
|
|
|
|
|
|
cmd := exec.Command(name, args...)
|
|
|
|
|
|
if out, err := cmd.CombinedOutput(); err == nil {
|
|
|
|
|
|
if bytes.Contains(out, []byte("-msvc\n")) || bytes.Contains(out, []byte("-msvc\r")) {
|
|
|
|
|
|
return true
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|