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 ++++++++++++ diff --git a/misc/cgo/testcshared/cshared_test.go b/misc/cgo/testcshared/cshared_test.go index d717b4dfb3321184d90d17d66f96dde235492047..dff2682e2022dd743330834f1f948dcbfffd1ee5 100644 --- a/misc/cgo/testcshared/cshared_test.go +++ b/misc/cgo/testcshared/cshared_test.go @@ -401,7 +401,7 @@ } 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 @@ if err := binary.Read(section.Open(), binary.LittleEndian, &e); err != nil { 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 @@ t.Fatalf("missing exported names: %v", e.NumberOfNames) } } 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 021930a8a8170106002e7d6cde64b749c43d49be..3f790cdeabc54341379efda562b5c0d32c967149 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -9,6 +9,7 @@ "bytes" "debug/elf" "debug/macho" "debug/pe" + "encoding/binary" "flag" "fmt" "go/format" @@ -2165,6 +2166,38 @@ t.Fatalf("unexpected optional header type of %T", f.OptionalHeader) } 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 fc897599970020f1ee79d19246f6ad98604e366e..d03fb6cf91b9260d2e811598dbaa214805c6fb62 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -1423,9 +1423,6 @@ // enable high-entropy ASLR on 64-bit. if ctxt.Arch.PtrSize >= 8 { argv = append(argv, "-Wl,--high-entropy-va") } - // 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 9184b91393ff59459c3069d2029404bbb6dd99d6..60cb011bf2457871a5d458385a6e907acddbf90e 100644 --- a/src/runtime/cgo/gcc_windows_386.c +++ b/src/runtime/cgo/gcc_windows_386.c @@ -9,6 +9,7 @@ #include #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 7192a2463154387fced551009329b031b550024e..0f8c817f0e4d138fd7d0efd396d26f16435bd6b3 100644 --- a/src/runtime/cgo/gcc_windows_amd64.c +++ b/src/runtime/cgo/gcc_windows_amd64.c @@ -9,6 +9,7 @@ #include #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 0000000000000000000000000000000000000000..0013f06baebd1b25683462bdde8dd2c416f3c53e --- /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;