diff options
author | Quim Muntal <quimmuntal@gmail.com> | 2020-10-15 23:12:49 +0200 |
---|---|---|
committer | Dmitri Shuralyov <dmitshur@golang.org> | 2021-03-31 21:39:27 +0000 |
commit | 5055314a5749664ab66a24beed8158552e276959 (patch) | |
tree | fd317bed928975311fdc353b967ff355eb846151 | |
parent | a07f9d2f82598d2f5cc0df0e813a6a2309cb96e6 (diff) | |
download | go-5055314a5749664ab66a24beed8158552e276959.tar.gz go-5055314a5749664ab66a24beed8158552e276959.zip |
[release-branch.go1.15] 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.
Updates #30674.
Fixes #43591.
Change-Id: I9c7fb09c677cc760f24d0f7d199740ae73981413
Reviewed-on: https://go-review.googlesource.com/c/go/+/262797
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
Trust: Alex Brainman <alex.brainman@gmail.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/300693
Trust: Dmitri Shuralyov <dmitshur@golang.org>
Run-TryBot: Dmitri Shuralyov <dmitshur@golang.org>
Reviewed-by: David Chase <drchase@google.com>
-rw-r--r-- | misc/cgo/testcshared/cshared_test.go | 96 | ||||
-rw-r--r-- | src/cmd/cgo/out.go | 6 |
2 files changed, 101 insertions, 1 deletions
diff --git a/misc/cgo/testcshared/cshared_test.go b/misc/cgo/testcshared/cshared_test.go index bd4d341820..d717b4dfb3 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 b9043efbf7..ee1c563495 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -961,7 +961,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" |