]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: fix large global variables in -linkshared mode on s390x
authorMichael Munday <mike.munday@ibm.com>
Wed, 20 Sep 2017 16:12:33 +0000 (12:12 -0400)
committerMichael Munday <mike.munday@ibm.com>
Wed, 20 Sep 2017 20:20:46 +0000 (20:20 +0000)
When rewriting loads and stores accessing global variables to use the
GOT we were making use of REGTMP (R10). Unfortunately loads and stores
with large offsets (larger than 20-bits) were also using REGTMP,
causing it to be clobbered and subsequently a segmentation fault.

This can be fixed by using REGTMP2 (R11) for the rewrite. This is fine
because REGTMP2 only has a couple of uses in the assembler (division,
high multiplication and storage-to-storage instructions). We didn't
use REGTMP2 originally because it used to be used more frequently,
in particular for stores of constants to memory. However we have now
eliminated those uses.

This was found while writing a test case for CL 63030. That test case
is included in this CL.

Change-Id: I13956f1f3ca258a7c8a7ff0a7570d2848adf7f68
Reviewed-on: https://go-review.googlesource.com/65011
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>

misc/cgo/testshared/shared_test.go
misc/cgo/testshared/src/global/main.go [new file with mode: 0644]
misc/cgo/testshared/src/globallib/global.go [new file with mode: 0644]
src/cmd/internal/obj/s390x/objz.go

index 97cdc80af8aa34a7d61a5d8ad8a14c603e878a0c..221185cc697ea12df3ea35cfd32816cd7d0ad4d9 100644 (file)
@@ -841,3 +841,12 @@ func TestInterface(t *testing.T) {
        goCmd(t, "install", "-linkshared", "iface")
        run(t, "running type/itab uniqueness tester", "./bin/iface")
 }
+
+// Access a global variable from a library.
+func TestGlobal(t *testing.T) {
+       goCmd(t, "install", "-buildmode=shared", "-linkshared", "globallib")
+       goCmd(t, "install", "-linkshared", "global")
+       run(t, "global executable", "./bin/global")
+       AssertIsLinkedTo(t, "./bin/global", soname)
+       AssertHasRPath(t, "./bin/global", gorootInstallDir)
+}
diff --git a/misc/cgo/testshared/src/global/main.go b/misc/cgo/testshared/src/global/main.go
new file mode 100644 (file)
index 0000000..94e7f24
--- /dev/null
@@ -0,0 +1,71 @@
+// Copyright 2017 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 main
+
+import (
+       "globallib"
+)
+
+//go:noinline
+func testLoop() {
+       for i, s := range globallib.Data {
+               if s != int64(i) {
+                       panic("testLoop: mismatch")
+               }
+       }
+}
+
+//go:noinline
+func ptrData() *[1<<20 + 10]int64 {
+       return &globallib.Data
+}
+
+//go:noinline
+func testMediumOffset() {
+       for i, s := range globallib.Data[1<<16-2:] {
+               if s != int64(i)+1<<16-2 {
+                       panic("testMediumOffset: index mismatch")
+               }
+       }
+
+       x := globallib.Data[1<<16-1]
+       if x != 1<<16-1 {
+               panic("testMediumOffset: direct mismatch")
+       }
+
+       y := &globallib.Data[1<<16-3]
+       if y != &ptrData()[1<<16-3] {
+               panic("testMediumOffset: address mismatch")
+       }
+}
+
+//go:noinline
+func testLargeOffset() {
+       for i, s := range globallib.Data[1<<20:] {
+               if s != int64(i)+1<<20 {
+                       panic("testLargeOffset: index mismatch")
+               }
+       }
+
+       x := globallib.Data[1<<20+1]
+       if x != 1<<20+1 {
+               panic("testLargeOffset: direct mismatch")
+       }
+
+       y := &globallib.Data[1<<20+2]
+       if y != &ptrData()[1<<20+2] {
+               panic("testLargeOffset: address mismatch")
+       }
+}
+
+func main() {
+       testLoop()
+
+       // SSA rules commonly merge offsets into addresses. These
+       // tests access global data in different ways to try
+       // and exercise different SSA rules.
+       testMediumOffset()
+       testLargeOffset()
+}
diff --git a/misc/cgo/testshared/src/globallib/global.go b/misc/cgo/testshared/src/globallib/global.go
new file mode 100644 (file)
index 0000000..b4372a2
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2017 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 globallib
+
+// Data is large enough to that offsets into it do not fit into
+// 16-bit or 20-bit immediates. Ideally we'd also try and overrun
+// 32-bit immediates, but that requires the test machine to have
+// too much memory.
+var Data [1<<20 + 10]int64
+
+func init() {
+       for i := range Data {
+               Data[i] = int64(i)
+       }
+}
index 1539de67c82b7fbfba5500082f817eb707e8e5ff..45ce68bebf2ea863cf3d7a7054726575d1da07ea 100644 (file)
@@ -126,7 +126,7 @@ func (c *ctxtz) rewriteToUseGot(p *obj.Prog) {
        // ADD instruction.
        if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
                // MOVD $sym, Rx becomes MOVD sym@GOT, Rx
-               // MOVD $sym+<off>, Rx becomes MOVD sym@GOT, Rx; MOVD $<off>(Rx or REGTMP2), Rx
+               // MOVD $sym+<off>, Rx becomes MOVD sym@GOT, Rx or REGTMP2; MOVD $<off>(Rx or REGTMP2), Rx
                if p.To.Type != obj.TYPE_REG || p.As != AMOVD {
                        c.ctxt.Diag("do not know how to handle LEA-type insn to non-register in %v with -dynlink", p)
                }
@@ -154,8 +154,8 @@ func (c *ctxtz) rewriteToUseGot(p *obj.Prog) {
                c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
        }
        var source *obj.Addr
-       // MOVD sym, Ry becomes MOVD sym@GOT, REGTMP; MOVD (REGTMP), Ry
-       // MOVD Ry, sym becomes MOVD sym@GOT, REGTMP; MOVD Ry, (REGTMP)
+       // MOVD sym, Ry becomes MOVD sym@GOT, REGTMP2; MOVD (REGTMP2), Ry
+       // MOVD Ry, sym becomes MOVD sym@GOT, REGTMP2; MOVD Ry, (REGTMP2)
        // An addition may be inserted between the two MOVs if there is an offset.
        if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
                if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
@@ -184,17 +184,17 @@ func (c *ctxtz) rewriteToUseGot(p *obj.Prog) {
        p1.From.Sym = source.Sym
        p1.From.Name = obj.NAME_GOTREF
        p1.To.Type = obj.TYPE_REG
-       p1.To.Reg = REGTMP
+       p1.To.Reg = REGTMP2
 
        p2.As = p.As
        p2.From = p.From
        p2.To = p.To
        if p.From.Name == obj.NAME_EXTERN {
-               p2.From.Reg = REGTMP
+               p2.From.Reg = REGTMP2
                p2.From.Name = obj.NAME_NONE
                p2.From.Sym = nil
        } else if p.To.Name == obj.NAME_EXTERN {
-               p2.To.Reg = REGTMP
+               p2.To.Reg = REGTMP2
                p2.To.Name = obj.NAME_NONE
                p2.To.Sym = nil
        } else {