1
0
mirror of https://github.com/golang/go synced 2024-09-24 07:20:14 -06:00

cmd/gc: disable link-time copying of un-Go-initialized globals

If you write:

        var x = 3

then the compiler arranges for x to be initialized in the linker
with an actual 3 from the data segment, rather than putting
x in the bss and emitting init-time "x = 3" assignment code.

If you write:

        var y = x
        var x = 3

then the compiler is clever and treats this the same as if
the code said 'y = 3': they both end up in the data segment
with no init-time assignments.

If you write

        var y = x
        var x int

then the compiler was treating this the same as if the
code said 'x = 0', making both x and y zero and avoiding
any init-time assignment.

This copying optimization to avoid init-time assignment of y
is incorrect if 'var x int' doesn't mean 'x = 0' but instead means
'x is initialized in C or assembly code'. The program ends up
with 'y = 0' instead of 'y = the value specified for x in that other code'.

Disable the propagation if there is no initializer for x.

This comes up in some uses of cgo, because cgo generates
Go globals that are initialized in accompanying C files.

Fixes #7665.

LGTM=iant
R=golang-codereviews, iant
CC=golang-codereviews
https://golang.org/cl/93200044
This commit is contained in:
Russ Cox 2014-05-09 16:03:44 -04:00
parent 3e8ed96c63
commit e5c105033a
3 changed files with 28 additions and 2 deletions

View File

@ -50,6 +50,7 @@ func TestFpVar(t *testing.T) { testFpVar(t) }
func Test4339(t *testing.T) { test4339(t) } func Test4339(t *testing.T) { test4339(t) }
func Test6390(t *testing.T) { test6390(t) } func Test6390(t *testing.T) { test6390(t) }
func Test5986(t *testing.T) { test5986(t) } func Test5986(t *testing.T) { test5986(t) }
func Test7665(t *testing.T) { test7665(t) }
func TestNaming(t *testing.T) { testNaming(t) } func TestNaming(t *testing.T) { testNaming(t) }
func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) } func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }

View File

@ -0,0 +1,25 @@
// Copyright 2013 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 cgotest
import (
"testing"
"unsafe"
)
// extern void f7665(void);
import "C"
//export f7665
func f7665() {}
var bad7665 unsafe.Pointer = C.f7665
var good7665 uintptr = uintptr(C.f7665)
func test7665(t *testing.T) {
if bad7665 == nil || bad7665 != unsafe.Pointer(good7665) {
t.Errorf("ptrs = %p, %#x, want same non-nil pointer", bad7665, good7665)
}
}

View File

@ -286,8 +286,8 @@ staticcopy(Node *l, Node *r, NodeList **out)
if(r->op != ONAME || r->class != PEXTERN || r->sym->pkg != localpkg) if(r->op != ONAME || r->class != PEXTERN || r->sym->pkg != localpkg)
return 0; return 0;
if(r->defn == N) // zeroed if(r->defn == N) // probably zeroed but perhaps supplied externally and of unknown value
return 1; return 0;
if(r->defn->op != OAS) if(r->defn->op != OAS)
return 0; return 0;
orig = r; orig = r;