From a413908dd064de6e3ea5b8d95d707a532bd3f4c8 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Wed, 16 Sep 2020 16:59:58 -0400 Subject: all: add GOOS=ios Introduce GOOS=ios for iOS systems. GOOS=ios matches "darwin" build tag, like GOOS=android matches "linux" and GOOS=illumos matches "solaris". Only ios/arm64 is supported (ios/amd64 is not). GOOS=ios and GOOS=darwin remain essentially the same at this point. They will diverge at later time, to differentiate macOS and iOS. Uses of GOOS=="darwin" are changed to (GOOS=="darwin" || GOOS=="ios"), except if it clearly means macOS (e.g. GOOS=="darwin" && GOARCH=="amd64"), it remains GOOS=="darwin". Updates #38485. Change-Id: I4faacdc1008f42434599efb3c3ad90763a83b67c Reviewed-on: https://go-review.googlesource.com/c/go/+/254740 Trust: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Go Bot Reviewed-by: Austin Clements --- src/cmd/internal/sys/supported.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/cmd/internal/sys') diff --git a/src/cmd/internal/sys/supported.go b/src/cmd/internal/sys/supported.go index c27b3b986d..b2b3b02bf6 100644 --- a/src/cmd/internal/sys/supported.go +++ b/src/cmd/internal/sys/supported.go @@ -38,7 +38,7 @@ func MustLinkExternal(goos, goarch string) bool { if goarch != "arm64" { return true } - case "darwin": + case "darwin", "ios": if goarch == "arm64" { return true } -- cgit v1.3 From 7d6b304f123b6d11784b48179059f843493c4790 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Sat, 3 Oct 2020 16:26:37 -0400 Subject: cmd/link: support plugin on macOS/ARM64 Updates #38485. Change-Id: I8295f7fad55b1f9701162f9d2902b3499137c64d Reviewed-on: https://go-review.googlesource.com/c/go/+/259441 Trust: Cherry Zhang Reviewed-by: Than McIntosh --- src/cmd/dist/test.go | 2 +- src/cmd/internal/sys/supported.go | 2 +- src/cmd/link/internal/arm64/asm.go | 20 ++++++++++-- src/cmd/link/internal/ld/config.go | 8 ++++- src/cmd/link/internal/ld/lib.go | 4 ++- src/cmd/link/internal/ld/macho.go | 62 ++++++++++++++++++++------------------ 6 files changed, 62 insertions(+), 36 deletions(-) (limited to 'src/cmd/internal/sys') diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index abe496fdee..4b07501b6d 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -1011,7 +1011,7 @@ func (t *tester) supportedBuildmode(mode string) bool { switch pair { case "linux-386", "linux-amd64", "linux-arm", "linux-s390x", "linux-ppc64le": return true - case "darwin-amd64": + case "darwin-amd64", "darwin-arm64": return true case "freebsd-amd64": return true diff --git a/src/cmd/internal/sys/supported.go b/src/cmd/internal/sys/supported.go index b2b3b02bf6..94fc92146c 100644 --- a/src/cmd/internal/sys/supported.go +++ b/src/cmd/internal/sys/supported.go @@ -104,7 +104,7 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool { switch platform { case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/s390x", "linux/ppc64le", "android/amd64", "android/arm", "android/arm64", "android/386", - "darwin/amd64", + "darwin/amd64", "darwin/arm64", "freebsd/amd64": return true } diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go index 945b83822c..1d2aa591d7 100644 --- a/src/cmd/link/internal/arm64/asm.go +++ b/src/cmd/link/internal/arm64/asm.go @@ -371,7 +371,7 @@ func machoreloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sy rt := r.Type siz := r.Size - if ldr.SymType(rs) == sym.SHOSTOBJ || rt == objabi.R_CALLARM64 || rt == objabi.R_ADDRARM64 { + if ldr.SymType(rs) == sym.SHOSTOBJ || rt == objabi.R_CALLARM64 || rt == objabi.R_ADDRARM64 || rt == objabi.R_ARM64_GOTPCREL { if ldr.SymDynid(rs) < 0 { ldr.Errorf(s, "reloc %d (%s) to non-macho symbol %s type=%d (%s)", rt, sym.RelocName(arch, rt), ldr.SymName(rs), ldr.SymType(rs), ldr.SymType(rs)) return false @@ -415,6 +415,22 @@ func machoreloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sy } v |= 1 << 24 // pc-relative bit v |= ld.MACHO_ARM64_RELOC_PAGE21 << 28 + case objabi.R_ARM64_GOTPCREL: + siz = 4 + // Two relocation entries: MACHO_ARM64_RELOC_GOT_LOAD_PAGEOFF12 MACHO_ARM64_RELOC_GOT_LOAD_PAGE21 + // if r.Xadd is non-zero, add two MACHO_ARM64_RELOC_ADDEND. + if r.Xadd != 0 { + out.Write32(uint32(sectoff + 4)) + out.Write32((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(r.Xadd&0xffffff)) + } + out.Write32(uint32(sectoff + 4)) + out.Write32(v | (ld.MACHO_ARM64_RELOC_GOT_LOAD_PAGEOFF12 << 28) | (2 << 25)) + if r.Xadd != 0 { + out.Write32(uint32(sectoff)) + out.Write32((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(r.Xadd&0xffffff)) + } + v |= 1 << 24 // pc-relative bit + v |= ld.MACHO_ARM64_RELOC_GOT_LOAD_PAGE21 << 28 } switch siz { @@ -457,7 +473,7 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade } nExtReloc = 2 // need two ELF/Mach-O relocations. see elfreloc1/machoreloc1 - if target.IsDarwin() && rt == objabi.R_ADDRARM64 && xadd != 0 { + if target.IsDarwin() && xadd != 0 { nExtReloc = 4 // need another two relocations for non-zero addend } diff --git a/src/cmd/link/internal/ld/config.go b/src/cmd/link/internal/ld/config.go index 9aa59fa3e3..a3ed5f2307 100644 --- a/src/cmd/link/internal/ld/config.go +++ b/src/cmd/link/internal/ld/config.go @@ -95,7 +95,13 @@ func (mode *BuildMode) Set(s string) error { default: return badmode() } - case "darwin", "freebsd": + case "darwin": + switch objabi.GOARCH { + case "amd64", "arm64": + default: + return badmode() + } + case "freebsd": switch objabi.GOARCH { case "amd64": default: diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index cd630e9eae..9fb85becec 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -1254,7 +1254,9 @@ func (ctxt *Link) hostlink() { // -headerpad is incompatible with -fembed-bitcode. argv = append(argv, "-Wl,-headerpad,1144") } - if ctxt.DynlinkingGo() && !ctxt.Arch.InFamily(sys.ARM, sys.ARM64) { + if ctxt.DynlinkingGo() && objabi.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 !combineDwarf { diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go index 9765ce18d3..80a753438e 100644 --- a/src/cmd/link/internal/ld/macho.go +++ b/src/cmd/link/internal/ld/macho.go @@ -76,36 +76,38 @@ const ( ) const ( - MACHO_CPU_AMD64 = 1<<24 | 7 - MACHO_CPU_386 = 7 - MACHO_SUBCPU_X86 = 3 - MACHO_CPU_ARM = 12 - MACHO_SUBCPU_ARM = 0 - MACHO_SUBCPU_ARMV7 = 9 - MACHO_CPU_ARM64 = 1<<24 | 12 - MACHO_SUBCPU_ARM64_ALL = 0 - MACHO32SYMSIZE = 12 - MACHO64SYMSIZE = 16 - MACHO_X86_64_RELOC_UNSIGNED = 0 - MACHO_X86_64_RELOC_SIGNED = 1 - MACHO_X86_64_RELOC_BRANCH = 2 - MACHO_X86_64_RELOC_GOT_LOAD = 3 - MACHO_X86_64_RELOC_GOT = 4 - MACHO_X86_64_RELOC_SUBTRACTOR = 5 - MACHO_X86_64_RELOC_SIGNED_1 = 6 - MACHO_X86_64_RELOC_SIGNED_2 = 7 - MACHO_X86_64_RELOC_SIGNED_4 = 8 - MACHO_ARM_RELOC_VANILLA = 0 - MACHO_ARM_RELOC_PAIR = 1 - MACHO_ARM_RELOC_SECTDIFF = 2 - MACHO_ARM_RELOC_BR24 = 5 - MACHO_ARM64_RELOC_UNSIGNED = 0 - MACHO_ARM64_RELOC_BRANCH26 = 2 - MACHO_ARM64_RELOC_PAGE21 = 3 - MACHO_ARM64_RELOC_PAGEOFF12 = 4 - MACHO_ARM64_RELOC_ADDEND = 10 - MACHO_GENERIC_RELOC_VANILLA = 0 - MACHO_FAKE_GOTPCREL = 100 + MACHO_CPU_AMD64 = 1<<24 | 7 + MACHO_CPU_386 = 7 + MACHO_SUBCPU_X86 = 3 + MACHO_CPU_ARM = 12 + MACHO_SUBCPU_ARM = 0 + MACHO_SUBCPU_ARMV7 = 9 + MACHO_CPU_ARM64 = 1<<24 | 12 + MACHO_SUBCPU_ARM64_ALL = 0 + MACHO32SYMSIZE = 12 + MACHO64SYMSIZE = 16 + MACHO_X86_64_RELOC_UNSIGNED = 0 + MACHO_X86_64_RELOC_SIGNED = 1 + MACHO_X86_64_RELOC_BRANCH = 2 + MACHO_X86_64_RELOC_GOT_LOAD = 3 + MACHO_X86_64_RELOC_GOT = 4 + MACHO_X86_64_RELOC_SUBTRACTOR = 5 + MACHO_X86_64_RELOC_SIGNED_1 = 6 + MACHO_X86_64_RELOC_SIGNED_2 = 7 + MACHO_X86_64_RELOC_SIGNED_4 = 8 + MACHO_ARM_RELOC_VANILLA = 0 + MACHO_ARM_RELOC_PAIR = 1 + MACHO_ARM_RELOC_SECTDIFF = 2 + MACHO_ARM_RELOC_BR24 = 5 + MACHO_ARM64_RELOC_UNSIGNED = 0 + MACHO_ARM64_RELOC_BRANCH26 = 2 + MACHO_ARM64_RELOC_PAGE21 = 3 + MACHO_ARM64_RELOC_PAGEOFF12 = 4 + MACHO_ARM64_RELOC_GOT_LOAD_PAGE21 = 5 + MACHO_ARM64_RELOC_GOT_LOAD_PAGEOFF12 = 6 + MACHO_ARM64_RELOC_ADDEND = 10 + MACHO_GENERIC_RELOC_VANILLA = 0 + MACHO_FAKE_GOTPCREL = 100 ) const ( -- cgit v1.3 From 234de9e1c2afc518e33c0adcf2928a2a9ebf5ce1 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Sat, 3 Oct 2020 23:36:58 -0400 Subject: cmd/link: support PIE on macOS/ARM64 On macOS/ARM64 everything must be PIE, and we already build PIE in exe buildmode. Support PIE buildmode as well. Updates #38485. Change-Id: I10b68c2f6eb77714e31c26116c61a0e28bf9a358 Reviewed-on: https://go-review.googlesource.com/c/go/+/259442 Trust: Cherry Zhang Reviewed-by: Than McIntosh --- src/cmd/dist/test.go | 2 +- src/cmd/internal/sys/supported.go | 2 +- src/cmd/link/internal/ld/config.go | 8 +++++++- 3 files changed, 9 insertions(+), 3 deletions(-) (limited to 'src/cmd/internal/sys') diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index 4b07501b6d..d37454c651 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -1023,7 +1023,7 @@ func (t *tester) supportedBuildmode(mode string) bool { "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-s390x", "android-amd64", "android-arm", "android-arm64", "android-386": return true - case "darwin-amd64": + case "darwin-amd64", "darwin-arm64": return true case "windows-amd64", "windows-386", "windows-arm": return true diff --git a/src/cmd/internal/sys/supported.go b/src/cmd/internal/sys/supported.go index 94fc92146c..f97f663f2a 100644 --- a/src/cmd/internal/sys/supported.go +++ b/src/cmd/internal/sys/supported.go @@ -86,7 +86,7 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool { case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x", "android/amd64", "android/arm", "android/arm64", "android/386", "freebsd/amd64", - "darwin/amd64", + "darwin/amd64", "darwin/arm64", "aix/ppc64", "windows/386", "windows/amd64", "windows/arm": return true diff --git a/src/cmd/link/internal/ld/config.go b/src/cmd/link/internal/ld/config.go index a3ed5f2307..aaf74b58de 100644 --- a/src/cmd/link/internal/ld/config.go +++ b/src/cmd/link/internal/ld/config.go @@ -39,7 +39,13 @@ func (mode *BuildMode) Set(s string) error { case "pie": switch objabi.GOOS { case "aix", "android", "linux", "windows": - case "darwin", "freebsd": + case "darwin": + switch objabi.GOARCH { + case "amd64", "arm64": + default: + return badmode() + } + case "freebsd": switch objabi.GOARCH { case "amd64": default: -- cgit v1.3 From f8e554021b7de4bf1150f64d047091b429c92b39 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Sat, 3 Oct 2020 23:58:29 -0400 Subject: cmd/link: support C-shared buildmode on macOS/ARM64 It just works, after the plugin work. Updates #38485. Change-Id: I55aa11b380a33a729fccb731b77f48bc7d0dea2e Reviewed-on: https://go-review.googlesource.com/c/go/+/259443 Trust: Cherry Zhang Reviewed-by: Than McIntosh --- src/cmd/dist/test.go | 2 +- src/cmd/internal/sys/supported.go | 2 +- src/cmd/link/internal/ld/lib.go | 3 --- 3 files changed, 2 insertions(+), 5 deletions(-) (limited to 'src/cmd/internal/sys') diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index d37454c651..03e6866d62 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -992,7 +992,7 @@ func (t *tester) supportedBuildmode(mode string) bool { case "c-shared": switch pair { case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-s390x", - "darwin-amd64", + "darwin-amd64", "darwin-arm64", "freebsd-amd64", "android-arm", "android-arm64", "android-386", "windows-amd64", "windows-386": diff --git a/src/cmd/internal/sys/supported.go b/src/cmd/internal/sys/supported.go index f97f663f2a..8d87e95655 100644 --- a/src/cmd/internal/sys/supported.go +++ b/src/cmd/internal/sys/supported.go @@ -69,7 +69,7 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool { case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/ppc64le", "linux/s390x", "android/amd64", "android/arm", "android/arm64", "android/386", "freebsd/amd64", - "darwin/amd64", + "darwin/amd64", "darwin/arm64", "windows/amd64", "windows/386": return true } diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 9fb85becec..5fe028d321 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -1329,9 +1329,6 @@ func (ctxt *Link) hostlink() { case BuildModeCShared: if ctxt.HeadType == objabi.Hdarwin { argv = append(argv, "-dynamiclib") - if ctxt.Arch.Family != sys.AMD64 { - argv = append(argv, "-Wl,-read_only_relocs,suppress") - } } else { // ELF. argv = append(argv, "-Wl,-Bsymbolic") -- cgit v1.3 From f8df205e74d5122c43f41923280451641e566ee2 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Wed, 7 Oct 2020 18:29:51 -0400 Subject: all: enable more tests on macOS/ARM64 On macOS, we can do "go build", can exec, and have the source tree available, so we can enable more tests. Skip ones that don't work. Most of them are due to that it requires external linking (for now) and some tests don't work with external linking (e.g. runtime deadlock detection). For them, helper functions CanInternalLink/MustInternalLink are introduced. I still want to have internal linking implemented, but it is still a good idea to identify which tests don't work with external linking. Updates #38485. Change-Id: I6b14697573cf3f371daf54b9ddd792acf232f2f2 Reviewed-on: https://go-review.googlesource.com/c/go/+/260719 Trust: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Go Bot Reviewed-by: Brad Fitzpatrick Reviewed-by: Than McIntosh --- src/cmd/go/go_test.go | 9 ++++--- src/cmd/internal/sys/supported.go | 1 + src/cmd/internal/sys/supported_test.go | 18 ++++++++++++++ src/cmd/link/internal/ld/dwarf_test.go | 17 +++++++++++++ src/cmd/link/internal/ld/ld_test.go | 7 +++++- src/cmd/link/link_test.go | 1 + src/cmd/nm/nm_cgo_test.go | 5 ++++ src/cmd/nm/nm_test.go | 3 +++ src/internal/cpu/cpu_test.go | 9 +++++++ src/internal/testenv/testenv.go | 44 +++++++++++++++++++++++----------- src/os/exec/exec_test.go | 4 ++++ src/runtime/crash_test.go | 21 ++++++++++++++++ src/runtime/time_test.go | 4 ++++ 13 files changed, 123 insertions(+), 20 deletions(-) create mode 100644 src/cmd/internal/sys/supported_test.go (limited to 'src/cmd/internal/sys') diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index 66a52c86ad..093ea2ffa1 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -58,11 +58,10 @@ func init() { switch runtime.GOOS { case "android", "js": canRun = false - case "darwin", "ios": - switch runtime.GOARCH { - case "arm64": - canRun = false - } + case "darwin": + // nothing to do + case "ios": + canRun = false case "linux": switch runtime.GOARCH { case "arm": diff --git a/src/cmd/internal/sys/supported.go b/src/cmd/internal/sys/supported.go index 8d87e95655..41e5ec1432 100644 --- a/src/cmd/internal/sys/supported.go +++ b/src/cmd/internal/sys/supported.go @@ -32,6 +32,7 @@ func MSanSupported(goos, goarch string) bool { } // MustLinkExternal reports whether goos/goarch requires external linking. +// (This is the opposite of internal/testenv.CanInternalLink. Keep them in sync.) func MustLinkExternal(goos, goarch string) bool { switch goos { case "android": diff --git a/src/cmd/internal/sys/supported_test.go b/src/cmd/internal/sys/supported_test.go new file mode 100644 index 0000000000..1217814af5 --- /dev/null +++ b/src/cmd/internal/sys/supported_test.go @@ -0,0 +1,18 @@ +// Copyright 2020 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 sys + +import ( + "internal/testenv" + "runtime" + "testing" +) + +func TestMustLinkExternalMatchesTestenv(t *testing.T) { + // MustLinkExternal and testenv.CanInternalLink are the exact opposite. + if b := MustLinkExternal(runtime.GOOS, runtime.GOARCH); b != !testenv.CanInternalLink() { + t.Fatalf("MustLinkExternal() == %v, testenv.CanInternalLink() == %v, don't match", b, testenv.CanInternalLink()) + } +} diff --git a/src/cmd/link/internal/ld/dwarf_test.go b/src/cmd/link/internal/ld/dwarf_test.go index 22948521f5..a66506d392 100644 --- a/src/cmd/link/internal/ld/dwarf_test.go +++ b/src/cmd/link/internal/ld/dwarf_test.go @@ -238,6 +238,10 @@ func TestSizes(t *testing.T) { if runtime.GOOS == "plan9" { t.Skip("skipping on plan9; no DWARF symbol table in executables") } + + // External linking may bring in C symbols with unknown size. Skip. + testenv.MustInternalLink(t) + t.Parallel() // DWARF sizes should never be -1. @@ -919,6 +923,7 @@ func TestAbstractOriginSanityIssue26237(t *testing.T) { func TestRuntimeTypeAttrInternal(t *testing.T) { testenv.MustHaveGoBuild(t) + testenv.MustInternalLink(t) if runtime.GOOS == "plan9" { t.Skip("skipping on plan9; no DWARF symbol table in executables") @@ -1018,6 +1023,9 @@ func main() { t.Fatalf("*main.X DIE had no runtime type attr. DIE: %v", dies[0]) } + if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" { + return // everything is PIE on ARM64, addresses are relocated + } if rtAttr.(uint64)+types.Addr != addr { t.Errorf("DWARF type offset was %#x+%#x, but test program said %#x", rtAttr.(uint64), types.Addr, addr) } @@ -1203,6 +1211,15 @@ func main() { } } + // When external linking, we put all symbols in the symbol table (so the + // external linker can find them). Skip the symbol table check. + // 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() { + return + } + syms, err := f.Symbols() if err != nil { t.Fatalf("error reading symbols: %v", err) diff --git a/src/cmd/link/internal/ld/ld_test.go b/src/cmd/link/internal/ld/ld_test.go index 4367c1028e..cdfaadb17d 100644 --- a/src/cmd/link/internal/ld/ld_test.go +++ b/src/cmd/link/internal/ld/ld_test.go @@ -18,8 +18,13 @@ import ( ) func TestUndefinedRelocErrors(t *testing.T) { - t.Parallel() testenv.MustHaveGoBuild(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) + + t.Parallel() dir, err := ioutil.TempDir("", "go-build") if err != nil { t.Fatal(err) diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go index b7611f207c..6729568766 100644 --- a/src/cmd/link/link_test.go +++ b/src/cmd/link/link_test.go @@ -181,6 +181,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 { diff --git a/src/cmd/nm/nm_cgo_test.go b/src/cmd/nm/nm_cgo_test.go index 9a257e0ed2..58f2c24908 100644 --- a/src/cmd/nm/nm_cgo_test.go +++ b/src/cmd/nm/nm_cgo_test.go @@ -15,6 +15,11 @@ func canInternalLink() bool { switch runtime.GOOS { case "aix": return false + case "darwin": + switch runtime.GOARCH { + case "arm64": + return false + } case "dragonfly": return false case "freebsd": diff --git a/src/cmd/nm/nm_test.go b/src/cmd/nm/nm_test.go index 413a4eb06f..382446e9fe 100644 --- a/src/cmd/nm/nm_test.go +++ b/src/cmd/nm/nm_test.go @@ -173,6 +173,9 @@ func testGoExec(t *testing.T, iscgo, isexternallinker bool) { if runtime.GOOS == "windows" { return true } + if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" { + return true // On darwin/arm64 everything is PIE + } return false } diff --git a/src/internal/cpu/cpu_test.go b/src/internal/cpu/cpu_test.go index e09bd2d8b9..919bbd5ed7 100644 --- a/src/internal/cpu/cpu_test.go +++ b/src/internal/cpu/cpu_test.go @@ -15,6 +15,7 @@ import ( ) func TestMinimalFeatures(t *testing.T) { + // TODO: maybe do MustSupportFeatureDectection(t) ? if runtime.GOARCH == "arm64" { switch runtime.GOOS { case "linux", "android": @@ -36,6 +37,13 @@ func MustHaveDebugOptionsSupport(t *testing.T) { } } +func MustSupportFeatureDectection(t *testing.T) { + if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" { + t.Skipf("CPU feature detection is not supported on %s/%s", runtime.GOOS, runtime.GOARCH) + } + // TODO: maybe there are other platforms? +} + func runDebugOptionsTest(t *testing.T, test string, options string) { MustHaveDebugOptionsSupport(t) @@ -58,6 +66,7 @@ func runDebugOptionsTest(t *testing.T, test string, options string) { } func TestDisableAllCapabilities(t *testing.T) { + MustSupportFeatureDectection(t) runDebugOptionsTest(t, "TestAllCapabilitiesDisabled", "cpu.all=off") } diff --git a/src/internal/testenv/testenv.go b/src/internal/testenv/testenv.go index cfb033b2a2..0ee6355ee3 100644 --- a/src/internal/testenv/testenv.go +++ b/src/internal/testenv/testenv.go @@ -43,12 +43,8 @@ func HasGoBuild() bool { return false } switch runtime.GOOS { - case "android", "js": + case "android", "js", "ios": return false - case "darwin", "ios": - if runtime.GOARCH == "arm64" { - return false - } } return true } @@ -122,12 +118,8 @@ func GoTool() (string, error) { // using os.StartProcess or (more commonly) exec.Command. func HasExec() bool { switch runtime.GOOS { - case "js": + case "js", "ios": return false - case "darwin", "ios": - if runtime.GOARCH == "arm64" { - return false - } } return true } @@ -135,10 +127,8 @@ func HasExec() bool { // HasSrc reports whether the entire source tree is available under GOROOT. func HasSrc() bool { switch runtime.GOOS { - case "darwin", "ios": - if runtime.GOARCH == "arm64" { - return false - } + case "ios": + return false } return true } @@ -202,6 +192,32 @@ func MustHaveCGO(t testing.TB) { } } +// CanInternalLink reports whether the current system can link programs with +// internal linking. +// (This is the opposite of cmd/internal/sys.MustLinkExternal. Keep them in sync.) +func CanInternalLink() bool { + switch runtime.GOOS { + case "android": + if runtime.GOARCH != "arm64" { + return false + } + case "darwin", "ios": + if runtime.GOARCH == "arm64" { + return false + } + } + return true +} + +// 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() { + t.Skipf("skipping test: internal linking on %s/%s is not supported", runtime.GOOS, runtime.GOARCH) + } +} + // HasSymlink reports whether the current system can use os.Symlink. func HasSymlink() bool { ok, _ := hasSymlink() diff --git a/src/os/exec/exec_test.go b/src/os/exec/exec_test.go index dafbc64a17..9746722980 100644 --- a/src/os/exec/exec_test.go +++ b/src/os/exec/exec_test.go @@ -605,6 +605,10 @@ func TestExtraFiles(t *testing.T) { testenv.MustHaveExec(t) testenv.MustHaveGoBuild(t) + // This test runs with cgo disabled. External linking needs cgo, so + // it doesn't work if external linking is required. + testenv.MustInternalLink(t) + if runtime.GOOS == "windows" { t.Skipf("skipping test on %q", runtime.GOOS) } diff --git a/src/runtime/crash_test.go b/src/runtime/crash_test.go index eae4f538c1..5e22b7593e 100644 --- a/src/runtime/crash_test.go +++ b/src/runtime/crash_test.go @@ -181,6 +181,9 @@ 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) + output := runTestProg(t, "testprog", name) want := "fatal error: all goroutines are asleep - deadlock!\n" if !strings.HasPrefix(output, want) { @@ -205,6 +208,9 @@ func TestLockedDeadlock2(t *testing.T) { } func TestGoexitDeadlock(t *testing.T) { + // External linking brings in cgo, causing deadlock detection not working. + testenv.MustInternalLink(t) + output := runTestProg(t, "testprog", "GoexitDeadlock") want := "no goroutines (main called runtime.Goexit) - deadlock!" if !strings.Contains(output, want) { @@ -290,6 +296,9 @@ func TestRecursivePanic4(t *testing.T) { } func TestGoexitCrash(t *testing.T) { + // External linking brings in cgo, causing deadlock detection not working. + testenv.MustInternalLink(t) + output := runTestProg(t, "testprog", "GoexitExit") want := "no goroutines (main called runtime.Goexit) - deadlock!" if !strings.Contains(output, want) { @@ -348,6 +357,9 @@ func TestBreakpoint(t *testing.T) { } func TestGoexitInPanic(t *testing.T) { + // External linking brings in cgo, causing deadlock detection not working. + testenv.MustInternalLink(t) + // see issue 8774: this code used to trigger an infinite recursion output := runTestProg(t, "testprog", "GoexitInPanic") want := "fatal error: no goroutines (main called runtime.Goexit) - deadlock!" @@ -412,6 +424,9 @@ func TestPanicAfterGoexit(t *testing.T) { } func TestRecoveredPanicAfterGoexit(t *testing.T) { + // External linking brings in cgo, causing deadlock detection not working. + testenv.MustInternalLink(t) + output := runTestProg(t, "testprog", "RecoveredPanicAfterGoexit") want := "fatal error: no goroutines (main called runtime.Goexit) - deadlock!" if !strings.HasPrefix(output, want) { @@ -420,6 +435,9 @@ func TestRecoveredPanicAfterGoexit(t *testing.T) { } func TestRecoverBeforePanicAfterGoexit(t *testing.T) { + // External linking brings in cgo, causing deadlock detection not working. + testenv.MustInternalLink(t) + t.Parallel() output := runTestProg(t, "testprog", "RecoverBeforePanicAfterGoexit") want := "fatal error: no goroutines (main called runtime.Goexit) - deadlock!" @@ -429,6 +447,9 @@ func TestRecoverBeforePanicAfterGoexit(t *testing.T) { } func TestRecoverBeforePanicAfterGoexit2(t *testing.T) { + // External linking brings in cgo, causing deadlock detection not working. + testenv.MustInternalLink(t) + t.Parallel() output := runTestProg(t, "testprog", "RecoverBeforePanicAfterGoexit2") want := "fatal error: no goroutines (main called runtime.Goexit) - deadlock!" diff --git a/src/runtime/time_test.go b/src/runtime/time_test.go index a8dab7db8e..afd9af2af4 100644 --- a/src/runtime/time_test.go +++ b/src/runtime/time_test.go @@ -20,6 +20,10 @@ func TestFakeTime(t *testing.T) { t.Skip("faketime not supported on windows") } + // Faketime is advanced in checkdead. External linking brings in cgo, + // causing checkdead not working. + testenv.MustInternalLink(t) + t.Parallel() exe, err := buildTestProg(t, "testfaketime", "-tags=faketime") -- cgit v1.3 From 6c0135d3772e710328c751fbc704927931f129ca Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Sun, 11 Oct 2020 16:27:25 -0400 Subject: cmd/go: don't always link in cgo for PIE Internal linking for PIE is now supported and enabled by default on some platforms, for which cgo is not needed. Don't always bring in cgo. Change-Id: I043ed436f0e6a3acbcc53ec543f06e193d614b36 Reviewed-on: https://go-review.googlesource.com/c/go/+/261498 Trust: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- src/cmd/go/internal/load/pkg.go | 3 ++- src/cmd/internal/sys/supported.go | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'src/cmd/internal/sys') diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index 5b3c2f0ff2..db2434260f 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -33,6 +33,7 @@ import ( "cmd/go/internal/search" "cmd/go/internal/str" "cmd/go/internal/trace" + "cmd/internal/sys" ) var IgnoreImports bool // control whether we ignore imports in packages @@ -1968,7 +1969,7 @@ func externalLinkingForced(p *Package) bool { // external linking mode, as of course does // -ldflags=-linkmode=external. External linking mode forces // an import of runtime/cgo. - pieCgo := cfg.BuildBuildmode == "pie" + pieCgo := cfg.BuildBuildmode == "pie" && !sys.InternalLinkPIESupported(cfg.BuildContext.GOOS, cfg.BuildContext.GOARCH) linkmodeExternal := false if p != nil { ldflags := BuildLdflags.For(p) diff --git a/src/cmd/internal/sys/supported.go b/src/cmd/internal/sys/supported.go index 41e5ec1432..55709f3915 100644 --- a/src/cmd/internal/sys/supported.go +++ b/src/cmd/internal/sys/supported.go @@ -115,3 +115,13 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool { return false } } + +func InternalLinkPIESupported(goos, goarch string) bool { + switch goos + "/" + goarch { + case "linux/amd64", "linux/arm64", + "android/arm64", + "windows-amd64", "windows-386", "windows-arm": + return true + } + return false +} -- cgit v1.3 From f46a5b1e4559191363dbd4f510105dd31ae97aaa Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Sun, 11 Oct 2020 15:48:22 -0400 Subject: cmd/link: support PIE internal linking on darwin/amd64 This CL adds support of PIE internal linking on darwin/amd64. This is also preparation for supporting internal linking on darwin/arm64 (macOS), which requires PIE for everything. Updates #38485. Change-Id: I2ed58583dcc102f5e0521982491fc7ba6f2754ed Reviewed-on: https://go-review.googlesource.com/c/go/+/261642 Trust: Cherry Zhang Reviewed-by: Than McIntosh --- misc/cgo/test/issue4029.c | 1 + misc/cgo/test/issue4029.go | 4 + misc/cgo/test/issue4029w.go | 2 +- src/cmd/dist/test.go | 17 +- src/cmd/internal/sys/supported.go | 3 +- src/cmd/link/internal/amd64/asm.go | 65 +++----- src/cmd/link/internal/ld/config.go | 1 + src/cmd/link/internal/ld/lib.go | 6 + src/cmd/link/internal/ld/macho.go | 226 +++++++++++++++++++++++++- src/cmd/link/internal/loader/symbolbuilder.go | 18 ++ 10 files changed, 289 insertions(+), 54 deletions(-) (limited to 'src/cmd/internal/sys') diff --git a/misc/cgo/test/issue4029.c b/misc/cgo/test/issue4029.c index 30646ade02..e6a777fe64 100644 --- a/misc/cgo/test/issue4029.c +++ b/misc/cgo/test/issue4029.c @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. // +build !windows,!static +// +build !darwin !internal_pie #include #include diff --git a/misc/cgo/test/issue4029.go b/misc/cgo/test/issue4029.go index 1bf029d760..8602ce19e2 100644 --- a/misc/cgo/test/issue4029.go +++ b/misc/cgo/test/issue4029.go @@ -3,6 +3,10 @@ // license that can be found in the LICENSE file. // +build !windows,!static +// +build !darwin !internal_pie + +// Excluded in darwin internal linking PIE mode, as dynamic export is not +// supported. package cgotest diff --git a/misc/cgo/test/issue4029w.go b/misc/cgo/test/issue4029w.go index eee33f7010..de0cf2138a 100644 --- a/misc/cgo/test/issue4029w.go +++ b/misc/cgo/test/issue4029w.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build windows static +// +build windows static darwin,internal_pie package cgotest diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index 03e6866d62..94b81613a9 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -964,10 +964,10 @@ func (t *tester) internalLink() bool { func (t *tester) internalLinkPIE() bool { switch goos + "-" + goarch { - case "linux-amd64", "linux-arm64", - "android-arm64": - return true - case "windows-amd64", "windows-386", "windows-arm": + case "darwin-amd64", + "linux-amd64", "linux-arm64", + "android-arm64", + "windows-amd64", "windows-386", "windows-arm": return true } return false @@ -1100,6 +1100,13 @@ func (t *tester) cgoTest(dt *distTest) error { cmd = t.addCmd(dt, "misc/cgo/test", t.goTest(), "-ldflags", "-linkmode=external -s") + if t.supportedBuildmode("pie") { + t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie") + if t.internalLink() && t.internalLinkPIE() { + t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie", "-ldflags=-linkmode=internal", "-tags=internal,internal_pie") + } + } + case "aix-ppc64", "android-arm", "android-arm64", "dragonfly-amd64", @@ -1151,7 +1158,7 @@ func (t *tester) cgoTest(dt *distTest) error { if t.supportedBuildmode("pie") { t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie") if t.internalLink() && t.internalLinkPIE() { - t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie", "-ldflags=-linkmode=internal") + t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie", "-ldflags=-linkmode=internal", "-tags=internal,internal_pie") } t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-buildmode=pie") t.addCmd(dt, "misc/cgo/nocgo", t.goTest(), "-buildmode=pie") diff --git a/src/cmd/internal/sys/supported.go b/src/cmd/internal/sys/supported.go index 55709f3915..07be998035 100644 --- a/src/cmd/internal/sys/supported.go +++ b/src/cmd/internal/sys/supported.go @@ -118,7 +118,8 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool { func InternalLinkPIESupported(goos, goarch string) bool { switch goos + "/" + goarch { - case "linux/amd64", "linux/arm64", + case "darwin/amd64", + "linux/amd64", "linux/arm64", "android/arm64", "windows-amd64", "windows-386", "windows-arm": return true diff --git a/src/cmd/link/internal/amd64/asm.go b/src/cmd/link/internal/amd64/asm.go index e5a6ef51b0..3658ac0be0 100644 --- a/src/cmd/link/internal/amd64/asm.go +++ b/src/cmd/link/internal/amd64/asm.go @@ -76,9 +76,9 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade targType = ldr.SymType(targ) } - switch r.Type() { + switch rt := r.Type(); rt { default: - if r.Type() >= objabi.ElfRelocOffset { + if rt >= objabi.ElfRelocOffset { ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type())) return false } @@ -167,13 +167,24 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_UNSIGNED*2 + 0, objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED*2 + 0, objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_BRANCH*2 + 0: - // TODO: What is the difference between all these? su := ldr.MakeSymbolUpdater(s) su.SetRelocType(rIdx, objabi.R_ADDR) if targType == sym.SDYNIMPORT { ldr.Errorf(s, "unexpected reloc for dynamic symbol %s", ldr.SymName(targ)) } + if target.IsPIE() && target.IsInternal() { + // For internal linking PIE, this R_ADDR relocation cannot + // be resolved statically. We need to generate a dynamic + // relocation. Let the code below handle it. + if rt == objabi.MachoRelocOffset+ld.MACHO_X86_64_RELOC_UNSIGNED*2 { + break + } else { + // MACHO_X86_64_RELOC_SIGNED or MACHO_X86_64_RELOC_BRANCH + // Can this happen? The object is expected to be PIC. + ldr.Errorf(s, "unsupported relocation for PIE: %v", rt) + } + } return true case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_BRANCH*2 + 1: @@ -223,7 +234,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade if targType != sym.SDYNIMPORT { ldr.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", ldr.SymName(targ)) } - ld.AddGotSym(target, ldr, syms, targ, uint32(elf.R_X86_64_GLOB_DAT)) + ld.AddGotSym(target, ldr, syms, targ, 0) su := ldr.MakeSymbolUpdater(s) su.SetRelocType(rIdx, objabi.R_PCREL) su.SetRelocSym(rIdx, syms.GOT) @@ -355,28 +366,15 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade return true } - if target.IsDarwin() && ldr.SymSize(s) == int64(target.Arch.PtrSize) && r.Off() == 0 { + if target.IsDarwin() { // Mach-O relocations are a royal pain to lay out. - // They use a compact stateful bytecode representation - // that is too much bother to deal with. - // Instead, interpret the C declaration - // void *_Cvar_stderr = &stderr; - // as making _Cvar_stderr the name of a GOT entry - // for stderr. This is separate from the usual GOT entry, - // just in case the C code assigns to the variable, - // and of course it only works for single pointers, - // but we only need to support cgo and that's all it needs. - ld.Adddynsym(ldr, target, syms, targ) - - got := ldr.MakeSymbolUpdater(syms.GOT) - su := ldr.MakeSymbolUpdater(s) - su.SetType(got.Type()) - got.AddInteriorSym(s) - su.SetValue(got.Size()) - got.AddUint64(target.Arch, 0) - leg := ldr.MakeSymbolUpdater(syms.LinkEditGOT) - leg.AddUint32(target.Arch, uint32(ldr.SymDynid(targ))) - su.SetRelocType(rIdx, objabi.ElfRelocOffset) // ignore during relocsym + // They use a compact stateful bytecode representation. + // Here we record what are needed and encode them later. + ld.MachoAddRebase(s, int64(r.Off())) + // Not mark r done here. So we still apply it statically, + // so in the file content we'll also have the right offset + // to the relocation target. So it can be examined statically + // (e.g. go version). return true } } @@ -627,26 +625,16 @@ func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade ldr.SetPlt(s, int32(plt.Size()-16)) } else if target.IsDarwin() { - // To do lazy symbol lookup right, we're supposed - // to tell the dynamic loader which library each - // symbol comes from and format the link info - // section just so. I'm too lazy (ha!) to do that - // so for now we'll just use non-lazy pointers, - // which don't need to be told which library to use. - // - // https://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html - // has details about what we're avoiding. - - ld.AddGotSym(target, ldr, syms, s, uint32(elf.R_X86_64_GLOB_DAT)) - plt := ldr.MakeSymbolUpdater(syms.PLT) + ld.AddGotSym(target, ldr, syms, s, 0) sDynid := ldr.SymDynid(s) lep := ldr.MakeSymbolUpdater(syms.LinkEditPLT) lep.AddUint32(target.Arch, uint32(sDynid)) - // jmpq *got+size(IP) + plt := ldr.MakeSymbolUpdater(syms.PLT) ldr.SetPlt(s, int32(plt.Size())) + // jmpq *got+size(IP) plt.AddUint8(0xff) plt.AddUint8(0x25) plt.AddPCRelPlus(target.Arch, syms.GOT, int64(ldr.SymGot(s))) @@ -654,6 +642,7 @@ func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade ldr.Errorf(s, "addpltsym: unsupported binary format") } } + func tlsIEtoLE(P []byte, off, size int) { // Transform the PC-relative instruction into a constant load. // That is, diff --git a/src/cmd/link/internal/ld/config.go b/src/cmd/link/internal/ld/config.go index aaf74b58de..c680d11c1d 100644 --- a/src/cmd/link/internal/ld/config.go +++ b/src/cmd/link/internal/ld/config.go @@ -222,6 +222,7 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) { switch objabi.GOOS + "/" + objabi.GOARCH { case "linux/amd64", "linux/arm64", "android/arm64": case "windows/386", "windows/amd64", "windows/arm": + case "darwin/amd64": default: // Internal linking does not support TLS_IE. return true, "buildmode=pie" diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 5fe028d321..8d04973fcf 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -2526,6 +2526,12 @@ func AddGotSym(target *Target, ldr *loader.Loader, syms *ArchSyms, s loader.Sym, } else if target.IsDarwin() { leg := ldr.MakeSymbolUpdater(syms.LinkEditGOT) leg.AddUint32(target.Arch, uint32(ldr.SymDynid(s))) + 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) + } } else { ldr.Errorf(s, "addgotsym: unsupported binary format") } diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go index eab6537c75..a19a4afd9a 100644 --- a/src/cmd/link/internal/ld/macho.go +++ b/src/cmd/link/internal/ld/macho.go @@ -118,6 +118,8 @@ const ( MH_EXECUTE = 0x2 MH_NOUNDEFS = 0x1 + MH_DYLDLINK = 0x4 + MH_PIE = 0x200000 ) const ( @@ -193,6 +195,56 @@ const ( PLATFORM_BRIDGEOS MachoPlatform = 5 ) +// rebase table opcode +const ( + REBASE_TYPE_POINTER = 1 + REBASE_TYPE_TEXT_ABSOLUTE32 = 2 + REBASE_TYPE_TEXT_PCREL32 = 3 + + REBASE_OPCODE_MASK = 0xF0 + REBASE_IMMEDIATE_MASK = 0x0F + REBASE_OPCODE_DONE = 0x00 + REBASE_OPCODE_SET_TYPE_IMM = 0x10 + REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB = 0x20 + REBASE_OPCODE_ADD_ADDR_ULEB = 0x30 + REBASE_OPCODE_ADD_ADDR_IMM_SCALED = 0x40 + REBASE_OPCODE_DO_REBASE_IMM_TIMES = 0x50 + REBASE_OPCODE_DO_REBASE_ULEB_TIMES = 0x60 + REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB = 0x70 + REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB = 0x80 +) + +// bind table opcode +const ( + BIND_TYPE_POINTER = 1 + BIND_TYPE_TEXT_ABSOLUTE32 = 2 + BIND_TYPE_TEXT_PCREL32 = 3 + + BIND_SPECIAL_DYLIB_SELF = 0 + BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE = -1 + BIND_SPECIAL_DYLIB_FLAT_LOOKUP = -2 + BIND_SPECIAL_DYLIB_WEAK_LOOKUP = -3 + + BIND_OPCODE_MASK = 0xF0 + BIND_IMMEDIATE_MASK = 0x0F + BIND_OPCODE_DONE = 0x00 + BIND_OPCODE_SET_DYLIB_ORDINAL_IMM = 0x10 + BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB = 0x20 + BIND_OPCODE_SET_DYLIB_SPECIAL_IMM = 0x30 + BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM = 0x40 + BIND_OPCODE_SET_TYPE_IMM = 0x50 + BIND_OPCODE_SET_ADDEND_SLEB = 0x60 + BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB = 0x70 + BIND_OPCODE_ADD_ADDR_ULEB = 0x80 + BIND_OPCODE_DO_BIND = 0x90 + BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB = 0xA0 + BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED = 0xB0 + BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB = 0xC0 + BIND_OPCODE_THREADED = 0xD0 + BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB = 0x00 + BIND_SUBOPCODE_THREADED_APPLY = 0x01 +) + // Mach-O file writing // https://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html @@ -279,7 +331,7 @@ var dylib []string var linkoff int64 -func machowrite(arch *sys.Arch, out *OutBuf, linkmode LinkMode) int { +func machowrite(ctxt *Link, arch *sys.Arch, out *OutBuf, linkmode LinkMode) int { o1 := out.Offset() loadsize := 4 * 4 * ndebug @@ -308,11 +360,14 @@ func machowrite(arch *sys.Arch, out *OutBuf, linkmode LinkMode) int { } out.Write32(uint32(len(load)) + uint32(nseg) + uint32(ndebug)) out.Write32(uint32(loadsize)) + flags := uint32(0) if nkind[SymKindUndef] == 0 { - out.Write32(MH_NOUNDEFS) /* flags - no undefines */ - } else { - out.Write32(0) /* flags */ + flags |= MH_NOUNDEFS + } + if ctxt.IsPIE() && linkmode == LinkInternal { + flags |= MH_PIE | MH_DYLDLINK } + out.Write32(flags) /* flags */ if arch.PtrSize == 8 { out.Write32(0) /* reserved */ } @@ -712,15 +767,17 @@ func asmbMacho(ctxt *Link) { s2 := ldr.SymSize(ctxt.ArchSyms.LinkEditPLT) s3 := ldr.SymSize(ctxt.ArchSyms.LinkEditGOT) s4 := ldr.SymSize(ldr.Lookup(".machosymstr", 0)) + s5 := ldr.SymSize(ldr.Lookup(".machorebase", 0)) + s6 := ldr.SymSize(ldr.Lookup(".machobind", 0)) if ctxt.LinkMode != LinkExternal { ms := newMachoSeg("__LINKEDIT", 0) ms.vaddr = uint64(Rnd(int64(Segdata.Vaddr+Segdata.Length), int64(*FlagRound))) - ms.vsize = uint64(s1) + uint64(s2) + uint64(s3) + uint64(s4) + ms.vsize = uint64(s1 + s2 + s3 + s4 + s5 + s6) ms.fileoffset = uint64(linkoff) ms.filesize = ms.vsize - ms.prot1 = 7 - ms.prot2 = 3 + ms.prot1 = 1 + ms.prot2 = 1 } ml := newMachoLoad(ctxt.Arch, LC_SYMTAB, 4) @@ -745,9 +802,23 @@ func asmbMacho(ctxt *Link) { stringtouint32(ml.data[4:], lib) } } + + if ctxt.LinkMode != LinkExternal && ctxt.IsPIE() { + ml := newMachoLoad(ctxt.Arch, LC_DYLD_INFO_ONLY, 10) + ml.data[0] = uint32(linkoff + s1 + s2 + s3 + s4) // rebase off + ml.data[1] = uint32(s5) // rebase size + ml.data[2] = uint32(linkoff + s1 + s2 + s3 + s4 + s5) // bind off + ml.data[3] = uint32(s6) // bind size + ml.data[4] = 0 // weak bind off + ml.data[5] = 0 // weak bind size + ml.data[6] = 0 // lazy bind off + ml.data[7] = 0 // lazy bind size + ml.data[8] = 0 // export + ml.data[9] = 0 // export size + } } - a := machowrite(ctxt.Arch, ctxt.Out, ctxt.LinkMode) + a := machowrite(ctxt, ctxt.Arch, ctxt.Out, ctxt.LinkMode) if int32(a) > HEADR { Exitf("HEADR too small: %d > %d", a, HEADR) } @@ -989,6 +1060,8 @@ func machodysymtab(ctxt *Link) { func doMachoLink(ctxt *Link) int64 { machosymtab(ctxt) + machoDyldInfo(ctxt) + ldr := ctxt.loader // write data that will be linkedit section @@ -996,6 +1069,8 @@ func doMachoLink(ctxt *Link) int64 { s2 := ctxt.ArchSyms.LinkEditPLT s3 := ctxt.ArchSyms.LinkEditGOT s4 := ldr.Lookup(".machosymstr", 0) + s5 := ldr.Lookup(".machorebase", 0) + s6 := ldr.Lookup(".machobind", 0) // Force the linkedit section to end on a 16-byte // boundary. This allows pure (non-cgo) Go binaries @@ -1019,7 +1094,7 @@ func doMachoLink(ctxt *Link) int64 { s4b.AddUint8(0) } - size := int(ldr.SymSize(s1) + ldr.SymSize(s2) + ldr.SymSize(s3) + ldr.SymSize(s4)) + size := int(ldr.SymSize(s1) + ldr.SymSize(s2) + ldr.SymSize(s3) + ldr.SymSize(s4) + ldr.SymSize(s5) + ldr.SymSize(s6)) if size > 0 { linkoff = Rnd(int64(uint64(HEADR)+Segtext.Length), int64(*FlagRound)) + Rnd(int64(Segrelrodata.Filelen), int64(*FlagRound)) + Rnd(int64(Segdata.Filelen), int64(*FlagRound)) + Rnd(int64(Segdwarf.Filelen), int64(*FlagRound)) @@ -1029,6 +1104,8 @@ func doMachoLink(ctxt *Link) int64 { ctxt.Out.Write(ldr.Data(s2)) ctxt.Out.Write(ldr.Data(s3)) ctxt.Out.Write(ldr.Data(s4)) + ctxt.Out.Write(ldr.Data(s5)) + ctxt.Out.Write(ldr.Data(s6)) } return Rnd(int64(size), int64(*FlagRound)) @@ -1172,3 +1249,134 @@ func peekMachoPlatform(m *macho.File) (*MachoPlatformLoad, error) { } return nil, nil } + +// A rebase entry tells the dynamic linker the data at sym+off needs to be +// relocated when the in-memory image moves. (This is somewhat like, say, +// ELF R_X86_64_RELATIVE). +// For now, the only kind of entry we support is that the data is an absolute +// address. That seems all we need. +// In the binary it uses a compact stateful bytecode encoding. So we record +// entries as we go and build the table at the end. +type machoRebaseRecord struct { + sym loader.Sym + off int64 +} + +var machorebase []machoRebaseRecord + +func MachoAddRebase(s loader.Sym, off int64) { + machorebase = append(machorebase, machoRebaseRecord{s, off}) +} + +// A bind entry tells the dynamic linker the data at GOT+off should be bound +// to the address of the target symbol, which is a dynamic import. +// For now, the only kind of entry we support is that the data is an absolute +// address, and the source symbol is always the GOT. That seems all we need. +// In the binary it uses a compact stateful bytecode encoding. So we record +// entries as we go and build the table at the end. +type machoBindRecord struct { + off int64 + targ loader.Sym +} + +var machobind []machoBindRecord + +func MachoAddBind(off int64, targ loader.Sym) { + machobind = append(machobind, machoBindRecord{off, targ}) +} + +// Generate data for the dynamic linker, used in LC_DYLD_INFO_ONLY load command. +// See mach-o/loader.h, struct dyld_info_command, for the encoding. +// e.g. https://opensource.apple.com/source/xnu/xnu-6153.81.5/EXTERNAL_HEADERS/mach-o/loader.h +func machoDyldInfo(ctxt *Link) { + ldr := ctxt.loader + rebase := ldr.CreateSymForUpdate(".machorebase", 0) + bind := ldr.CreateSymForUpdate(".machobind", 0) + + if !(ctxt.IsPIE() && ctxt.IsInternal()) { + return + } + + segId := func(seg *sym.Segment) uint8 { + switch seg { + case &Segtext: + return 1 + case &Segrelrodata: + return 2 + case &Segdata: + if Segrelrodata.Length > 0 { + return 3 + } + return 2 + } + panic("unknown segment") + } + + dylibId := func(s loader.Sym) int { + slib := ldr.SymDynimplib(s) + for i, lib := range dylib { + if lib == slib { + return i + 1 + } + } + return BIND_SPECIAL_DYLIB_FLAT_LOOKUP // don't know where it is from + } + + // Rebase table. + // TODO: use more compact encoding. The encoding is stateful, and + // we can use delta encoding. + rebase.AddUint8(REBASE_OPCODE_SET_TYPE_IMM | REBASE_TYPE_POINTER) + for _, r := range machorebase { + seg := ldr.SymSect(r.sym).Seg + off := uint64(ldr.SymValue(r.sym)+r.off) - seg.Vaddr + rebase.AddUint8(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segId(seg)) + rebase.AddUleb(off) + + rebase.AddUint8(REBASE_OPCODE_DO_REBASE_IMM_TIMES | 1) + } + rebase.AddUint8(REBASE_OPCODE_DONE) + sz := Rnd(rebase.Size(), 8) + rebase.Grow(sz) + rebase.SetSize(sz) + + // Bind table. + // TODO: compact encoding, as above. + // TODO: lazy binding? + got := ctxt.GOT + seg := ldr.SymSect(got).Seg + gotAddr := ldr.SymValue(got) + bind.AddUint8(BIND_OPCODE_SET_TYPE_IMM | BIND_TYPE_POINTER) + for _, r := range machobind { + off := uint64(gotAddr+r.off) - seg.Vaddr + bind.AddUint8(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segId(seg)) + bind.AddUleb(off) + + d := dylibId(r.targ) + if d > 0 && d < 128 { + bind.AddUint8(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | uint8(d)&0xf) + } else if d >= 128 { + bind.AddUint8(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB) + bind.AddUleb(uint64(d)) + } else { // d <= 0 + bind.AddUint8(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | uint8(d)&0xf) + } + + bind.AddUint8(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM) + // target symbol name as a C string, with _ prefix + bind.AddUint8('_') + bind.Addstring(ldr.SymExtname(r.targ)) + + bind.AddUint8(BIND_OPCODE_DO_BIND) + } + bind.AddUint8(BIND_OPCODE_DONE) + sz = Rnd(bind.Size(), 16) // make it 16-byte aligned, see the comment in doMachoLink + bind.Grow(sz) + bind.SetSize(sz) + + // TODO: export table. + // The symbols names are encoded as a trie. I'm really too lazy to do that + // for now. + // Without it, the symbols are not dynamically exported, so they cannot be + // e.g. dlsym'd. But internal linking is not the default in that case, so + // it is fine. +} diff --git a/src/cmd/link/internal/loader/symbolbuilder.go b/src/cmd/link/internal/loader/symbolbuilder.go index c0c723d7f0..5d37da8ac6 100644 --- a/src/cmd/link/internal/loader/symbolbuilder.go +++ b/src/cmd/link/internal/loader/symbolbuilder.go @@ -420,3 +420,21 @@ func (sb *SymbolBuilder) MakeWritable() { sb.l.SetAttrReadOnly(sb.symIdx, false) } } + +func (sb *SymbolBuilder) AddUleb(v uint64) { + if v < 128 { // common case: 1 byte + sb.AddUint8(uint8(v)) + return + } + for { + c := uint8(v & 0x7f) + v >>= 7 + if v != 0 { + c |= 0x80 + } + sb.AddUint8(c) + if c&0x80 == 0 { + break + } + } +} -- cgit v1.3 From e4ec30965b9ca629922e83b8d335224ae4bdf062 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Mon, 12 Oct 2020 13:44:21 -0400 Subject: cmd/link: support internal linking on darwin/arm64 Add support of internal linking on darwin/arm64 (macOS). Still incomplete. Pure Go binaries work. Cgo doesn't. TLS is not set up when cgo is not used (as before) (so asynchronous preemption is not enabled). Internal linking is not enabled by default but can be requested via -ldflags=-linkmode=internal. Updates #38485. Change-Id: I1e0c81b6028edcb1ac26dcdafeb9bb3f788cf732 Reviewed-on: https://go-review.googlesource.com/c/go/+/261643 Trust: Cherry Zhang Reviewed-by: Than McIntosh --- src/cmd/go/internal/load/pkg.go | 7 +++--- src/cmd/internal/sys/supported.go | 2 +- src/cmd/link/internal/arm64/asm.go | 49 ++++++++++++++++++++++++++++++++++++++ src/cmd/link/internal/arm64/obj.go | 2 +- src/cmd/link/internal/ld/config.go | 13 ++++++++-- src/cmd/link/internal/ld/macho.go | 8 +++---- src/cmd/link/internal/ld/main.go | 2 +- src/runtime/rt0_darwin_arm64.s | 20 +++++++--------- 8 files changed, 79 insertions(+), 24 deletions(-) (limited to 'src/cmd/internal/sys') diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index db2434260f..f73b79d089 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -1948,6 +1948,10 @@ func LinkerDeps(p *Package) []string { // externalLinkingForced reports whether external linking is being // forced even for programs that do not use cgo. func externalLinkingForced(p *Package) bool { + if !cfg.BuildContext.CgoEnabled { + return false + } + // Some targets must use external linking even inside GOROOT. switch cfg.BuildContext.GOOS { case "android": @@ -1960,9 +1964,6 @@ func externalLinkingForced(p *Package) bool { } } - if !cfg.BuildContext.CgoEnabled { - return false - } // Currently build modes c-shared, pie (on systems that do not // support PIE with internal linking mode (currently all // systems: issue #18968)), plugin, and -linkshared force diff --git a/src/cmd/internal/sys/supported.go b/src/cmd/internal/sys/supported.go index 07be998035..c433a872be 100644 --- a/src/cmd/internal/sys/supported.go +++ b/src/cmd/internal/sys/supported.go @@ -118,7 +118,7 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool { func InternalLinkPIESupported(goos, goarch string) bool { switch goos + "/" + goarch { - case "darwin/amd64", + case "darwin/amd64", "darwin/arm64", "linux/amd64", "linux/arm64", "android/arm64", "windows-amd64", "windows-386", "windows-arm": diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go index 1d2aa591d7..7bf41c93a6 100644 --- a/src/cmd/link/internal/arm64/asm.go +++ b/src/cmd/link/internal/arm64/asm.go @@ -219,6 +219,15 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade // External linker will do this relocation. return true } + if target.IsDarwin() { // XXX why we don't need this for ELF? + // Internal linking. + // Build a PLT entry and change the relocation target to that entry. + addpltsym(target, ldr, syms, targ) + su := ldr.MakeSymbolUpdater(s) + su.SetRelocSym(rIdx, syms.PLT) + su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ))) + return true + } case objabi.R_ADDR: if ldr.SymType(s) == sym.STEXT && target.IsElf() { @@ -313,6 +322,18 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade // (e.g. go version). return true } + + if target.IsDarwin() { + // 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. + ld.MachoAddRebase(s, int64(r.Off())) + // Not mark r done here. So we still apply it statically, + // so in the file content we'll also have the right offset + // to the relocation target. So it can be examined statically + // (e.g. go version). + return true + } } return false } @@ -812,6 +833,34 @@ func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade rela.AddUint64(target.Arch, 0) ldr.SetPlt(s, int32(plt.Size()-16)) + } else if target.IsDarwin() { + ld.AddGotSym(target, ldr, syms, s, 0) + + sDynid := ldr.SymDynid(s) + lep := ldr.MakeSymbolUpdater(syms.LinkEditPLT) + lep.AddUint32(target.Arch, uint32(sDynid)) + + plt := ldr.MakeSymbolUpdater(syms.PLT) + ldr.SetPlt(s, int32(plt.Size())) + + // adrp x16, GOT + plt.AddUint32(target.Arch, 0x90000010) + r, _ := plt.AddRel(objabi.R_ARM64_GOT) + r.SetOff(int32(plt.Size() - 4)) + r.SetSiz(4) + r.SetSym(syms.GOT) + r.SetAdd(int64(ldr.SymGot(s))) + + // ldr x17, [x16, ] + plt.AddUint32(target.Arch, 0xf9400211) + r, _ = plt.AddRel(objabi.R_ARM64_GOT) + r.SetOff(int32(plt.Size() - 4)) + r.SetSiz(4) + r.SetSym(syms.GOT) + r.SetAdd(int64(ldr.SymGot(s))) + + // br x17 + plt.AddUint32(target.Arch, 0xd61f0220) } else { ldr.Errorf(s, "addpltsym: unsupported binary format") } diff --git a/src/cmd/link/internal/arm64/obj.go b/src/cmd/link/internal/arm64/obj.go index a980cfee52..ab3dfd99f7 100644 --- a/src/cmd/link/internal/arm64/obj.go +++ b/src/cmd/link/internal/arm64/obj.go @@ -102,7 +102,7 @@ func archinit(ctxt *ld.Link) { case objabi.Hdarwin: /* apple MACH */ ld.HEADR = ld.INITIAL_MACHO_HEADR if *ld.FlagTextAddr == -1 { - *ld.FlagTextAddr = 4096 + int64(ld.HEADR) + *ld.FlagTextAddr = 1<<32 + int64(ld.HEADR) } if *ld.FlagRound == -1 { *ld.FlagRound = 16384 // 16K page alignment diff --git a/src/cmd/link/internal/ld/config.go b/src/cmd/link/internal/ld/config.go index c680d11c1d..f55e4fc027 100644 --- a/src/cmd/link/internal/ld/config.go +++ b/src/cmd/link/internal/ld/config.go @@ -35,6 +35,10 @@ func (mode *BuildMode) Set(s string) error { default: return fmt.Errorf("invalid buildmode: %q", s) case "exe": + if objabi.GOOS == "darwin" && objabi.GOARCH == "arm64" { + *mode = BuildModePIE // On darwin/arm64 everything is PIE. + break + } *mode = BuildModeExe case "pie": switch objabi.GOOS { @@ -187,7 +191,7 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) { }() } - if sys.MustLinkExternal(objabi.GOOS, objabi.GOARCH) { + if sys.MustLinkExternal(objabi.GOOS, objabi.GOARCH) && !(objabi.GOOS == "darwin" && objabi.GOARCH == "arm64") { // XXX allow internal linking for darwin/arm64 but not change the default return true, fmt.Sprintf("%s/%s requires external linking", objabi.GOOS, objabi.GOARCH) } @@ -204,6 +208,9 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) { if iscgo && objabi.GOOS == "android" { return true, objabi.GOOS + " does not support internal cgo" } + if iscgo && objabi.GOOS == "darwin" && objabi.GOARCH == "arm64" { + return true, objabi.GOOS + "/" + objabi.GOARCH + " does not support internal cgo" + } // When the race flag is set, the LLVM tsan relocatable file is linked // into the final binary, which means external linking is required because @@ -222,7 +229,7 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) { switch objabi.GOOS + "/" + objabi.GOARCH { case "linux/amd64", "linux/arm64", "android/arm64": case "windows/386", "windows/amd64", "windows/arm": - case "darwin/amd64": + case "darwin/amd64", "darwin/arm64": default: // Internal linking does not support TLS_IE. return true, "buildmode=pie" @@ -263,6 +270,8 @@ func determineLinkMode(ctxt *Link) { default: if extNeeded || (iscgo && externalobj) { ctxt.LinkMode = LinkExternal + } else if ctxt.IsDarwin() && ctxt.IsARM64() { + ctxt.LinkMode = LinkExternal // default to external linking for now } else { ctxt.LinkMode = LinkInternal } diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go index a19a4afd9a..155769c48f 100644 --- a/src/cmd/link/internal/ld/macho.go +++ b/src/cmd/link/internal/ld/macho.go @@ -751,11 +751,9 @@ func asmbMacho(ctxt *Link) { ml.data[2+32+1] = uint32(Entryvalue(ctxt) >> 32) case sys.ARM64: - ml := newMachoLoad(ctxt.Arch, LC_UNIXTHREAD, 68+2) - ml.data[0] = 6 /* thread type */ - ml.data[1] = 68 /* word count */ - ml.data[2+64] = uint32(Entryvalue(ctxt)) /* start pc */ - ml.data[2+64+1] = uint32(Entryvalue(ctxt) >> 32) + ml := newMachoLoad(ctxt.Arch, LC_MAIN, 4) + ml.data[0] = uint32(uint64(Entryvalue(ctxt)) - (Segtext.Vaddr - uint64(HEADR))) + ml.data[1] = uint32((uint64(Entryvalue(ctxt)) - (Segtext.Vaddr - uint64(HEADR))) >> 32) } } diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go index 50c643748c..3f7370b636 100644 --- a/src/cmd/link/internal/ld/main.go +++ b/src/cmd/link/internal/ld/main.go @@ -169,7 +169,7 @@ func Main(arch *sys.Arch, theArch Arch) { startProfile() if ctxt.BuildMode == BuildModeUnset { - ctxt.BuildMode = BuildModeExe + ctxt.BuildMode.Set("exe") } if ctxt.BuildMode != BuildModeShared && flag.NArg() != 1 { diff --git a/src/runtime/rt0_darwin_arm64.s b/src/runtime/rt0_darwin_arm64.s index e3972f4924..0040361215 100644 --- a/src/runtime/rt0_darwin_arm64.s +++ b/src/runtime/rt0_darwin_arm64.s @@ -4,11 +4,14 @@ #include "textflag.h" -// No need for _rt0_arm64_darwin as darwin/arm64 only -// supports external linking. TEXT _rt0_arm64_darwin(SB),NOSPLIT|NOFRAME,$0 - MOVD $42, R0 - BL libc_exit(SB) + MOVD $runtime·rt0_go(SB), R2 + BL (R2) +exit: + MOVD $0, R0 + MOVD $1, R16 // sys_exit + SVC $0x80 + B exit // When linking with -buildmode=c-archive or -buildmode=c-shared, // this symbol is called from a global initialization function. @@ -86,11 +89,6 @@ GLOBL _rt0_arm64_darwin_lib_argc<>(SB),NOPTR, $8 DATA _rt0_arm64_darwin_lib_argv<>(SB)/8, $0 GLOBL _rt0_arm64_darwin_lib_argv<>(SB),NOPTR, $8 +// external linking entry point. TEXT main(SB),NOSPLIT|NOFRAME,$0 - MOVD $runtime·rt0_go(SB), R2 - BL (R2) -exit: - MOVD $0, R0 - MOVD $1, R16 // sys_exit - SVC $0x80 - B exit + JMP _rt0_arm64_darwin(SB) -- cgit v1.3 From 431d58da69e8c36d654876e7808f971c5667649c Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Tue, 20 Oct 2020 11:01:46 +0200 Subject: all: add GOOS=ios GOARCH=amd64 target for the ios simulator The Go toolchain has supported the simulator for years, but always in buildmode=c-archive which is intrinsically externally linked and PIE. This CL moves that support from GOOS=darwin GOARCH=amd64 -tags=ios to just GOOS=ios GOARCH=amd64 to match the change for iOS devices. This change also forces external linking and defaults to buildmode=pie to support Go binaries in the default buildmode to run on the simulator. CL 255257 added the necessary support to the exec wrapper. Updates #38485 Fixes #42100 Change-Id: I6e6ee0e8d421be53b31e3d403880e5b9b880d031 Reviewed-on: https://go-review.googlesource.com/c/go/+/263798 Reviewed-by: Austin Clements Reviewed-by: Cherry Zhang Trust: Elias Naur --- src/cmd/dist/build.go | 1 + src/cmd/go/internal/load/pkg.go | 4 +++- src/cmd/go/internal/work/init.go | 5 ++++- src/cmd/internal/sys/supported.go | 1 + src/cmd/link/internal/ld/config.go | 8 +------- src/runtime/rt0_ios_amd64.s | 14 ++++++++++++++ 6 files changed, 24 insertions(+), 9 deletions(-) create mode 100644 src/runtime/rt0_ios_amd64.s (limited to 'src/cmd/internal/sys') diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go index d902addb0c..e46c33522d 100644 --- a/src/cmd/dist/build.go +++ b/src/cmd/dist/build.go @@ -1557,6 +1557,7 @@ var cgoEnabled = map[string]bool{ "android/arm": true, "android/arm64": true, "ios/arm64": true, + "ios/amd64": true, "js/wasm": false, "netbsd/386": true, "netbsd/amd64": true, diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index f07bd3e075..29709a6dd3 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -1966,7 +1966,9 @@ func externalLinkingForced(p *Package) bool { if cfg.BuildContext.GOARCH != "arm64" { return true } - case "darwin", "ios": + case "ios": + return true + case "darwin": if cfg.BuildContext.GOARCH == "arm64" { return true } diff --git a/src/cmd/go/internal/work/init.go b/src/cmd/go/internal/work/init.go index 81c4fb7465..d65c076c6a 100644 --- a/src/cmd/go/internal/work/init.go +++ b/src/cmd/go/internal/work/init.go @@ -168,7 +168,10 @@ func buildModeInit() { ldBuildmode = "pie" case "windows": ldBuildmode = "pie" - case "darwin", "ios": + case "ios": + codegenArg = "-shared" + ldBuildmode = "pie" + case "darwin": switch cfg.Goarch { case "arm64": codegenArg = "-shared" diff --git a/src/cmd/internal/sys/supported.go b/src/cmd/internal/sys/supported.go index c433a872be..ccc5b2245b 100644 --- a/src/cmd/internal/sys/supported.go +++ b/src/cmd/internal/sys/supported.go @@ -88,6 +88,7 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool { "android/amd64", "android/arm", "android/arm64", "android/386", "freebsd/amd64", "darwin/amd64", "darwin/arm64", + "ios/amd64", "ios/arm64", "aix/ppc64", "windows/386", "windows/amd64", "windows/arm": return true diff --git a/src/cmd/link/internal/ld/config.go b/src/cmd/link/internal/ld/config.go index a54b96dd5d..54a94cebba 100644 --- a/src/cmd/link/internal/ld/config.go +++ b/src/cmd/link/internal/ld/config.go @@ -42,13 +42,7 @@ func (mode *BuildMode) Set(s string) error { *mode = BuildModeExe case "pie": switch objabi.GOOS { - case "aix", "android", "linux", "windows": - case "darwin": - switch objabi.GOARCH { - case "amd64", "arm64": - default: - return badmode() - } + case "aix", "android", "linux", "windows", "darwin", "ios": case "freebsd": switch objabi.GOARCH { case "amd64": diff --git a/src/runtime/rt0_ios_amd64.s b/src/runtime/rt0_ios_amd64.s new file mode 100644 index 0000000000..c6990324f4 --- /dev/null +++ b/src/runtime/rt0_ios_amd64.s @@ -0,0 +1,14 @@ +// Copyright 2020 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. + +#include "textflag.h" + +// internal linking executable entry point. +// ios/amd64 only supports external linking. +TEXT _rt0_amd64_ios(SB),NOSPLIT|NOFRAME,$0 + UNDEF + +// library entry point. +TEXT _rt0_amd64_ios_lib(SB),NOSPLIT|NOFRAME,$0 + JMP _rt0_amd64_darwin_lib(SB) -- cgit v1.3 From 4f2d2134764b0b7654105ac2d6f75a75cdc1de56 Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Tue, 2 Jun 2020 23:34:06 +1000 Subject: cmd/compile,cmd/internal/sys: enable additional build modes on linux/riscv64 Enable c-archive, c-shared, shared and pie build modes for linux/riscv64. Change-Id: I15a8a51b84dbbb82a5b6592aec84a7f09f0cc37f Reviewed-on: https://go-review.googlesource.com/c/go/+/263457 Trust: Joel Sing Reviewed-by: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Go Bot --- src/cmd/compile/internal/gc/main.go | 2 +- src/cmd/dist/test.go | 8 ++++---- src/cmd/go/go_test.go | 2 +- src/cmd/internal/sys/supported.go | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) (limited to 'src/cmd/internal/sys') diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index 4b401f2aa4..0b65e8a0b4 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -130,7 +130,7 @@ func hidePanic() { // supportsDynlink reports whether or not the code generator for the given // architecture supports the -shared and -dynlink flags. func supportsDynlink(arch *sys.Arch) bool { - return arch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.I386, sys.PPC64, sys.S390X) + return arch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.I386, sys.PPC64, sys.RISCV64, sys.S390X) } // timing data for compiler phases diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index dbe55a7c38..622d0cee83 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -983,7 +983,7 @@ func (t *tester) supportedBuildmode(mode string) bool { switch pair { case "aix-ppc64", "darwin-amd64", "darwin-arm64", "ios-arm64", - "linux-amd64", "linux-386", "linux-ppc64le", "linux-s390x", + "linux-amd64", "linux-386", "linux-ppc64le", "linux-riscv64", "linux-s390x", "freebsd-amd64", "windows-amd64", "windows-386": return true @@ -991,7 +991,7 @@ func (t *tester) supportedBuildmode(mode string) bool { return false case "c-shared": switch pair { - case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-s390x", + case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-riscv64", "linux-s390x", "darwin-amd64", "darwin-arm64", "freebsd-amd64", "android-arm", "android-arm64", "android-386", @@ -1001,7 +1001,7 @@ func (t *tester) supportedBuildmode(mode string) bool { return false case "shared": switch pair { - case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-s390x": + case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-riscv64", "linux-s390x": return true } return false @@ -1020,7 +1020,7 @@ func (t *tester) supportedBuildmode(mode string) bool { case "pie": switch pair { case "aix/ppc64", - "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-s390x", + "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-riscv64", "linux-s390x", "android-amd64", "android-arm", "android-arm64", "android-386": return true case "darwin-amd64", "darwin-arm64": diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index e9c26d161a..d1bd516a5d 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -2070,7 +2070,7 @@ func TestBuildmodePIE(t *testing.T) { platform := fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH) switch platform { - case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x", + case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/riscv64", "linux/s390x", "android/amd64", "android/arm", "android/arm64", "android/386", "freebsd/amd64", "windows/386", "windows/amd64", "windows/arm": diff --git a/src/cmd/internal/sys/supported.go b/src/cmd/internal/sys/supported.go index ccc5b2245b..1d813bbb47 100644 --- a/src/cmd/internal/sys/supported.go +++ b/src/cmd/internal/sys/supported.go @@ -67,7 +67,7 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool { case "c-shared": switch platform { - case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/ppc64le", "linux/s390x", + case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/ppc64le", "linux/riscv64", "linux/s390x", "android/amd64", "android/arm", "android/arm64", "android/386", "freebsd/amd64", "darwin/amd64", "darwin/arm64", @@ -84,7 +84,7 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool { case "pie": switch platform { - case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x", + case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/riscv64", "linux/s390x", "android/amd64", "android/arm", "android/arm64", "android/386", "freebsd/amd64", "darwin/amd64", "darwin/arm64", @@ -97,7 +97,7 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool { case "shared": switch platform { - case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x": + case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/riscv64", "linux/s390x": return true } return false -- cgit v1.3 From b85c2dd56c4ecc7bf445bd1615467ecd38598eee Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Sat, 24 Oct 2020 20:58:38 -0400 Subject: cmd/link: enable internal linking by default on darwin/arm64 With previous CLs, internal linking without cgo should work well. Enable it by default. And stop always requiring cgo. Enable tests that were previously disabled due to the lack of internal linking. Updates #38485. Change-Id: I45125b9c263fd21d6847aa6b14ecaea3a2989b29 Reviewed-on: https://go-review.googlesource.com/c/go/+/265121 Trust: Cherry Zhang Reviewed-by: Austin Clements Reviewed-by: Than McIntosh --- src/cmd/go/internal/load/pkg.go | 4 ---- src/cmd/internal/sys/supported.go | 2 +- src/cmd/link/internal/ld/config.go | 4 +--- src/cmd/nm/nm_cgo_test.go | 5 ----- src/internal/testenv/testenv.go | 2 +- test/fixedbugs/bug429_run.go | 4 ---- test/fixedbugs/issue21576.go | 4 ---- 7 files changed, 3 insertions(+), 22 deletions(-) (limited to 'src/cmd/internal/sys') diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index 4c541b9017..ff744ee9fa 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -1964,10 +1964,6 @@ func externalLinkingForced(p *Package) bool { } case "ios": return true - case "darwin": - if cfg.BuildContext.GOARCH == "arm64" { - return true - } } // Currently build modes c-shared, pie (on systems that do not diff --git a/src/cmd/internal/sys/supported.go b/src/cmd/internal/sys/supported.go index 1d813bbb47..afc81381fd 100644 --- a/src/cmd/internal/sys/supported.go +++ b/src/cmd/internal/sys/supported.go @@ -39,7 +39,7 @@ func MustLinkExternal(goos, goarch string) bool { if goarch != "arm64" { return true } - case "darwin", "ios": + case "ios": if goarch == "arm64" { return true } diff --git a/src/cmd/link/internal/ld/config.go b/src/cmd/link/internal/ld/config.go index 54a94cebba..0cb3cc25c0 100644 --- a/src/cmd/link/internal/ld/config.go +++ b/src/cmd/link/internal/ld/config.go @@ -185,7 +185,7 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) { }() } - if sys.MustLinkExternal(objabi.GOOS, objabi.GOARCH) && !(objabi.GOOS == "darwin" && objabi.GOARCH == "arm64") { // XXX allow internal linking for darwin/arm64 but not change the default + if sys.MustLinkExternal(objabi.GOOS, objabi.GOARCH) { return true, fmt.Sprintf("%s/%s requires external linking", objabi.GOOS, objabi.GOARCH) } @@ -261,8 +261,6 @@ func determineLinkMode(ctxt *Link) { default: if extNeeded || (iscgo && externalobj) { ctxt.LinkMode = LinkExternal - } else if ctxt.IsDarwin() && ctxt.IsARM64() { - ctxt.LinkMode = LinkExternal // default to external linking for now } else { ctxt.LinkMode = LinkInternal } diff --git a/src/cmd/nm/nm_cgo_test.go b/src/cmd/nm/nm_cgo_test.go index 58f2c24908..9a257e0ed2 100644 --- a/src/cmd/nm/nm_cgo_test.go +++ b/src/cmd/nm/nm_cgo_test.go @@ -15,11 +15,6 @@ func canInternalLink() bool { switch runtime.GOOS { case "aix": return false - case "darwin": - switch runtime.GOARCH { - case "arm64": - return false - } case "dragonfly": return false case "freebsd": diff --git a/src/internal/testenv/testenv.go b/src/internal/testenv/testenv.go index 0ee6355ee3..dff68869bd 100644 --- a/src/internal/testenv/testenv.go +++ b/src/internal/testenv/testenv.go @@ -201,7 +201,7 @@ func CanInternalLink() bool { if runtime.GOARCH != "arm64" { return false } - case "darwin", "ios": + case "ios": if runtime.GOARCH == "arm64" { return false } diff --git a/test/fixedbugs/bug429_run.go b/test/fixedbugs/bug429_run.go index 60cc5b62de..c2bb1b85cb 100644 --- a/test/fixedbugs/bug429_run.go +++ b/test/fixedbugs/bug429_run.go @@ -1,10 +1,6 @@ // run // +build !nacl,!js -// +build !darwin !arm64 - -// Skip on darwin/arm64 as it requires external linking, which brings in -// cgo, causing deadlock detection not working. // Copyright 2014 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/test/fixedbugs/issue21576.go b/test/fixedbugs/issue21576.go index 3797a8c9ba..ae6161ccf5 100644 --- a/test/fixedbugs/issue21576.go +++ b/test/fixedbugs/issue21576.go @@ -1,10 +1,6 @@ // run // +build !nacl,!js -// +build !darwin !arm64 - -// Skip on darwin/arm64 as it requires external linking, which brings in -// cgo, causing deadlock detection not working. // Copyright 2019 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style -- cgit v1.3 From 2e6f50020cacd68f24e413d24d4c3e92e0c9e69f Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Fri, 30 Oct 2020 04:32:18 +1100 Subject: Revert "cmd/compile,cmd/internal/sys: enable additional build modes on linux/riscv64" This reverts CL 263457. It turns out that this still missed changes to cmd/link/internal/ld/config.go and some of these build modes also fail once cgo is enabled. Disable again for now. Change-Id: Iaf40d44e1551afd5b040d357f04af134f55a64a9 Reviewed-on: https://go-review.googlesource.com/c/go/+/266317 Reviewed-by: Cherry Zhang Trust: Joel Sing --- src/cmd/compile/internal/gc/main.go | 2 +- src/cmd/dist/test.go | 8 ++++---- src/cmd/go/go_test.go | 2 +- src/cmd/internal/sys/supported.go | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) (limited to 'src/cmd/internal/sys') diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index 0b65e8a0b4..4b401f2aa4 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -130,7 +130,7 @@ func hidePanic() { // supportsDynlink reports whether or not the code generator for the given // architecture supports the -shared and -dynlink flags. func supportsDynlink(arch *sys.Arch) bool { - return arch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.I386, sys.PPC64, sys.RISCV64, sys.S390X) + return arch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.I386, sys.PPC64, sys.S390X) } // timing data for compiler phases diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index aeffc2659f..7c454dd38d 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -984,7 +984,7 @@ func (t *tester) supportedBuildmode(mode string) bool { switch pair { case "aix-ppc64", "darwin-amd64", "darwin-arm64", "ios-arm64", - "linux-amd64", "linux-386", "linux-ppc64le", "linux-riscv64", "linux-s390x", + "linux-amd64", "linux-386", "linux-ppc64le", "linux-s390x", "freebsd-amd64", "windows-amd64", "windows-386": return true @@ -992,7 +992,7 @@ func (t *tester) supportedBuildmode(mode string) bool { return false case "c-shared": switch pair { - case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-riscv64", "linux-s390x", + case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-s390x", "darwin-amd64", "darwin-arm64", "freebsd-amd64", "android-arm", "android-arm64", "android-386", @@ -1002,7 +1002,7 @@ func (t *tester) supportedBuildmode(mode string) bool { return false case "shared": switch pair { - case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-riscv64", "linux-s390x": + case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-s390x": return true } return false @@ -1021,7 +1021,7 @@ func (t *tester) supportedBuildmode(mode string) bool { case "pie": switch pair { case "aix/ppc64", - "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-riscv64", "linux-s390x", + "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-s390x", "android-amd64", "android-arm", "android-arm64", "android-386": return true case "darwin-amd64", "darwin-arm64": diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index c7ca73b5b5..1fb1325519 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -2021,7 +2021,7 @@ func TestBuildmodePIE(t *testing.T) { platform := fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH) switch platform { - case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/riscv64", "linux/s390x", + case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x", "android/amd64", "android/arm", "android/arm64", "android/386", "freebsd/amd64", "windows/386", "windows/amd64", "windows/arm": diff --git a/src/cmd/internal/sys/supported.go b/src/cmd/internal/sys/supported.go index afc81381fd..3c750774ed 100644 --- a/src/cmd/internal/sys/supported.go +++ b/src/cmd/internal/sys/supported.go @@ -67,7 +67,7 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool { case "c-shared": switch platform { - case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/ppc64le", "linux/riscv64", "linux/s390x", + case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/ppc64le", "linux/s390x", "android/amd64", "android/arm", "android/arm64", "android/386", "freebsd/amd64", "darwin/amd64", "darwin/arm64", @@ -84,7 +84,7 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool { case "pie": switch platform { - case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/riscv64", "linux/s390x", + case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x", "android/amd64", "android/arm", "android/arm64", "android/386", "freebsd/amd64", "darwin/amd64", "darwin/arm64", @@ -97,7 +97,7 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool { case "shared": switch platform { - case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/riscv64", "linux/s390x": + case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x": return true } return false -- cgit v1.3 From b53df56001a6bd375b1dc2026908f331729cd731 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Thu, 29 Oct 2020 11:27:17 -0400 Subject: runtime, cmd: support race detector on darwin/arm64 https://reviews.llvm.org/D90435 is the counterpart in LLVM TSAN. race_linux_arm64.syso is built with LLVM commit 00da38ce2d36c07f12c287dc515d37bb7bc410e9 on a macOS/ARM64 machine. (It is not built on a builder with golang.org/x/build/cmd/racebuild as we don't have darwin/arm64 builder for now.) Updates #38485. Change-Id: I391efdacd9480197e308370bfccd05777deb4aee Reviewed-on: https://go-review.googlesource.com/c/go/+/266373 Trust: Cherry Zhang Reviewed-by: Ian Lance Taylor --- src/cmd/dist/test.go | 4 +++- src/cmd/go/internal/work/init.go | 2 +- src/cmd/internal/sys/supported.go | 4 +++- src/cmd/link/internal/ld/config.go | 2 +- src/cmd/link/internal/loadmacho/ldmacho.go | 12 ++++++++++-- src/runtime/race/README | 1 + src/runtime/race/race.go | 2 +- src/runtime/race/race_darwin_arm64.syso | Bin 0 -> 438936 bytes src/runtime/race_arm64.s | 15 +++++++++++++++ 9 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 src/runtime/race/race_darwin_arm64.syso (limited to 'src/cmd/internal/sys') diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index 7c454dd38d..9c25392cc0 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -1619,7 +1619,9 @@ func raceDetectorSupported(goos, goarch string) bool { switch goos { case "linux": return goarch == "amd64" || goarch == "ppc64le" || goarch == "arm64" - case "darwin", "freebsd", "netbsd", "windows": + case "darwin": + return goarch == "amd64" || goarch == "arm64" + case "freebsd", "netbsd", "windows": return goarch == "amd64" default: return false diff --git a/src/cmd/go/internal/work/init.go b/src/cmd/go/internal/work/init.go index d65c076c6a..102def4838 100644 --- a/src/cmd/go/internal/work/init.go +++ b/src/cmd/go/internal/work/init.go @@ -79,7 +79,7 @@ func instrumentInit() { } if cfg.BuildRace { if !sys.RaceDetectorSupported(cfg.Goos, cfg.Goarch) { - fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64, linux/ppc64le, linux/arm64, freebsd/amd64, netbsd/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0]) + fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64, linux/ppc64le, linux/arm64, freebsd/amd64, netbsd/amd64, darwin/amd64, darwin/arm64, and windows/amd64\n", flag.Args()[0]) base.SetExitStatus(2) base.Exit() } diff --git a/src/cmd/internal/sys/supported.go b/src/cmd/internal/sys/supported.go index 3c750774ed..69d7591440 100644 --- a/src/cmd/internal/sys/supported.go +++ b/src/cmd/internal/sys/supported.go @@ -13,7 +13,9 @@ func RaceDetectorSupported(goos, goarch string) bool { switch goos { case "linux": return goarch == "amd64" || goarch == "ppc64le" || goarch == "arm64" - case "darwin", "freebsd", "netbsd", "windows": + case "darwin": + return goarch == "amd64" || goarch == "arm64" + case "freebsd", "netbsd", "windows": return goarch == "amd64" default: return false diff --git a/src/cmd/link/internal/ld/config.go b/src/cmd/link/internal/ld/config.go index 0cb3cc25c0..cd64d86a4a 100644 --- a/src/cmd/link/internal/ld/config.go +++ b/src/cmd/link/internal/ld/config.go @@ -206,7 +206,7 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) { // When the race flag is set, the LLVM tsan relocatable file is linked // into the final binary, which means external linking is required because // internal linking does not support it. - if *flagRace && ctxt.Arch.InFamily(sys.PPC64) { + if *flagRace && (ctxt.Arch.InFamily(sys.PPC64) || ctxt.IsDarwin() && ctxt.IsARM64()) { return true, "race on " + objabi.GOARCH } diff --git a/src/cmd/link/internal/loadmacho/ldmacho.go b/src/cmd/link/internal/loadmacho/ldmacho.go index d12f2bc2ac..d26869e23a 100644 --- a/src/cmd/link/internal/loadmacho/ldmacho.go +++ b/src/cmd/link/internal/loadmacho/ldmacho.go @@ -47,7 +47,7 @@ THE SOFTWARE. const ( MACHO_X86_64_RELOC_UNSIGNED = 0 MACHO_X86_64_RELOC_SIGNED = 1 - MACHO_FAKE_GOTPCREL = 100 + MACHO_ARM64_RELOC_ADDEND = 10 ) type ldMachoObj struct { @@ -707,11 +707,11 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader, } sb := l.MakeSymbolUpdater(sect.sym) + var rAdd int64 for j := uint32(0); j < sect.nreloc; j++ { var ( rOff int32 rSize uint8 - rAdd int64 rType objabi.RelocType rSym loader.Sym ) @@ -722,6 +722,14 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader, return errorf("%v: unexpected scattered relocation", s) } + if arch.Family == sys.ARM64 && rel.type_ == MACHO_ARM64_RELOC_ADDEND { + // Two relocations. This addend will be applied to the next one. + rAdd = int64(rel.symnum) + continue + } else { + rAdd = 0 + } + rSize = rel.length rType = objabi.MachoRelocOffset + (objabi.RelocType(rel.type_) << 1) + objabi.RelocType(rel.pcrel) rOff = int32(rel.addr) diff --git a/src/runtime/race/README b/src/runtime/race/README index b36d82ccfd..178ab94ab5 100644 --- a/src/runtime/race/README +++ b/src/runtime/race/README @@ -11,3 +11,4 @@ race_linux_ppc64le.syso built with LLVM 89f7ccea6f6488c443655880229c54db1f180153 race_netbsd_amd64.syso built with LLVM 89f7ccea6f6488c443655880229c54db1f180153 and Go f62d3202bf9dbb3a00ad2a2c63ff4fa4188c5d3b. race_windows_amd64.syso built with LLVM 89f7ccea6f6488c443655880229c54db1f180153 and Go f62d3202bf9dbb3a00ad2a2c63ff4fa4188c5d3b. race_linux_arm64.syso built with LLVM 89f7ccea6f6488c443655880229c54db1f180153 and Go f62d3202bf9dbb3a00ad2a2c63ff4fa4188c5d3b. +race_darwin_arm64.syso built with LLVM 00da38ce2d36c07f12c287dc515d37bb7bc410e9 and Go fe70a3a0fd31441bcbb9932ecab11a6083cf2119. diff --git a/src/runtime/race/race.go b/src/runtime/race/race.go index c894de5f72..d6a14b79e7 100644 --- a/src/runtime/race/race.go +++ b/src/runtime/race/race.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build race,linux,amd64 race,freebsd,amd64 race,netbsd,amd64 race,darwin,amd64 race,windows,amd64 race,linux,ppc64le race,linux,arm64 +// +build race,linux,amd64 race,freebsd,amd64 race,netbsd,amd64 race,darwin,amd64 race,windows,amd64 race,linux,ppc64le race,linux,arm64 race,darwin,arm64 package race diff --git a/src/runtime/race/race_darwin_arm64.syso b/src/runtime/race/race_darwin_arm64.syso new file mode 100644 index 0000000000..f6eaa62ae3 Binary files /dev/null and b/src/runtime/race/race_darwin_arm64.syso differ diff --git a/src/runtime/race_arm64.s b/src/runtime/race_arm64.s index 9b909ac021..59373a9f3f 100644 --- a/src/runtime/race_arm64.s +++ b/src/runtime/race_arm64.s @@ -25,8 +25,15 @@ // The race ctx, ThreadState *thr below, is passed in R0 and loaded in racecalladdr. +#ifdef TLS_darwin +#define TP_ALIGN AND $~7, R0 +#else +#define TP_ALIGN +#endif + #define load_g \ MRS_TPIDR_R0 \ + TP_ALIGN \ MOVD runtime·tls_g(SB), R11 \ ADD R11, R0 \ MOVD 0(R0), g @@ -423,7 +430,13 @@ TEXT runtime·racecallbackthunk(SB), NOSPLIT|NOFRAME, $0 // benefit from this fast path. CBNZ R0, rest MOVD g, R13 +#ifdef TLS_darwin + MOVD R27, R12 // save R27 a.k.a. REGTMP (callee-save in C). load_g clobbers it +#endif load_g +#ifdef TLS_darwin + MOVD R12, R27 +#endif MOVD g_m(g), R0 MOVD m_p(R0), R0 MOVD p_raceprocctx(R0), R0 @@ -477,5 +490,7 @@ noswitch: BL runtime·racecallback(SB) JMP ret +#ifndef TLSG_IS_VARIABLE // tls_g, g value for each thread in TLS GLOBL runtime·tls_g+0(SB), TLSBSS+DUPOK, $8 +#endif -- cgit v1.3 From 8eb846fd37eb7bded8a1cf6932be2c59069863e5 Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Wed, 4 Nov 2020 00:26:15 +1100 Subject: cmd/compile,cmd/dist,cmd/go: enable pie buildmode for linux/riscv64 Enable pie as a buildmode for linux/riscv64, along with associated tests. Change-Id: I3fb0234d534dbeb96aa6cee6ae872304fbe02cf4 Reviewed-on: https://go-review.googlesource.com/c/go/+/267317 Trust: Joel Sing Reviewed-by: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Go Bot --- src/cmd/compile/internal/gc/main.go | 2 +- src/cmd/dist/test.go | 2 +- src/cmd/go/go_test.go | 2 +- src/cmd/internal/sys/supported.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/cmd/internal/sys') diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index 8b94c7f71b..d1097e8236 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -130,7 +130,7 @@ func hidePanic() { // supportsDynlink reports whether or not the code generator for the given // architecture supports the -shared and -dynlink flags. func supportsDynlink(arch *sys.Arch) bool { - return arch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.I386, sys.PPC64, sys.S390X) + return arch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.I386, sys.PPC64, sys.RISCV64, sys.S390X) } // timing data for compiler phases diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index d12a52b1cc..f087aba2b9 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -1021,7 +1021,7 @@ func (t *tester) supportedBuildmode(mode string) bool { case "pie": switch pair { case "aix/ppc64", - "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-s390x", + "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-riscv64", "linux-s390x", "android-amd64", "android-arm", "android-arm64", "android-386": return true case "darwin-amd64", "darwin-arm64": diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index 7bbadd3974..91d5884036 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -2022,7 +2022,7 @@ func TestBuildmodePIE(t *testing.T) { platform := fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH) switch platform { - case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x", + case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/riscv64", "linux/s390x", "android/amd64", "android/arm", "android/arm64", "android/386", "freebsd/amd64", "windows/386", "windows/amd64", "windows/arm": diff --git a/src/cmd/internal/sys/supported.go b/src/cmd/internal/sys/supported.go index 69d7591440..ef7c017bd4 100644 --- a/src/cmd/internal/sys/supported.go +++ b/src/cmd/internal/sys/supported.go @@ -86,7 +86,7 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool { case "pie": switch platform { - case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x", + case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/riscv64", "linux/s390x", "android/amd64", "android/arm", "android/arm64", "android/386", "freebsd/amd64", "darwin/amd64", "darwin/arm64", -- cgit v1.3