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 --- misc/cgo/testcshared/cshared_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'misc/cgo/testcshared') diff --git a/misc/cgo/testcshared/cshared_test.go b/misc/cgo/testcshared/cshared_test.go index bd4d341820..d557f34b0f 100644 --- a/misc/cgo/testcshared/cshared_test.go +++ b/misc/cgo/testcshared/cshared_test.go @@ -98,7 +98,7 @@ func testMain(m *testing.M) int { } switch GOOS { - case "darwin": + case "darwin", "ios": // For Darwin/ARM. // TODO(crawshaw): can we do better? cc = append(cc, []string{"-framework", "CoreFoundation", "-framework", "Foundation"}...) @@ -107,7 +107,7 @@ func testMain(m *testing.M) int { } libgodir := GOOS + "_" + GOARCH switch GOOS { - case "darwin": + case "darwin", "ios": if GOARCH == "arm64" { libgodir += "_shared" } @@ -407,7 +407,7 @@ func TestUnexportedSymbols(t *testing.T) { adbPush(t, libname) linkFlags := "-Wl,--no-as-needed" - if GOOS == "darwin" { + if GOOS == "darwin" || GOOS == "ios" { linkFlags = "" } @@ -636,7 +636,7 @@ func copyFile(t *testing.T, dst, src string) { func TestGo2C2Go(t *testing.T) { switch GOOS { - case "darwin": + case "darwin", "ios": // Darwin shared libraries don't support the multiple // copies of the runtime package implied by this test. t.Skip("linking c-shared into Go programs not supported on Darwin; issue 29061") -- cgit v1.3 From 6f7b553c82b69b47becbe36d9115971d30fdab48 Mon Sep 17 00:00:00 2001 From: Quim Muntal Date: Thu, 15 Oct 2020 23:12:49 +0200 Subject: cmd/cgo: avoid exporting all symbols on windows buildmode=c-shared Disable default symbol auto-export behaviour by marking exported function with the __declspec(dllexport) attribute. Old behaviour can still be used by setting -extldflags=-Wl,--export-all-symbols. See https://sourceware.org/binutils/docs/ld/WIN32.html for more info. This change cuts 50kb of a "hello world" dll. Updates #6853 Fixes #30674 Change-Id: I9c7fb09c677cc760f24d0f7d199740ae73981413 Reviewed-on: https://go-review.googlesource.com/c/go/+/262797 Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor Reviewed-by: Alex Brainman Trust: Alex Brainman --- misc/cgo/testcshared/cshared_test.go | 96 ++++++++++++++++++++++++++++++++++++ src/cmd/cgo/out.go | 6 ++- 2 files changed, 101 insertions(+), 1 deletion(-) (limited to 'misc/cgo/testcshared') diff --git a/misc/cgo/testcshared/cshared_test.go b/misc/cgo/testcshared/cshared_test.go index d557f34b0f..e1835afa51 100644 --- a/misc/cgo/testcshared/cshared_test.go +++ b/misc/cgo/testcshared/cshared_test.go @@ -7,6 +7,8 @@ package cshared_test import ( "bytes" "debug/elf" + "debug/pe" + "encoding/binary" "flag" "fmt" "io/ioutil" @@ -355,6 +357,100 @@ func TestExportedSymbols(t *testing.T) { } } +func checkNumberOfExportedFunctionsWindows(t *testing.T, exportAllSymbols bool) { + const prog = ` +package main + +import "C" + +//export GoFunc +func GoFunc() { + println(42) +} + +//export GoFunc2 +func GoFunc2() { + println(24) +} + +func main() { +} +` + + tmpdir := t.TempDir() + + srcfile := filepath.Join(tmpdir, "test.go") + objfile := filepath.Join(tmpdir, "test.dll") + if err := ioutil.WriteFile(srcfile, []byte(prog), 0666); err != nil { + t.Fatal(err) + } + argv := []string{"build", "-buildmode=c-shared"} + if exportAllSymbols { + argv = append(argv, "-ldflags", "-extldflags=-Wl,--export-all-symbols") + } + argv = append(argv, "-o", objfile, srcfile) + out, err := exec.Command("go", argv...).CombinedOutput() + if err != nil { + t.Fatalf("build failure: %s\n%s\n", err, string(out)) + } + + f, err := pe.Open(objfile) + if err != nil { + t.Fatalf("pe.Open failed: %v", err) + } + defer f.Close() + section := f.Section(".edata") + if section == nil { + t.Error(".edata section is not present") + } + + // TODO: deduplicate this struct from cmd/link/internal/ld/pe.go + type IMAGE_EXPORT_DIRECTORY struct { + _ [2]uint32 + _ [2]uint16 + _ [2]uint32 + NumberOfFunctions uint32 + NumberOfNames uint32 + _ [3]uint32 + } + var e IMAGE_EXPORT_DIRECTORY + if err := binary.Read(section.Open(), binary.LittleEndian, &e); err != nil { + t.Fatalf("binary.Read failed: %v", err) + } + + expectedNumber := uint32(2) + + if exportAllSymbols { + if e.NumberOfFunctions <= expectedNumber { + t.Fatalf("missing exported functions: %v", e.NumberOfFunctions) + } + if e.NumberOfNames <= expectedNumber { + t.Fatalf("missing exported names: %v", e.NumberOfNames) + } + } else { + if e.NumberOfFunctions != expectedNumber { + t.Fatalf("too many exported functions: %v", e.NumberOfFunctions) + } + if e.NumberOfNames != expectedNumber { + t.Fatalf("too many exported names: %v", e.NumberOfNames) + } + } +} + +func TestNumberOfExportedFunctions(t *testing.T) { + if GOOS != "windows" { + t.Skip("skipping windows only test") + } + t.Parallel() + + t.Run("OnlyExported", func(t *testing.T) { + checkNumberOfExportedFunctionsWindows(t, false) + }) + t.Run("All", func(t *testing.T) { + checkNumberOfExportedFunctionsWindows(t, true) + }) +} + // test1: shared library can be dynamically loaded and exported symbols are accessible. func TestExportedSymbolsWithDynamicLoad(t *testing.T) { t.Parallel() diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index b447b07645..82316a300b 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -939,7 +939,11 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) { } // Build the wrapper function compiled by gcc. - s := fmt.Sprintf("%s %s(", gccResult, exp.ExpName) + gccExport := "" + if goos == "windows" { + gccExport = "__declspec(dllexport)" + } + s := fmt.Sprintf("%s %s %s(", gccExport, gccResult, exp.ExpName) if fn.Recv != nil { s += p.cgoType(fn.Recv.List[0].Type).C.String() s += " recv" -- cgit v1.3 From e463c28cc116fb1f40a4e203bddf93b6ef52c8d9 Mon Sep 17 00:00:00 2001 From: Quim Muntal Date: Thu, 22 Oct 2020 22:32:20 +0200 Subject: cmd/link: avoid exporting all symbols on windows buildmode=pie Marking one functions with __declspec(dllexport) forces mingw to create .reloc section without having to export all symbols. See https://insights.sei.cmu.edu/cert/2018/08/when-aslr-is-not-really-aslr---the-case-of-incorrect-assumptions-and-bad-defaults.html for more info. This change cuts 73kb of a "hello world" pie binary. Updates #6853 Fixes #40795 Change-Id: I3cc57c3b64f61187550bc8751dfa085f106c8475 Reviewed-on: https://go-review.googlesource.com/c/go/+/264459 Trust: Alex Brainman Run-TryBot: Alex Brainman TryBot-Result: Go Bot Reviewed-by: Alex Brainman Reviewed-by: Austin Clements --- misc/cgo/testcshared/cshared_test.go | 9 +++++---- src/cmd/go/go_test.go | 33 +++++++++++++++++++++++++++++++++ src/cmd/link/internal/ld/lib.go | 3 --- src/runtime/cgo/gcc_windows_386.c | 1 + src/runtime/cgo/gcc_windows_amd64.c | 1 + src/runtime/cgo/libcgo_windows.h | 12 ++++++++++++ 6 files changed, 52 insertions(+), 7 deletions(-) create mode 100644 src/runtime/cgo/libcgo_windows.h (limited to 'misc/cgo/testcshared') diff --git a/misc/cgo/testcshared/cshared_test.go b/misc/cgo/testcshared/cshared_test.go index e1835afa51..3a4886cf30 100644 --- a/misc/cgo/testcshared/cshared_test.go +++ b/misc/cgo/testcshared/cshared_test.go @@ -401,7 +401,7 @@ func main() { defer f.Close() section := f.Section(".edata") if section == nil { - t.Error(".edata section is not present") + t.Fatalf(".edata section is not present") } // TODO: deduplicate this struct from cmd/link/internal/ld/pe.go @@ -418,7 +418,8 @@ func main() { t.Fatalf("binary.Read failed: %v", err) } - expectedNumber := uint32(2) + // Only the two exported functions and _cgo_dummy_export should be exported + expectedNumber := uint32(3) if exportAllSymbols { if e.NumberOfFunctions <= expectedNumber { @@ -429,10 +430,10 @@ func main() { } } else { if e.NumberOfFunctions != expectedNumber { - t.Fatalf("too many exported functions: %v", e.NumberOfFunctions) + t.Fatalf("got %d exported functions; want %d", e.NumberOfFunctions, expectedNumber) } if e.NumberOfNames != expectedNumber { - t.Fatalf("too many exported names: %v", e.NumberOfNames) + t.Fatalf("got %d exported names; want %d", e.NumberOfNames, expectedNumber) } } } diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index 1fb1325519..7bbadd3974 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -9,6 +9,7 @@ import ( "debug/elf" "debug/macho" "debug/pe" + "encoding/binary" "flag" "fmt" "go/format" @@ -2129,6 +2130,38 @@ func testBuildmodePIE(t *testing.T, useCgo, setBuildmodeToPIE bool) { if (dc & pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) == 0 { t.Error("IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE flag is not set") } + if useCgo { + // Test that only one symbol is exported (#40795). + // PIE binaries don´t require .edata section but unfortunately + // binutils doesn´t generate a .reloc section unless there is + // at least one symbol exported. + // See https://sourceware.org/bugzilla/show_bug.cgi?id=19011 + section := f.Section(".edata") + if section == nil { + t.Fatalf(".edata section is not present") + } + // TODO: deduplicate this struct from cmd/link/internal/ld/pe.go + type IMAGE_EXPORT_DIRECTORY struct { + _ [2]uint32 + _ [2]uint16 + _ [2]uint32 + NumberOfFunctions uint32 + NumberOfNames uint32 + _ [3]uint32 + } + var e IMAGE_EXPORT_DIRECTORY + if err := binary.Read(section.Open(), binary.LittleEndian, &e); err != nil { + t.Fatalf("binary.Read failed: %v", err) + } + + // Only _cgo_dummy_export should be exported + if e.NumberOfFunctions != 1 { + t.Fatalf("got %d exported functions; want 1", e.NumberOfFunctions) + } + if e.NumberOfNames != 1 { + t.Fatalf("got %d exported names; want 1", e.NumberOfNames) + } + } default: panic("unreachable") } diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 73e0b35bc0..735b84d37d 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -1320,9 +1320,6 @@ func (ctxt *Link) hostlink() { case objabi.Hdarwin, objabi.Haix: case objabi.Hwindows: argv = addASLRargs(argv) - // Work around binutils limitation that strips relocation table for dynamicbase. - // See https://sourceware.org/bugzilla/show_bug.cgi?id=19011 - argv = append(argv, "-Wl,--export-all-symbols") default: // ELF. if ctxt.UseRelro() { diff --git a/src/runtime/cgo/gcc_windows_386.c b/src/runtime/cgo/gcc_windows_386.c index 9184b91393..60cb011bf2 100644 --- a/src/runtime/cgo/gcc_windows_386.c +++ b/src/runtime/cgo/gcc_windows_386.c @@ -9,6 +9,7 @@ #include #include #include "libcgo.h" +#include "libcgo_windows.h" static void threadentry(void*); diff --git a/src/runtime/cgo/gcc_windows_amd64.c b/src/runtime/cgo/gcc_windows_amd64.c index 7192a24631..0f8c817f0e 100644 --- a/src/runtime/cgo/gcc_windows_amd64.c +++ b/src/runtime/cgo/gcc_windows_amd64.c @@ -9,6 +9,7 @@ #include #include #include "libcgo.h" +#include "libcgo_windows.h" static void threadentry(void*); diff --git a/src/runtime/cgo/libcgo_windows.h b/src/runtime/cgo/libcgo_windows.h new file mode 100644 index 0000000000..0013f06bae --- /dev/null +++ b/src/runtime/cgo/libcgo_windows.h @@ -0,0 +1,12 @@ +// 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. + +// Ensure there's one symbol marked __declspec(dllexport). +// If there are no exported symbols, the unfortunate behavior of +// the binutils linker is to also strip the relocations table, +// resulting in non-PIE binary. The other option is the +// --export-all-symbols flag, but we don't need to export all symbols +// and this may overflow the export table (#40795). +// See https://sourceware.org/bugzilla/show_bug.cgi?id=19011 +__declspec(dllexport) int _cgo_dummy_export; -- cgit v1.3