mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/link/internal/ld: move more of mustLinkExternal into internal/platform
internal/platform.MustLinkExternal is used in various places to determine whether external linking is required. It should always match what the linker actually requires, but today does not match because the linker imposes additional constraints. Updates #31544. Change-Id: I0cc6ad587e95c607329dea5d60d29a5fb2a9e722 Reviewed-on: https://go-review.googlesource.com/c/go/+/472515 Run-TryBot: Bryan Mills <bcmills@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@google.com>
This commit is contained in:
parent
b958d4a597
commit
3f8f929d60
13 changed files with 105 additions and 105 deletions
33
src/cmd/dist/build.go
vendored
33
src/cmd/dist/build.go
vendored
|
|
@ -539,7 +539,36 @@ func setup() {
|
|||
// mustLinkExternal is a copy of internal/platform.MustLinkExternal,
|
||||
// duplicated here to avoid version skew in the MustLinkExternal function
|
||||
// during bootstrapping.
|
||||
func mustLinkExternal(goos, goarch string) bool {
|
||||
func mustLinkExternal(goos, goarch string, cgoEnabled bool) bool {
|
||||
if cgoEnabled {
|
||||
switch goarch {
|
||||
case "loong64",
|
||||
"mips", "mipsle", "mips64", "mips64le",
|
||||
"riscv64":
|
||||
// Internally linking cgo is incomplete on some architectures.
|
||||
// https://golang.org/issue/14449
|
||||
return true
|
||||
case "arm64":
|
||||
if goos == "windows" {
|
||||
// windows/arm64 internal linking is not implemented.
|
||||
return true
|
||||
}
|
||||
case "ppc64":
|
||||
// Big Endian PPC64 cgo internal linking is not implemented for aix or linux.
|
||||
return true
|
||||
}
|
||||
|
||||
switch goos {
|
||||
case "android":
|
||||
return true
|
||||
case "dragonfly":
|
||||
// It seems that on Dragonfly thread local storage is
|
||||
// set up by the dynamic linker, so internal cgo linking
|
||||
// doesn't work. Test case is "go test runtime/cgo".
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
switch goos {
|
||||
case "android":
|
||||
if goarch != "arm64" {
|
||||
|
|
@ -1283,7 +1312,7 @@ func timelog(op, name string) {
|
|||
// to switch between the host and target configurations when cross-compiling.
|
||||
func toolenv() []string {
|
||||
var env []string
|
||||
if !mustLinkExternal(goos, goarch) {
|
||||
if !mustLinkExternal(goos, goarch, false) {
|
||||
// Unless the platform requires external linking,
|
||||
// we disable cgo to get static binaries for cmd/go and cmd/pprof,
|
||||
// so that they work on systems without the same dynamic libraries
|
||||
|
|
|
|||
10
src/cmd/dist/build_test.go
vendored
10
src/cmd/dist/build_test.go
vendored
|
|
@ -14,10 +14,12 @@ import (
|
|||
func TestMustLinkExternal(t *testing.T) {
|
||||
for _, goos := range okgoos {
|
||||
for _, goarch := range okgoarch {
|
||||
got := mustLinkExternal(goos, goarch)
|
||||
want := platform.MustLinkExternal(goos, goarch)
|
||||
if got != want {
|
||||
t.Errorf("mustLinkExternal(%q, %q) = %v; want %v", goos, goarch, got, want)
|
||||
for _, cgoEnabled := range []bool{true, false} {
|
||||
got := mustLinkExternal(goos, goarch, cgoEnabled)
|
||||
want := platform.MustLinkExternal(goos, goarch, cgoEnabled)
|
||||
if got != want {
|
||||
t.Errorf("mustLinkExternal(%q, %q, %v) = %v; want %v", goos, goarch, cgoEnabled, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -643,7 +643,7 @@ func (gcToolchain) ld(b *Builder, root *Action, out, importcfg, mainpkg string)
|
|||
// linker's build id, which will cause our build id to not
|
||||
// match the next time the tool is built.
|
||||
// Rely on the external build id instead.
|
||||
if !platform.MustLinkExternal(cfg.Goos, cfg.Goarch) {
|
||||
if !platform.MustLinkExternal(cfg.Goos, cfg.Goarch, false) {
|
||||
ldflags = append(ldflags, "-X=cmd/internal/objabi.buildID="+root.buildID)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
package ld
|
||||
|
||||
import (
|
||||
"cmd/internal/sys"
|
||||
"fmt"
|
||||
"internal/buildcfg"
|
||||
"internal/platform"
|
||||
|
|
@ -125,7 +124,7 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) {
|
|||
}()
|
||||
}
|
||||
|
||||
if platform.MustLinkExternal(buildcfg.GOOS, buildcfg.GOARCH) {
|
||||
if platform.MustLinkExternal(buildcfg.GOOS, buildcfg.GOARCH, false) {
|
||||
return true, fmt.Sprintf("%s/%s requires external linking", buildcfg.GOOS, buildcfg.GOARCH)
|
||||
}
|
||||
|
||||
|
|
@ -137,25 +136,9 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) {
|
|||
return true, "asan"
|
||||
}
|
||||
|
||||
// Internally linking cgo is incomplete on some architectures.
|
||||
// https://golang.org/issue/14449
|
||||
if iscgo && ctxt.Arch.InFamily(sys.Loong64, sys.MIPS64, sys.MIPS, sys.RISCV64) {
|
||||
if iscgo && platform.MustLinkExternal(buildcfg.GOOS, buildcfg.GOARCH, true) {
|
||||
return true, buildcfg.GOARCH + " does not support internal cgo"
|
||||
}
|
||||
if iscgo && (buildcfg.GOOS == "android" || buildcfg.GOOS == "dragonfly") {
|
||||
// It seems that on Dragonfly thread local storage is
|
||||
// set up by the dynamic linker, so internal cgo linking
|
||||
// doesn't work. Test case is "go test runtime/cgo".
|
||||
return true, buildcfg.GOOS + " does not support internal cgo"
|
||||
}
|
||||
if iscgo && buildcfg.GOOS == "windows" && buildcfg.GOARCH == "arm64" {
|
||||
// windows/arm64 internal linking is not implemented.
|
||||
return true, buildcfg.GOOS + "/" + buildcfg.GOARCH + " does not support internal cgo"
|
||||
}
|
||||
if iscgo && ctxt.Arch == sys.ArchPPC64 {
|
||||
// Big Endian PPC64 cgo internal linking is not implemented for aix or linux.
|
||||
return true, buildcfg.GOOS + " does not support internal cgo"
|
||||
}
|
||||
|
||||
// Some build modes require work the internal linker cannot do (yet).
|
||||
switch ctxt.BuildMode {
|
||||
|
|
@ -164,12 +147,7 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) {
|
|||
case BuildModeCShared:
|
||||
return true, "buildmode=c-shared"
|
||||
case BuildModePIE:
|
||||
switch buildcfg.GOOS + "/" + buildcfg.GOARCH {
|
||||
case "android/arm64":
|
||||
case "linux/amd64", "linux/arm64", "linux/ppc64le":
|
||||
case "windows/386", "windows/amd64", "windows/arm", "windows/arm64":
|
||||
case "darwin/amd64", "darwin/arm64":
|
||||
default:
|
||||
if !platform.InternalLinkPIESupported(buildcfg.GOOS, buildcfg.GOARCH) {
|
||||
// Internal linking does not support TLS_IE.
|
||||
return true, "buildmode=pie"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -274,7 +274,7 @@ func TestSizes(t *testing.T) {
|
|||
}
|
||||
|
||||
// External linking may bring in C symbols with unknown size. Skip.
|
||||
testenv.MustInternalLink(t)
|
||||
testenv.MustInternalLink(t, false)
|
||||
|
||||
t.Parallel()
|
||||
|
||||
|
|
@ -882,7 +882,7 @@ func TestAbstractOriginSanityIssue26237(t *testing.T) {
|
|||
|
||||
func TestRuntimeTypeAttrInternal(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t)
|
||||
testenv.MustInternalLink(t)
|
||||
testenv.MustInternalLink(t, false)
|
||||
|
||||
if runtime.GOOS == "plan9" {
|
||||
t.Skip("skipping on plan9; no DWARF symbol table in executables")
|
||||
|
|
@ -1165,7 +1165,7 @@ func main() {
|
|||
// TODO: maybe there is some way to tell the external linker not to put
|
||||
// those symbols in the executable's symbol table? Prefix the symbol name
|
||||
// with "." or "L" to pretend it is a label?
|
||||
if !testenv.CanInternalLink() {
|
||||
if !testenv.CanInternalLink(false) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ func TestUndefinedRelocErrors(t *testing.T) {
|
|||
|
||||
// When external linking, symbols may be defined externally, so we allow
|
||||
// undefined symbols and let external linker resolve. Skip the test.
|
||||
testenv.MustInternalLink(t)
|
||||
testenv.MustInternalLink(t, false)
|
||||
|
||||
t.Parallel()
|
||||
|
||||
|
|
|
|||
|
|
@ -176,19 +176,7 @@ main.x: relocation target main.zero not defined
|
|||
func TestIssue33979(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t)
|
||||
testenv.MustHaveCGO(t)
|
||||
testenv.MustInternalLink(t)
|
||||
|
||||
// Skip test on platforms that do not support cgo internal linking.
|
||||
switch runtime.GOARCH {
|
||||
case "loong64":
|
||||
t.Skipf("Skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
case "mips", "mipsle", "mips64", "mips64le":
|
||||
t.Skipf("Skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
if runtime.GOOS == "aix" ||
|
||||
runtime.GOOS == "windows" && runtime.GOARCH == "arm64" {
|
||||
t.Skipf("Skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
testenv.MustInternalLink(t, true)
|
||||
|
||||
t.Parallel()
|
||||
|
||||
|
|
@ -751,8 +739,8 @@ func TestTrampolineCgo(t *testing.T) {
|
|||
|
||||
// Test internal linking mode.
|
||||
|
||||
if runtime.GOARCH == "ppc64" || (runtime.GOARCH == "arm64" && runtime.GOOS == "windows") || !testenv.CanInternalLink() {
|
||||
return // internal linking cgo is not supported
|
||||
if !testenv.CanInternalLink(true) {
|
||||
continue
|
||||
}
|
||||
cmd = testenv.Command(t, testenv.GoToolPath(t), "build", "-buildmode="+mode, "-ldflags=-debugtramp=2 -linkmode=internal", "-o", exe, src)
|
||||
out, err = cmd.CombinedOutput()
|
||||
|
|
|
|||
|
|
@ -2,56 +2,25 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build cgo
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"internal/testenv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func canInternalLink() bool {
|
||||
switch runtime.GOOS {
|
||||
case "aix":
|
||||
return false
|
||||
case "dragonfly":
|
||||
return false
|
||||
case "freebsd":
|
||||
switch runtime.GOARCH {
|
||||
case "arm64", "riscv64":
|
||||
return false
|
||||
}
|
||||
case "linux":
|
||||
switch runtime.GOARCH {
|
||||
case "arm64", "loong64", "mips64", "mips64le", "mips", "mipsle", "ppc64", "ppc64le", "riscv64":
|
||||
return false
|
||||
}
|
||||
case "openbsd":
|
||||
switch runtime.GOARCH {
|
||||
case "arm64", "mips64":
|
||||
return false
|
||||
}
|
||||
case "windows":
|
||||
switch runtime.GOARCH {
|
||||
case "arm64":
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func TestInternalLinkerCgoExec(t *testing.T) {
|
||||
if !canInternalLink() {
|
||||
t.Skip("skipping; internal linking is not supported")
|
||||
}
|
||||
testenv.MustHaveCGO(t)
|
||||
testenv.MustInternalLink(t, true)
|
||||
testGoExec(t, true, false)
|
||||
}
|
||||
|
||||
func TestExternalLinkerCgoExec(t *testing.T) {
|
||||
testenv.MustHaveCGO(t)
|
||||
testGoExec(t, true, true)
|
||||
}
|
||||
|
||||
func TestCgoLib(t *testing.T) {
|
||||
testenv.MustHaveCGO(t)
|
||||
testGoLib(t, true)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,8 +71,39 @@ func FuzzInstrumented(goos, goarch string) bool {
|
|||
}
|
||||
}
|
||||
|
||||
// MustLinkExternal reports whether goos/goarch requires external linking.
|
||||
func MustLinkExternal(goos, goarch string) bool {
|
||||
// MustLinkExternal reports whether goos/goarch requires external linking
|
||||
// with or without cgo dependencies.
|
||||
func MustLinkExternal(goos, goarch string, withCgo bool) bool {
|
||||
if withCgo {
|
||||
switch goarch {
|
||||
case "loong64",
|
||||
"mips", "mipsle", "mips64", "mips64le",
|
||||
"riscv64":
|
||||
// Internally linking cgo is incomplete on some architectures.
|
||||
// https://go.dev/issue/14449
|
||||
return true
|
||||
case "arm64":
|
||||
if goos == "windows" {
|
||||
// windows/arm64 internal linking is not implemented.
|
||||
return true
|
||||
}
|
||||
case "ppc64":
|
||||
// Big Endian PPC64 cgo internal linking is not implemented for aix or linux.
|
||||
// https://go.dev/issue/8912
|
||||
return true
|
||||
}
|
||||
|
||||
switch goos {
|
||||
case "android":
|
||||
return true
|
||||
case "dragonfly":
|
||||
// It seems that on Dragonfly thread local storage is
|
||||
// set up by the dynamic linker, so internal cgo linking
|
||||
// doesn't work. Test case is "go test runtime/cgo".
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
switch goos {
|
||||
case "android":
|
||||
if goarch != "arm64" {
|
||||
|
|
@ -178,10 +209,10 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool {
|
|||
|
||||
func InternalLinkPIESupported(goos, goarch string) bool {
|
||||
switch goos + "/" + goarch {
|
||||
case "darwin/amd64", "darwin/arm64",
|
||||
case "android/arm64",
|
||||
"darwin/amd64", "darwin/arm64",
|
||||
"linux/amd64", "linux/arm64", "linux/ppc64le",
|
||||
"android/arm64",
|
||||
"windows-amd64", "windows-386", "windows-arm":
|
||||
"windows/386", "windows/amd64", "windows/arm", "windows/arm64":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
|
|
|||
|
|
@ -288,15 +288,18 @@ func MustHaveCGO(t testing.TB) {
|
|||
|
||||
// CanInternalLink reports whether the current system can link programs with
|
||||
// internal linking.
|
||||
func CanInternalLink() bool {
|
||||
return !platform.MustLinkExternal(runtime.GOOS, runtime.GOARCH)
|
||||
func CanInternalLink(withCgo bool) bool {
|
||||
return !platform.MustLinkExternal(runtime.GOOS, runtime.GOARCH, withCgo)
|
||||
}
|
||||
|
||||
// MustInternalLink checks that the current system can link programs with internal
|
||||
// linking.
|
||||
// If not, MustInternalLink calls t.Skip with an explanation.
|
||||
func MustInternalLink(t testing.TB) {
|
||||
if !CanInternalLink() {
|
||||
func MustInternalLink(t testing.TB, withCgo bool) {
|
||||
if !CanInternalLink(withCgo) {
|
||||
if withCgo && CanInternalLink(false) {
|
||||
t.Skipf("skipping test: internal linking on %s/%s is not supported with cgo", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
t.Skipf("skipping test: internal linking on %s/%s is not supported", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -694,7 +694,7 @@ func TestExtraFiles(t *testing.T) {
|
|||
|
||||
// This test runs with cgo disabled. External linking needs cgo, so
|
||||
// it doesn't work if external linking is required.
|
||||
testenv.MustInternalLink(t)
|
||||
testenv.MustInternalLink(t, false)
|
||||
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skipf("skipping test on %q", runtime.GOOS)
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ func TestCrashHandler(t *testing.T) {
|
|||
|
||||
func testDeadlock(t *testing.T, name string) {
|
||||
// External linking brings in cgo, causing deadlock detection not working.
|
||||
testenv.MustInternalLink(t)
|
||||
testenv.MustInternalLink(t, false)
|
||||
|
||||
output := runTestProg(t, "testprog", name)
|
||||
want := "fatal error: all goroutines are asleep - deadlock!\n"
|
||||
|
|
@ -211,7 +211,7 @@ func TestLockedDeadlock2(t *testing.T) {
|
|||
|
||||
func TestGoexitDeadlock(t *testing.T) {
|
||||
// External linking brings in cgo, causing deadlock detection not working.
|
||||
testenv.MustInternalLink(t)
|
||||
testenv.MustInternalLink(t, false)
|
||||
|
||||
output := runTestProg(t, "testprog", "GoexitDeadlock")
|
||||
want := "no goroutines (main called runtime.Goexit) - deadlock!"
|
||||
|
|
@ -311,7 +311,7 @@ panic: third panic
|
|||
|
||||
func TestGoexitCrash(t *testing.T) {
|
||||
// External linking brings in cgo, causing deadlock detection not working.
|
||||
testenv.MustInternalLink(t)
|
||||
testenv.MustInternalLink(t, false)
|
||||
|
||||
output := runTestProg(t, "testprog", "GoexitExit")
|
||||
want := "no goroutines (main called runtime.Goexit) - deadlock!"
|
||||
|
|
@ -372,7 +372,7 @@ func TestBreakpoint(t *testing.T) {
|
|||
|
||||
func TestGoexitInPanic(t *testing.T) {
|
||||
// External linking brings in cgo, causing deadlock detection not working.
|
||||
testenv.MustInternalLink(t)
|
||||
testenv.MustInternalLink(t, false)
|
||||
|
||||
// see issue 8774: this code used to trigger an infinite recursion
|
||||
output := runTestProg(t, "testprog", "GoexitInPanic")
|
||||
|
|
@ -439,7 +439,7 @@ func TestPanicAfterGoexit(t *testing.T) {
|
|||
|
||||
func TestRecoveredPanicAfterGoexit(t *testing.T) {
|
||||
// External linking brings in cgo, causing deadlock detection not working.
|
||||
testenv.MustInternalLink(t)
|
||||
testenv.MustInternalLink(t, false)
|
||||
|
||||
output := runTestProg(t, "testprog", "RecoveredPanicAfterGoexit")
|
||||
want := "fatal error: no goroutines (main called runtime.Goexit) - deadlock!"
|
||||
|
|
@ -450,7 +450,7 @@ func TestRecoveredPanicAfterGoexit(t *testing.T) {
|
|||
|
||||
func TestRecoverBeforePanicAfterGoexit(t *testing.T) {
|
||||
// External linking brings in cgo, causing deadlock detection not working.
|
||||
testenv.MustInternalLink(t)
|
||||
testenv.MustInternalLink(t, false)
|
||||
|
||||
t.Parallel()
|
||||
output := runTestProg(t, "testprog", "RecoverBeforePanicAfterGoexit")
|
||||
|
|
@ -462,7 +462,7 @@ func TestRecoverBeforePanicAfterGoexit(t *testing.T) {
|
|||
|
||||
func TestRecoverBeforePanicAfterGoexit2(t *testing.T) {
|
||||
// External linking brings in cgo, causing deadlock detection not working.
|
||||
testenv.MustInternalLink(t)
|
||||
testenv.MustInternalLink(t, false)
|
||||
|
||||
t.Parallel()
|
||||
output := runTestProg(t, "testprog", "RecoverBeforePanicAfterGoexit2")
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ func TestFakeTime(t *testing.T) {
|
|||
|
||||
// Faketime is advanced in checkdead. External linking brings in cgo,
|
||||
// causing checkdead not working.
|
||||
testenv.MustInternalLink(t)
|
||||
testenv.MustInternalLink(t, false)
|
||||
|
||||
t.Parallel()
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue