]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1.15] cmd/link: avoid exporting all symbols on windows buildmode=pie
authorQuim Muntal <quimmuntal@gmail.com>
Thu, 22 Oct 2020 20:32:20 +0000 (22:32 +0200)
committerDmitri Shuralyov <dmitshur@golang.org>
Wed, 31 Mar 2021 21:39:47 +0000 (21:39 +0000)
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.
Updates #40795.
Fixes #43592.

Change-Id: I3cc57c3b64f61187550bc8751dfa085f106c8475
Reviewed-on: https://go-review.googlesource.com/c/go/+/264459
Trust: Alex Brainman <alex.brainman@gmail.com>
Run-TryBot: Alex Brainman <alex.brainman@gmail.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
Reviewed-by: Austin Clements <austin@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/300692
Trust: Dmitri Shuralyov <dmitshur@golang.org>
Run-TryBot: Dmitri Shuralyov <dmitshur@golang.org>
Reviewed-by: David Chase <drchase@google.com>
misc/cgo/testcshared/cshared_test.go
src/cmd/go/go_test.go
src/cmd/link/internal/ld/lib.go
src/runtime/cgo/gcc_windows_386.c
src/runtime/cgo/gcc_windows_amd64.c
src/runtime/cgo/libcgo_windows.h [new file with mode: 0644]

index d717b4dfb3321184d90d17d66f96dde235492047..dff2682e2022dd743330834f1f948dcbfffd1ee5 100644 (file)
@@ -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)
                }
        }
 }
index 021930a8a8170106002e7d6cde64b749c43d49be..3f790cdeabc54341379efda562b5c0d32c967149 100644 (file)
@@ -9,6 +9,7 @@ import (
        "debug/elf"
        "debug/macho"
        "debug/pe"
+       "encoding/binary"
        "flag"
        "fmt"
        "go/format"
@@ -2166,6 +2167,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")
        }
index fc897599970020f1ee79d19246f6ad98604e366e..d03fb6cf91b9260d2e811598dbaa214805c6fb62 100644 (file)
@@ -1423,9 +1423,6 @@ func (ctxt *Link) hostlink() {
                        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() {
index 9184b91393ff59459c3069d2029404bbb6dd99d6..60cb011bf2457871a5d458385a6e907acddbf90e 100644 (file)
@@ -9,6 +9,7 @@
 #include <stdio.h>
 #include <errno.h>
 #include "libcgo.h"
+#include "libcgo_windows.h"
 
 static void threadentry(void*);
 
index 7192a2463154387fced551009329b031b550024e..0f8c817f0e4d138fd7d0efd396d26f16435bd6b3 100644 (file)
@@ -9,6 +9,7 @@
 #include <stdio.h>
 #include <errno.h>
 #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 (file)
index 0000000..0013f06
--- /dev/null
@@ -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;