"cmd/internal/sys"
"cmd/link/internal/ld"
"fmt"
- "log"
)
// Reading object files.
}
func archinit(ctxt *ld.Link) {
- // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
- // Go was built; see ../../make.bash.
- if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" {
- ld.Linkmode = ld.LinkInternal
- }
-
- switch ld.Headtype {
- default:
- if ld.Linkmode == ld.LinkAuto {
- ld.Linkmode = ld.LinkInternal
- }
- if ld.Linkmode == ld.LinkExternal && obj.Getgoextlinkenabled() != "1" {
- log.Fatalf("cannot use -linkmode=external with -H %v", ld.Headtype)
- }
-
- case obj.Hdarwin,
- obj.Hdragonfly,
- obj.Hfreebsd,
- obj.Hlinux,
- obj.Hnacl,
- obj.Hnetbsd,
- obj.Hopenbsd,
- obj.Hsolaris,
- obj.Hwindows,
- obj.Hwindowsgui:
- break
- }
-
switch ld.Headtype {
default:
ld.Exitf("unknown -H option: %v", ld.Headtype)
"cmd/internal/sys"
"cmd/link/internal/ld"
"fmt"
- "log"
)
// Reading object files.
}
func archinit(ctxt *ld.Link) {
- // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
- // Go was built; see ../../make.bash.
- if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" {
- ld.Linkmode = ld.LinkInternal
- }
-
- switch ld.Headtype {
- default:
- if ld.Linkmode == ld.LinkAuto {
- ld.Linkmode = ld.LinkInternal
- }
- if ld.Linkmode == ld.LinkExternal && obj.Getgoextlinkenabled() != "1" {
- log.Fatalf("cannot use -linkmode=external with -H %v", ld.Headtype)
- }
-
- case obj.Hlinux,
- obj.Hfreebsd,
- obj.Hnacl,
- obj.Hdarwin:
- break
- }
-
switch ld.Headtype {
default:
ld.Exitf("unknown -H option: %v", ld.Headtype)
"cmd/internal/sys"
"cmd/link/internal/ld"
"fmt"
- "log"
)
// Reading object files.
}
func archinit(ctxt *ld.Link) {
- // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
- // Go was built; see ../../make.bash.
- if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" {
- ld.Linkmode = ld.LinkInternal
- }
-
- // Darwin/arm64 only supports external linking
- if ld.Headtype == obj.Hdarwin {
- ld.Linkmode = ld.LinkExternal
- }
-
- switch ld.Headtype {
- default:
- if ld.Linkmode == ld.LinkAuto {
- ld.Linkmode = ld.LinkInternal
- }
- if ld.Linkmode == ld.LinkExternal && obj.Getgoextlinkenabled() != "1" {
- log.Fatalf("cannot use -linkmode=external with -H %v", ld.Headtype)
- }
- case obj.Hlinux, obj.Hdarwin:
- break
- }
-
switch ld.Headtype {
default:
ld.Exitf("unknown -H option: %v", ld.Headtype)
--- /dev/null
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ld
+
+import (
+ "cmd/internal/obj"
+ "cmd/internal/sys"
+ "fmt"
+ "log"
+)
+
+var (
+ Linkmode LinkMode
+ Buildmode BuildMode
+)
+
+// A BuildMode indicates the sort of object we are building.
+//
+// Possible build modes are the same as those for the -buildmode flag
+// in cmd/go, and are documented in 'go help buildmode'.
+type BuildMode uint8
+
+const (
+ BuildmodeUnset BuildMode = iota
+ BuildmodeExe
+ BuildmodePIE
+ BuildmodeCArchive
+ BuildmodeCShared
+ BuildmodeShared
+ BuildmodePlugin
+)
+
+func (mode *BuildMode) Set(s string) error {
+ badmode := func() error {
+ return fmt.Errorf("buildmode %s not supported on %s/%s", s, obj.GOOS, obj.GOARCH)
+ }
+ switch s {
+ default:
+ return fmt.Errorf("invalid buildmode: %q", s)
+ case "exe":
+ *mode = BuildmodeExe
+ case "pie":
+ switch obj.GOOS {
+ case "android", "linux":
+ default:
+ return badmode()
+ }
+ *mode = BuildmodePIE
+ case "c-archive":
+ switch obj.GOOS {
+ case "darwin", "linux":
+ case "windows":
+ switch obj.GOARCH {
+ case "amd64", "386":
+ default:
+ return badmode()
+ }
+ default:
+ return badmode()
+ }
+ *mode = BuildmodeCArchive
+ case "c-shared":
+ switch obj.GOARCH {
+ case "386", "amd64", "arm", "arm64":
+ default:
+ return badmode()
+ }
+ *mode = BuildmodeCShared
+ case "shared":
+ switch obj.GOOS {
+ case "linux":
+ switch obj.GOARCH {
+ case "386", "amd64", "arm", "arm64", "ppc64le", "s390x":
+ default:
+ return badmode()
+ }
+ default:
+ return badmode()
+ }
+ *mode = BuildmodeShared
+ case "plugin":
+ switch obj.GOOS {
+ case "linux":
+ switch obj.GOARCH {
+ case "386", "amd64", "arm", "arm64":
+ default:
+ return badmode()
+ }
+ default:
+ return badmode()
+ }
+ *mode = BuildmodePlugin
+ }
+ return nil
+}
+
+func (mode *BuildMode) String() string {
+ switch *mode {
+ case BuildmodeUnset:
+ return "" // avoid showing a default in usage message
+ case BuildmodeExe:
+ return "exe"
+ case BuildmodePIE:
+ return "pie"
+ case BuildmodeCArchive:
+ return "c-archive"
+ case BuildmodeCShared:
+ return "c-shared"
+ case BuildmodeShared:
+ return "shared"
+ case BuildmodePlugin:
+ return "plugin"
+ }
+ return fmt.Sprintf("BuildMode(%d)", uint8(*mode))
+}
+
+// LinkMode indicates whether an external linker is used for the final link.
+type LinkMode uint8
+
+const (
+ LinkAuto LinkMode = iota
+ LinkInternal
+ LinkExternal
+)
+
+func (mode *LinkMode) Set(s string) error {
+ switch s {
+ default:
+ return fmt.Errorf("invalid linkmode: %q", s)
+ case "auto":
+ *mode = LinkAuto
+ case "internal":
+ *mode = LinkInternal
+ case "external":
+ *mode = LinkExternal
+ }
+ return nil
+}
+
+func (mode *LinkMode) String() string {
+ switch *mode {
+ case LinkAuto:
+ return "auto"
+ case LinkInternal:
+ return "internal"
+ case LinkExternal:
+ return "external"
+ }
+ return fmt.Sprintf("LinkMode(%d)", uint8(*mode))
+}
+
+// mustLinkExternal reports whether the program being linked requires
+// the external linker be used to complete the link.
+func mustLinkExternal(ctxt *Link) (res bool, reason string) {
+ if ctxt.Debugvlog > 1 {
+ defer func() {
+ if res {
+ log.Printf("external linking is forced by: %s\n", reason)
+ }
+ }()
+ }
+
+ switch obj.GOOS {
+ case "android":
+ return true, "android"
+ case "darwin":
+ if SysArch.InFamily(sys.ARM, sys.ARM64) {
+ return true, "iOS"
+ }
+ }
+
+ if *flagMsan {
+ return true, "msan"
+ }
+
+ // Internally linking cgo is incomplete on some architectures.
+ // https://golang.org/issue/10373
+ // https://golang.org/issue/14449
+ if iscgo && SysArch.InFamily(sys.ARM64, sys.MIPS64) {
+ return true, obj.GOARCH + " does not support internal cgo"
+ }
+
+ // Some build modes require work the internal linker cannot do (yet).
+ switch Buildmode {
+ case BuildmodeCArchive:
+ return true, "buildmode=c-archive"
+ case BuildmodeCShared:
+ return true, "buildmode=c-shared"
+ case BuildmodePIE:
+ switch obj.GOOS + "/" + obj.GOARCH {
+ case "linux/amd64":
+ default:
+ // Internal linking does not support TLS_IE.
+ return true, "buildmode=pie"
+ }
+ case BuildmodeShared:
+ return true, "buildmode=shared"
+ }
+ if *FlagLinkshared {
+ return true, "dynamically linking with a shared library"
+ }
+
+ return false, ""
+}
+
+// determineLinkMode sets Linkmode.
+//
+// It is called after flags are processed and inputs are processed,
+// so the Linkmode variable has an initial value from the -linkmode
+// flag and the iscgo externalobj variables are set.
+func determineLinkMode(ctxt *Link) {
+ switch Linkmode {
+ case LinkAuto:
+ // The environment variable GO_EXTLINK_ENABLED controls the
+ // default value of -linkmode. If it is not set when the
+ // linker is called we take the value it was set to when
+ // cmd/link was compiled. (See make.bash.)
+ switch obj.Getgoextlinkenabled() {
+ case "0":
+ if needed, reason := mustLinkExternal(ctxt); needed {
+ Exitf("internal linking requested via GO_EXTLINK_ENABLED, but external linking required: %s", reason)
+ }
+ Linkmode = LinkInternal
+ case "1":
+ Linkmode = LinkExternal
+ default:
+ if needed, _ := mustLinkExternal(ctxt); needed {
+ Linkmode = LinkExternal
+ } else if iscgo && externalobj {
+ Linkmode = LinkExternal
+ } else {
+ Linkmode = LinkInternal
+ }
+ }
+ case LinkInternal:
+ if needed, reason := mustLinkExternal(ctxt); needed {
+ Exitf("internal linking requested but external linking required: %s", reason)
+ }
+ }
+}
p.cycle()
}
}
-
-func setlinkmode(arg string) {
- if arg == "internal" {
- Linkmode = LinkInternal
- } else if arg == "external" {
- Linkmode = LinkExternal
- } else if arg == "auto" {
- Linkmode = LinkAuto
- } else {
- Exitf("unknown link mode -linkmode %s", arg)
- }
-}
Headtype obj.HeadType
nerrors int
- Linkmode int
liveness int64
)
}
}
- if Linkmode == LinkAuto {
- if iscgo && externalobj {
- Linkmode = LinkExternal
- } else {
- Linkmode = LinkInternal
- }
-
- // Force external linking for android.
- if obj.GOOS == "android" {
- Linkmode = LinkExternal
- }
-
- // These build modes depend on the external linker
- // to handle some relocations (such as TLS IE) not
- // yet supported by the internal linker.
- switch Buildmode {
- case BuildmodeCArchive, BuildmodeCShared, BuildmodePIE, BuildmodePlugin, BuildmodeShared:
- Linkmode = LinkExternal
- }
- if *FlagLinkshared {
- Linkmode = LinkExternal
- }
-
- // cgo on Darwin must use external linking
- // we can always use external linking, but then there will be circular
- // dependency problems when compiling natively (external linking requires
- // runtime/cgo, runtime/cgo requires cmd/cgo, but cmd/cgo needs to be
- // compiled using external linking.)
- if SysArch.InFamily(sys.ARM, sys.ARM64) && Headtype == obj.Hdarwin && iscgo {
- Linkmode = LinkExternal
- }
-
- // Force external linking for msan.
- if *flagMsan {
- Linkmode = LinkExternal
- }
- }
+ // We now have enough information to determine the link mode.
+ determineLinkMode(ctxt)
- // cmd/7l doesn't support cgo internal linking
- // This is https://golang.org/issue/10373.
- // mips64x doesn't support cgo internal linking either (golang.org/issue/14449)
- if iscgo && (obj.GOARCH == "arm64" || obj.GOARCH == "mips64" || obj.GOARCH == "mips64le") {
- Linkmode = LinkExternal
+ if Linkmode == LinkExternal && SysArch.Family == sys.PPC64 {
+ toc := Linklookup(ctxt, ".TOC.", 0)
+ toc.Type = obj.SDYNIMPORT
}
if Linkmode == LinkExternal && !iscgo {
gcdataAddresses map[*Symbol]uint64
}
+// Link holds the context for writing object code from a compiler
+// or for reading that input into the linker.
type Link struct {
Arch *sys.Arch
Debugvlog int
RV_CHECK_OVERFLOW = 1 << 8
RV_TYPE_MASK = RV_CHECK_OVERFLOW - 1
)
-
-// Pcdata iterator.
-// for(pciterinit(ctxt, &it, &pcd); !it.done; pciternext(&it)) { it.value holds in [it.pc, it.nextpc) }
-
-// Link holds the context for writing object code from a compiler
-// to be linker input or for reading that input into the linker.
-
-// LinkArch is the definition of a single architecture.
-
-const (
- LinkAuto = 0 + iota
- LinkInternal
- LinkExternal
-)
)
func init() {
+ flag.Var(&Linkmode, "linkmode", "set link `mode`")
flag.Var(&Buildmode, "buildmode", "set build `mode`")
flag.Var(&Headtype, "H", "set header `type`")
flag.Var(&rpath, "r", "set the ELF dynamic linker search `path` to dir1:dir2:...")
flagOutfile = flag.String("o", "", "write output to `file`")
FlagLinkshared = flag.Bool("linkshared", false, "link against installed Go shared libraries")
- Buildmode BuildMode
flagInstallSuffix = flag.String("installsuffix", "", "set package directory `suffix`")
flagDumpDep = flag.Bool("dumpdep", false, "dump symbol dependency graph")
obj.Flagfn0("V", "print version and exit", doversion)
obj.Flagfn1("X", "add string value `definition` of the form importpath.name=value", func(s string) { addstrdata1(ctxt, s) })
obj.Flagcount("v", "print link trace", &ctxt.Debugvlog)
- obj.Flagfn1("linkmode", "set link `mode` (internal, external, auto)", setlinkmode)
obj.Flagparse(usage)
import (
"cmd/internal/obj"
"cmd/internal/sys"
- "fmt"
"log"
)
func Linkrlookup(ctxt *Link, name string, v int) *Symbol {
return ctxt.Hash[v][name]
}
-
-// A BuildMode indicates the sort of object we are building:
-// "exe": build a main package and everything it imports into an executable.
-// "c-shared": build a main package, plus all packages that it imports, into a
-// single C shared library. The only callable symbols will be those functions
-// marked as exported.
-// "shared": combine all packages passed on the command line, and their
-// dependencies, into a single shared library that will be used when
-// building with the -linkshared option.
-type BuildMode uint8
-
-const (
- BuildmodeUnset BuildMode = iota
- BuildmodeExe
- BuildmodePIE
- BuildmodeCArchive
- BuildmodeCShared
- BuildmodeShared
- BuildmodePlugin
-)
-
-func (mode *BuildMode) Set(s string) error {
- badmode := func() error {
- return fmt.Errorf("buildmode %s not supported on %s/%s", s, obj.GOOS, obj.GOARCH)
- }
- switch s {
- default:
- return fmt.Errorf("invalid buildmode: %q", s)
- case "exe":
- *mode = BuildmodeExe
- case "pie":
- switch obj.GOOS {
- case "android", "linux":
- default:
- return badmode()
- }
- *mode = BuildmodePIE
- case "c-archive":
- switch obj.GOOS {
- case "darwin", "linux":
- case "windows":
- switch obj.GOARCH {
- case "amd64", "386":
- default:
- return badmode()
- }
- default:
- return badmode()
- }
- *mode = BuildmodeCArchive
- case "c-shared":
- switch obj.GOARCH {
- case "386", "amd64", "arm", "arm64":
- default:
- return badmode()
- }
- *mode = BuildmodeCShared
- case "shared":
- switch obj.GOOS {
- case "linux":
- switch obj.GOARCH {
- case "386", "amd64", "arm", "arm64", "ppc64le", "s390x":
- default:
- return badmode()
- }
- default:
- return badmode()
- }
- *mode = BuildmodeShared
- case "plugin":
- switch obj.GOOS {
- case "linux":
- switch obj.GOARCH {
- case "386", "amd64", "arm", "arm64":
- default:
- return badmode()
- }
- default:
- return badmode()
- }
- *mode = BuildmodePlugin
- }
- return nil
-}
-
-func (mode *BuildMode) String() string {
- switch *mode {
- case BuildmodeUnset:
- return "" // avoid showing a default in usage message
- case BuildmodeExe:
- return "exe"
- case BuildmodePIE:
- return "pie"
- case BuildmodeCArchive:
- return "c-archive"
- case BuildmodeCShared:
- return "c-shared"
- case BuildmodeShared:
- return "shared"
- case BuildmodePlugin:
- return "plugin"
- }
- return fmt.Sprintf("BuildMode(%d)", uint8(*mode))
-}
"cmd/internal/sys"
"cmd/link/internal/ld"
"fmt"
- "log"
)
// Reading object files.
}
func archinit(ctxt *ld.Link) {
- // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
- // Go was built; see ../../make.bash.
- if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" {
- ld.Linkmode = ld.LinkInternal
- }
-
- switch ld.Headtype {
- default:
- if ld.Linkmode == ld.LinkAuto {
- ld.Linkmode = ld.LinkInternal
- }
- if ld.Linkmode == ld.LinkExternal && obj.Getgoextlinkenabled() != "1" {
- log.Fatalf("cannot use -linkmode=external with -H %v", ld.Headtype)
- }
-
- case obj.Hlinux:
- break
- }
-
switch ld.Headtype {
default:
ld.Exitf("unknown -H option: %v", ld.Headtype)
"cmd/internal/sys"
"cmd/link/internal/ld"
"fmt"
- "log"
)
// Reading object files.
}
func archinit(ctxt *ld.Link) {
- // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
- // Go was built; see ../../make.bash.
- if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" {
- ld.Linkmode = ld.LinkInternal
- }
-
- switch ld.Buildmode {
- case ld.BuildmodePIE, ld.BuildmodeShared:
- ld.Linkmode = ld.LinkExternal
- }
-
- if *ld.FlagLinkshared {
- ld.Linkmode = ld.LinkExternal
- }
-
- if ld.Linkmode == ld.LinkExternal {
- toc := ld.Linklookup(ctxt, ".TOC.", 0)
- toc.Type = obj.SDYNIMPORT
- }
-
- switch ld.Headtype {
- default:
- if ld.Linkmode == ld.LinkAuto {
- ld.Linkmode = ld.LinkInternal
- }
- if ld.Linkmode == ld.LinkExternal && obj.Getgoextlinkenabled() != "1" {
- log.Fatalf("cannot use -linkmode=external with -H %v", ld.Headtype)
- }
-
- case obj.Hlinux:
- break
- }
-
switch ld.Headtype {
default:
ld.Exitf("unknown -H option: %v", ld.Headtype)
}
func archinit(ctxt *ld.Link) {
- // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
- // Go was built; see ../../make.bash.
- if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" {
- ld.Linkmode = ld.LinkInternal
- }
-
switch ld.Headtype {
default:
ld.Exitf("unknown -H option: %v", ld.Headtype)
"cmd/internal/sys"
"cmd/link/internal/ld"
"fmt"
- "log"
)
// Reading object files.
}
func archinit(ctxt *ld.Link) {
- // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
- // Go was built; see ../../make.bash.
- if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" {
- ld.Linkmode = ld.LinkInternal
- }
-
- switch ld.Headtype {
- default:
- if ld.Linkmode == ld.LinkAuto {
- ld.Linkmode = ld.LinkInternal
- }
- if ld.Linkmode == ld.LinkExternal && obj.Getgoextlinkenabled() != "1" {
- log.Fatalf("cannot use -linkmode=external with -H %v", ld.Headtype)
- }
-
- case obj.Hdarwin,
- obj.Hfreebsd,
- obj.Hlinux,
- obj.Hnetbsd,
- obj.Hopenbsd,
- obj.Hwindows,
- obj.Hwindowsgui:
- break
- }
-
switch ld.Headtype {
default:
ld.Exitf("unknown -H option: %v", ld.Headtype)