"encoding/base64"
"encoding/binary"
"fmt"
+ "internal/buildcfg"
exec "internal/execabs"
"io"
"io/ioutil"
"os"
"path/filepath"
"runtime"
- "sort"
"strings"
"sync"
)
Dynamic loader.Sym
DynSym loader.Sym
DynStr loader.Sym
+
+ unreachableMethod loader.Sym
}
// mkArchSym is a helper for setArchSyms, to set up a special symbol.
ctxt.mkArchSym(".dynamic", 0, &ctxt.Dynamic)
ctxt.mkArchSym(".dynsym", 0, &ctxt.DynSym)
ctxt.mkArchSym(".dynstr", 0, &ctxt.DynStr)
+ ctxt.mkArchSym("runtime.unreachableMethod", sym.SymVerABIInternal, &ctxt.unreachableMethod)
if ctxt.IsPPC64() {
ctxt.mkArchSym("TOC", 0, &ctxt.TOC)
}
type Arch struct {
- Funcalign int
- Maxalign int
- Minalign int
- Dwarfregsp int
- Dwarfreglr int
+ 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
+
Androiddynld string
Linuxdynld string
Freebsddynld string
// are padded with zeros.
CodePad []byte
- // Set to true to write all text blocks in with CodeBlkWrite
- WriteTextBlocks bool
-
// Plan 9 variables.
Plan9Magic uint32
Plan9_64Bit bool
// to-be-relocated data item (from sym.P). Return is an updated
// offset value.
Archrelocvariant func(target *Target, ldr *loader.Loader, rel loader.Reloc,
- rv sym.RelocVariant, sym loader.Sym, offset int64) (relocatedOffset int64)
+ rv sym.RelocVariant, sym loader.Sym, offset int64, data []byte) (relocatedOffset int64)
// Generate a trampoline for a call from s to rs if necessary. ri is
// index of the relocation.
suffix = "msan"
}
- Lflag(ctxt, filepath.Join(objabi.GOROOT, "pkg", fmt.Sprintf("%s_%s%s%s", objabi.GOOS, objabi.GOARCH, suffixsep, suffix)))
+ Lflag(ctxt, filepath.Join(buildcfg.GOROOT, "pkg", fmt.Sprintf("%s_%s%s%s", buildcfg.GOOS, buildcfg.GOARCH, suffixsep, suffix)))
mayberemoveoutfile()
if *flagEntrySymbol == "" {
switch ctxt.BuildMode {
case BuildModeCShared, BuildModeCArchive:
- *flagEntrySymbol = fmt.Sprintf("_rt0_%s_%s_lib", objabi.GOARCH, objabi.GOOS)
+ *flagEntrySymbol = fmt.Sprintf("_rt0_%s_%s_lib", buildcfg.GOARCH, buildcfg.GOOS)
case BuildModeExe, BuildModePIE:
- *flagEntrySymbol = fmt.Sprintf("_rt0_%s_%s", objabi.GOARCH, objabi.GOOS)
+ *flagEntrySymbol = fmt.Sprintf("_rt0_%s_%s", buildcfg.GOARCH, buildcfg.GOOS)
case BuildModeShared, BuildModePlugin:
// No *flagEntrySymbol for -buildmode=shared and plugin
default:
default:
log.Fatalf("invalid -strictdups flag value %d", *FlagStrictDups)
}
- if !*flagAbiWrap || ctxt.linkShared {
+ if !buildcfg.Experiment.RegabiWrappers {
// Use ABI aliases if ABI wrappers are not used.
- // TODO: for now we still use ABI aliases in shared linkage, even if
- // the wrapper is enabled.
flags |= loader.FlagUseABIAlias
}
elfsetstring1 := func(str string, off int) { elfsetstring(ctxt, 0, str, off) }
return ctxt.loader.SymName(s)
}
- ctxt.cgo_export_static = make(map[string]bool)
- ctxt.cgo_export_dynamic = make(map[string]bool)
-
// ctxt.Library grows during the loop, so not a range loop.
i := 0
for ; i < len(ctxt.Library); i++ {
// up symbol by name may not get expected result.
iscgo = ctxt.LibraryByPkg["runtime/cgo"] != nil
- ctxt.canUsePlugins = ctxt.LibraryByPkg["plugin"] != nil
+
+ // 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
// We now have enough information to determine the link mode.
determineLinkMode(ctxt)
- if ctxt.LinkMode == LinkExternal && !iscgo && !(objabi.GOOS == "darwin" && ctxt.BuildMode != BuildModePlugin && ctxt.Arch.Family == sys.AMD64) {
+ if ctxt.LinkMode == LinkExternal && !iscgo && !(buildcfg.GOOS == "darwin" && ctxt.BuildMode != BuildModePlugin && ctxt.Arch.Family == sys.AMD64) {
// This indicates a user requested -linkmode=external.
// The startup code uses an import of runtime/cgo to decide
// whether to initialize the TLS. So give it one. This could
if ctxt.BuildMode == BuildModeShared || ctxt.linkShared {
Exitf("cannot implicitly include runtime/cgo in a shared library")
}
- loadobjfile(ctxt, lib)
+ for ; i < len(ctxt.Library); i++ {
+ lib := ctxt.Library[i]
+ if lib.Shlib == "" {
+ loadobjfile(ctxt, lib)
+ }
+ }
}
}
// errors - see if we can find libcompiler_rt.a instead.
*flagLibGCC = ctxt.findLibPathCmd("--print-file-name=libcompiler_rt.a", "libcompiler_rt")
}
- if *flagLibGCC != "none" {
- hostArchive(ctxt, *flagLibGCC)
- }
if ctxt.HeadType == objabi.Hwindows {
if p := ctxt.findLibPath("libmingwex.a"); p != "none" {
hostArchive(ctxt, p)
libmsvcrt.a libm.a
*/
}
+ if *flagLibGCC != "none" {
+ hostArchive(ctxt, *flagLibGCC)
+ }
}
}
strictDupMsgCount = ctxt.loader.NStrictDupMsgs()
}
-// setupdynexp constructs ctxt.dynexp, a list of loader.Sym.
-func setupdynexp(ctxt *Link) {
- dynexpMap := ctxt.cgo_export_dynamic
- if ctxt.LinkMode == LinkExternal {
- dynexpMap = ctxt.cgo_export_static
- }
- d := make([]loader.Sym, 0, len(dynexpMap))
- for exp := range dynexpMap {
- s := ctxt.loader.LookupOrCreateSym(exp, 0)
- d = append(d, s)
- // sanity check
- if !ctxt.loader.AttrReachable(s) {
- panic("dynexp entry not reachable")
- }
- }
- sort.Slice(d, func(i, j int) bool {
- return ctxt.loader.SymName(d[i]) < ctxt.loader.SymName(d[j])
- })
-
- // Resolve ABI aliases in the list of cgo-exported functions.
- // This is necessary because we load the ABI0 symbol for all
- // cgo exports.
- for i, s := range d {
- if ctxt.loader.SymType(s) != sym.SABIALIAS {
- continue
- }
- t := ctxt.loader.ResolveABIAlias(s)
- ctxt.loader.CopyAttributes(s, t)
- ctxt.loader.SetSymExtname(t, ctxt.loader.SymExtname(s))
- d[i] = t
- }
- ctxt.dynexp = d
-
- ctxt.cgo_export_static = nil
- ctxt.cgo_export_dynamic = nil
-}
-
// 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 {
- setCgoAttr(ctxt, ctxt.loader.LookupOrCreateSym, d.file, d.pkg, d.directives, hostObjSyms)
+ setCgoAttr(ctxt, d.file, d.pkg, d.directives, hostObjSyms)
}
ctxt.cgodata = nil
}
}
- if ctxt.LinkMode == LinkExternal && ctxt.Arch.Family == sys.PPC64 && objabi.GOOS != "aix" {
+ if ctxt.LinkMode == LinkExternal && ctxt.Arch.Family == sys.PPC64 && buildcfg.GOOS != "aix" {
toc := ctxt.loader.LookupOrCreateSym(".TOC.", 0)
sb := ctxt.loader.MakeSymbolUpdater(toc)
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.
- if objabi.GOOS != "android" {
+ if buildcfg.GOOS != "android" {
tlsg := ctxt.loader.LookupOrCreateSym("runtime.tlsg", 0)
sb := ctxt.loader.MakeSymbolUpdater(tlsg)
sb := ctxt.loader.MakeSymbolUpdater(goarm)
sb.SetType(sym.SDATA)
sb.SetSize(0)
- sb.AddUint8(uint8(objabi.GOARM))
+ sb.AddUint8(uint8(buildcfg.GOARM))
+ }
+
+ // Set runtime.disableMemoryProfiling bool if
+ // runtime.MemProfile is not retained in the binary after
+ // deadcode (and we're not dynamically linking).
+ memProfile := ctxt.loader.Lookup("runtime.MemProfile", sym.SymVerABIInternal)
+ if memProfile != 0 && !ctxt.loader.AttrReachable(memProfile) && !ctxt.DynlinkingGo() {
+ memProfSym := ctxt.loader.LookupOrCreateSym("runtime.disableMemoryProfiling", 0)
+ sb := ctxt.loader.MakeSymbolUpdater(memProfSym)
+ sb.SetType(sym.SDATA)
+ sb.SetSize(0)
+ sb.AddUint8(1) // true bool
}
} else {
// If OTOH the module does not contain the runtime package,
// -headerpad is incompatible with -fembed-bitcode.
argv = append(argv, "-Wl,-headerpad,1144")
}
- if ctxt.DynlinkingGo() && objabi.GOOS != "ios" {
+ if ctxt.DynlinkingGo() && buildcfg.GOOS != "ios" {
// -flat_namespace is deprecated on iOS.
// It is useful for supporting plugins. We don't support plugins on iOS.
argv = append(argv, "-Wl,-flat_namespace")
if ctxt.HeadType == objabi.Hdarwin {
argv = append(argv, "-dynamiclib")
} else {
- // ELF.
- argv = append(argv, "-Wl,-Bsymbolic")
if ctxt.UseRelro() {
argv = append(argv, "-Wl,-z,relro")
}
// Pass -z nodelete to mark the shared library as
// non-closeable: a dlclose will do nothing.
argv = append(argv, "-Wl,-z,nodelete")
+ // Only pass Bsymbolic on non-Windows.
+ argv = append(argv, "-Wl,-Bsymbolic")
}
}
case BuildModeShared:
// from the beginning of the section (like sym.STYPE).
argv = append(argv, "-Wl,-znocopyreloc")
- if objabi.GOOS == "android" {
+ if buildcfg.GOOS == "android" {
// Use lld to avoid errors from default linker (issue #38838)
altLinker = "lld"
}
- if ctxt.Arch.InFamily(sys.ARM, sys.ARM64) && objabi.GOOS == "linux" {
+ if ctxt.Arch.InFamily(sys.ARM, sys.ARM64) && buildcfg.GOOS == "linux" {
// On ARM, the GNU linker will generate COPY relocations
// even with -znocopyreloc set.
// https://sourceware.org/bugzilla/show_bug.cgi?id=19962
}
}
}
- if ctxt.Arch.Family == sys.ARM64 && objabi.GOOS == "freebsd" {
+ if ctxt.Arch.Family == sys.ARM64 && buildcfg.GOOS == "freebsd" {
// Switch to ld.bfd on freebsd/arm64.
altLinker = "bfd"
// only want to do this when producing a Windows output file
// on a Windows host.
outopt := *flagOutfile
- if objabi.GOOS == "windows" && runtime.GOOS == "windows" && filepath.Ext(outopt) == "" {
+ if buildcfg.GOOS == "windows" && runtime.GOOS == "windows" && filepath.Ext(outopt) == "" {
outopt += "."
}
argv = append(argv, "-o")
argv = append(argv, fmt.Sprintf("-Wl,-rpath,%s", rpath.val))
}
+ 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))
+ }
+
// Force global symbols to be exported for dlopen, etc.
if ctxt.IsELF {
argv = append(argv, "-rdynamic")
argv = append(argv, "-Wl,-bE:"+fileName)
}
- if strings.Contains(argv[0], "clang") {
- argv = append(argv, "-Qunused-arguments")
+ const unusedArguments = "-Qunused-arguments"
+ if linkerFlagSupported(ctxt.Arch, argv[0], altLinker, unusedArguments) {
+ argv = append(argv, unusedArguments)
}
const compressDWARF = "-Wl,--compress-debug-sections=zlib-gnu"
// 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
- // only adding -rdynamic later, so that -*extldflags
+ // only adding -rdynamic later, so that -extldflags
// can override -rdynamic without using -static.
+ // Similarly for -Wl,--dynamic-linker.
checkStatic := func(arg string) {
if ctxt.IsELF && arg == "-static" {
for i := range argv {
- if argv[i] == "-rdynamic" {
+ if argv[i] == "-rdynamic" || strings.HasPrefix(argv[i], "-Wl,--dynamic-linker,") {
argv[i] = "-static"
}
}
case sys.I386:
return []string{"-m32"}
case sys.AMD64:
- if objabi.GOOS == "darwin" {
+ if buildcfg.GOOS == "darwin" {
return []string{"-arch", "x86_64", "-m64"}
}
return []string{"-m64"}
case sys.ARM:
return []string{"-marm"}
case sys.ARM64:
- if objabi.GOOS == "darwin" {
+ if buildcfg.GOOS == "darwin" {
return []string{"-arch", "arm64"}
}
case sys.MIPS64:
case sys.MIPS:
return []string{"-mabi=32"}
case sys.PPC64:
- if objabi.GOOS == "aix" {
+ if buildcfg.GOOS == "aix" {
return []string{"-maix64"}
} else {
return []string{"-m64"}
return nil
}
+var wantHdr = objabi.HeaderString()
+
// 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
// it is a Go object, it returns nil.
return ldhostobj(ldmacho, ctxt.HeadType, f, pkg, length, pn, file)
}
- if /* x86 */ c1 == 0x4c && c2 == 0x01 || /* x86_64 */ c1 == 0x64 && c2 == 0x86 || /* armv7 */ c1 == 0xc4 && c2 == 0x01 {
+ switch c1<<8 | c2 {
+ case 0x4c01, // 386
+ 0x6486, // amd64
+ 0xc401, // arm
+ 0x64aa: // arm64
ldpe := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
textp, rsrc, err := loadpe.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn)
if err != nil {
return nil
}
- Errorf(nil, "%s: not an object file", pn)
+ Errorf(nil, "%s: not an object file: @%d %02x%02x%02x%02x", pn, start, c1, c2, c3, c4)
return nil
}
// First, check that the basic GOOS, GOARCH, and Version match.
- t := fmt.Sprintf("%s %s %s ", objabi.GOOS, objabi.GOARCH, objabi.Version)
-
- line = strings.TrimRight(line, "\n")
- if !strings.HasPrefix(line[10:]+" ", t) && !*flagF {
- Errorf(nil, "%s: object is [%s] expected [%s]", pn, line[10:], t)
- return nil
- }
-
- // Second, check that longer lines match each other exactly,
- // so that the Go compiler and write additional information
- // that must be the same from run to run.
- if len(line) >= len(t)+10 {
- if theline == "" {
- theline = line[10:]
- } else if theline != line[10:] {
- Errorf(nil, "%s: object is [%s] expected [%s]", pn, line[10:], theline)
- return nil
- }
+ if line != wantHdr {
+ Errorf(nil, "%s: linked object header mismatch:\nhave %q\nwant %q\n", pn, line, wantHdr)
}
// Skip over exports and other info -- ends with \n!\n.
return
}
- // collect text symbol ABI versions.
- symabi := make(map[string]int) // map (unmangled) symbol name to version
- if *flagAbiWrap {
- for _, elfsym := range syms {
- if elf.ST_TYPE(elfsym.Info) != elf.STT_FUNC {
- continue
- }
- // Demangle the name. Keep in sync with symtab.go:putelfsym.
- if strings.HasSuffix(elfsym.Name, ".abiinternal") {
- // ABIInternal symbol has mangled name, so the primary symbol is ABI0.
- symabi[strings.TrimSuffix(elfsym.Name, ".abiinternal")] = 0
- }
- if strings.HasSuffix(elfsym.Name, ".abi0") {
- // ABI0 symbol has mangled name, so the primary symbol is ABIInternal.
- symabi[strings.TrimSuffix(elfsym.Name, ".abi0")] = sym.SymVerABIInternal
- }
- }
- }
-
for _, elfsym := range syms {
if elf.ST_TYPE(elfsym.Info) == elf.STT_NOTYPE || elf.ST_TYPE(elfsym.Info) == elf.STT_SECTION {
continue
symname := elfsym.Name // (unmangled) symbol name
if elf.ST_TYPE(elfsym.Info) == elf.STT_FUNC && strings.HasPrefix(elfsym.Name, "type.") {
ver = sym.SymVerABIInternal
- } else if *flagAbiWrap && elf.ST_TYPE(elfsym.Info) == elf.STT_FUNC {
+ } else if buildcfg.Experiment.RegabiWrappers && elf.ST_TYPE(elfsym.Info) == elf.STT_FUNC {
+ // Demangle the ABI name. Keep in sync with symtab.go:mangleABIName.
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")
- } else if abi, ok := symabi[elfsym.Name]; ok {
- ver = abi
}
}
l.SetSymExtname(s, elfsym.Name)
}
- // For function symbols, we don't know what ABI is
- // available, so alias it under both ABIs.
- //
- // TODO(austin): This is almost certainly wrong once
- // the ABIs are actually different. We might have to
- // mangle Go function names in the .so to include the
- // ABI.
- if elf.ST_TYPE(elfsym.Info) == elf.STT_FUNC && ver == 0 {
- if *flagAbiWrap {
- if _, ok := symabi[symname]; ok {
- continue // only use alias for functions w/o ABI wrappers
- }
- }
+ // For function symbols, if ABI wrappers are not used, we don't
+ // know what ABI is available, so alias it under both ABIs.
+ if !buildcfg.Experiment.RegabiWrappers && elf.ST_TYPE(elfsym.Info) == elf.STT_FUNC && ver == 0 {
alias := ctxt.loader.LookupOrCreateSym(symname, sym.SymVerABIInternal)
if l.SymType(alias) != 0 {
continue
// of non-splitting functions.
var ch chain
ch.limit = objabi.StackLimit - callsize(ctxt)
- if objabi.GOARCH == "arm64" {
+ if buildcfg.GOARCH == "arm64" {
// need extra 8 bytes below SP to save FP
ch.limit -= 8
}
ctxt := sc.ctxt
var name string
if ch.sym != 0 {
- name = ldr.SymName(ch.sym)
+ name = fmt.Sprintf("%s<%d>", ldr.SymName(ch.sym), ldr.SymVersion(ch.sym))
if ldr.IsNoSplit(ch.sym) {
name += " (nosplit)"
}