]> Cypherpunks.ru repositories - gostls13.git/commitdiff
runtime/cgo,cmd/internal/obj/ppc64: fix signals with cgo
authorLynn Boger <laboger@linux.vnet.ibm.com>
Wed, 31 Mar 2021 17:28:47 +0000 (12:28 -0500)
committerLynn Boger <laboger@linux.vnet.ibm.com>
Mon, 10 May 2021 17:21:32 +0000 (17:21 +0000)
Recently some tsan tests were enabled on ppc64le which had not
been enabled before. This resulted in failures on systems with
tsan available, and while debugging it was determined that
there were other issues related to the use of signals with cgo.

Signals were not being forwarded within programs linked against
libtsan because the nocgo sigaction was being called for ppc64le
with or without cgo. Adding callCgoSigaction and calling that
allows signals to be registered so that signal forwarding works.

For linux-ppc64 and aix-ppc64, this won't change. On linux-ppc64
there is no cgo. I can't test aix-ppc64 so those owners can enable
it if they want.

In reviewing comments about sigtramp in sys_linux_arm64 it was
noted that a previous issue in arm64 due to missing callee save
registers could also be a problem on ppc64x, so code was added
to save and restore those.

Also, the use of R31 as a temp register in some cases caused an
issue since it is a nonvolatile register in C and was being clobbered
in cases where the C code expected it to be valid. The code sequences to
load these addresses were changed to avoid the use of R31 when loading
such an address.

To get around a vet error, the stubs_ppc64x.go file in runtime
was split into stubs_ppc64.go and stubs_ppc64le.go.

Updates #45040

Change-Id: Ia4ecff950613cbe1b89471790b1d3819d5b5cfb9
Reviewed-on: https://go-review.googlesource.com/c/go/+/306369
Trust: Lynn Boger <laboger@linux.vnet.ibm.com>
Run-TryBot: Lynn Boger <laboger@linux.vnet.ibm.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Carlos Eduardo Seo <carlos.seo@linaro.org>
src/cmd/asm/internal/asm/testdata/ppc64.s
src/cmd/internal/obj/ppc64/asm9.go
src/runtime/cgo/gcc_mmap.c
src/runtime/cgo/gcc_sigaction.c
src/runtime/cgo/sigaction.go
src/runtime/cgo_sigaction.go
src/runtime/sigaction.go
src/runtime/stubs_ppc64.go [new file with mode: 0644]
src/runtime/stubs_ppc64le.go [moved from src/runtime/stubs_ppc64x.go with 83% similarity]
src/runtime/sys_linux_ppc64x.s

index 1bd4b1e1c89057783fd84b71c2339415bfd38ff0..b6c0aa5035c013652dcd7df91505d78cfd9ac6a7 100644 (file)
@@ -41,8 +41,8 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
        MOVDBR (R3)(R4), R5             // 7ca41c28
        MOVWBR (R3)(R4), R5             // 7ca41c2c
        MOVHBR (R3)(R4), R5             // 7ca41e2c
-       MOVD $foo+4009806848(FP), R5    // 3fe1ef0138bfcc20
-       MOVD $foo(SB), R5               // 3fe0000038bf0000
+       MOVD $foo+4009806848(FP), R5    // 3ca1ef0138a5cc20
+       MOVD $foo(SB), R5               // 3ca0000038a50000
 
        MOVDU 8(R3), R4                 // e8830009
        MOVDU (R3)(R4), R5              // 7ca4186a
index 69f967acfd459939948568e1eac8bfb968f22178..316959f62d792763b16382e13b8ba6123ee6be06 100644 (file)
@@ -2220,7 +2220,7 @@ func (c *ctxt9) opform(insn uint32) int {
 
 // Encode instructions and create relocation for accessing s+d according to the
 // instruction op with source or destination (as appropriate) register reg.
-func (c *ctxt9) symbolAccess(s *obj.LSym, d int64, reg int16, op uint32) (o1, o2 uint32) {
+func (c *ctxt9) symbolAccess(s *obj.LSym, d int64, reg int16, op uint32, reuse bool) (o1, o2 uint32) {
        if c.ctxt.Headtype == objabi.Haix {
                // Every symbol access must be made via a TOC anchor.
                c.ctxt.Diag("symbolAccess called for %s", s.Name)
@@ -2232,8 +2232,15 @@ func (c *ctxt9) symbolAccess(s *obj.LSym, d int64, reg int16, op uint32) (o1, o2
        } else {
                base = REG_R0
        }
-       o1 = AOP_IRR(OP_ADDIS, REGTMP, base, 0)
-       o2 = AOP_IRR(op, uint32(reg), REGTMP, 0)
+       // If reg can be reused when computing the symbol address,
+       // use it instead of REGTMP.
+       if !reuse {
+               o1 = AOP_IRR(OP_ADDIS, REGTMP, base, 0)
+               o2 = AOP_IRR(op, uint32(reg), REGTMP, 0)
+       } else {
+               o1 = AOP_IRR(OP_ADDIS, uint32(reg), base, 0)
+               o2 = AOP_IRR(op, uint32(reg), uint32(reg), 0)
+       }
        rel := obj.Addrel(c.cursym)
        rel.Off = int32(c.pc)
        rel.Siz = 8
@@ -2877,14 +2884,14 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
                switch p.From.Name {
                case obj.NAME_EXTERN, obj.NAME_STATIC:
                        // Load a 32 bit constant, or relocation depending on if a symbol is attached
-                       o1, o2 = c.symbolAccess(p.From.Sym, v, p.To.Reg, OP_ADDI)
+                       o1, o2 = c.symbolAccess(p.From.Sym, v, p.To.Reg, OP_ADDI, true)
                default:
                        if r == 0 {
                                r = c.getimpliedreg(&p.From, p)
                        }
                        // Add a 32 bit offset to a register.
-                       o1 = AOP_IRR(OP_ADDIS, REGTMP, uint32(r), uint32(high16adjusted(int32(v))))
-                       o2 = AOP_IRR(OP_ADDI, uint32(p.To.Reg), REGTMP, uint32(v))
+                       o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), uint32(r), uint32(high16adjusted(int32(v))))
+                       o2 = AOP_IRR(OP_ADDI, uint32(p.To.Reg), uint32(p.To.Reg), uint32(v))
                }
 
        case 27: /* subc ra,$simm,rd => subfic rd,ra,$simm */
@@ -3043,10 +3050,10 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
                if r == 0 {
                        r = c.getimpliedreg(&p.From, p)
                }
-               o1 = AOP_IRR(OP_ADDIS, REGTMP, uint32(r), uint32(high16adjusted(v)))
-               o2 = AOP_IRR(c.opload(p.As), uint32(p.To.Reg), REGTMP, uint32(v))
+               o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), uint32(r), uint32(high16adjusted(v)))
+               o2 = AOP_IRR(c.opload(p.As), uint32(p.To.Reg), uint32(p.To.Reg), uint32(v))
 
-               // Sign extend MOVB operations. This is ignored for other cases (o.size == 8).
+               // Sign extend MOVB if needed
                o3 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.To.Reg), 0)
 
        case 40: /* word */
@@ -3404,7 +3411,8 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
                if c.opform(inst) == DS_FORM && v&0x3 != 0 {
                        log.Fatalf("invalid offset for DS form load/store %v", p)
                }
-               o1, o2 = c.symbolAccess(p.To.Sym, v, p.From.Reg, inst)
+               // Can't reuse base for store instructions.
+               o1, o2 = c.symbolAccess(p.To.Sym, v, p.From.Reg, inst, false)
 
        case 75: // 32 bit offset symbol loads (got/toc/addr)
                v := p.From.Offset
@@ -3432,10 +3440,11 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
                                rel.Type = objabi.R_ADDRPOWER_TOCREL_DS
                        }
                default:
-                       o1, o2 = c.symbolAccess(p.From.Sym, v, p.To.Reg, inst)
+                       reuseBaseReg := p.As != AFMOVD && p.As != AFMOVS
+                       // Reuse To.Reg as base register if not FP move.
+                       o1, o2 = c.symbolAccess(p.From.Sym, v, p.To.Reg, inst, reuseBaseReg)
                }
 
-               // Sign extend MOVB operations. This is ignored for other cases (o.size == 8).
                o3 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.To.Reg), 0)
 
        case 79:
index e6a621d5a37a5b3026faed560866eaf6922f9d14..698a7e3cd243e2c17bb6588f1e897933c852c583 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build linux,amd64 linux,arm64
+// +build linux,amd64 linux,arm64 linux,ppc64le
 
 #include <errno.h>
 #include <stdint.h>
index 890008e327d5edbf1c0e9f4f850fcc947765a789..dd283151f17055c1061f1e2e850e62534de489e6 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build linux,amd64 linux,arm64
+// +build linux,amd64 linux,arm64 linux,ppc64le
 
 #include <errno.h>
 #include <stddef.h>
index ee63ea4c09edbb5296984dd9890dc5a42bc76fe9..692fd2675f9475febed88480b615584c2d663fef 100644 (file)
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build (linux && amd64) || (freebsd && amd64) || (linux && arm64)
-// +build linux,amd64 freebsd,amd64 linux,arm64
+//go:build (linux && amd64) || (freebsd && amd64) || (linux && arm64) || (linux && ppc64le)
+// +build linux,amd64 freebsd,amd64 linux,arm64 linux,ppc64le
 
 package cgo
 
@@ -11,8 +11,8 @@ package cgo
 import _ "unsafe"
 
 // When using cgo, call the C library for sigaction, so that we call into
-// any sanitizer interceptors. This supports using the memory
-// sanitizer with Go programs. The memory sanitizer only applies to
+// any sanitizer interceptors. This supports using the sanitizers
+// with Go programs. The thread and memory sanitizers only apply to
 // C/C++ code; this permits that code to see the Go runtime's existing signal
 // handlers when registering new signal handlers for the process.
 
index 15690ecb0bf6e0378305b416cc4a64032fd6fd48..6099d1b746f80a3803c9e21c2d3a19125168b18c 100644 (file)
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Support for memory sanitizer. See runtime/cgo/sigaction.go.
+// Support for sanitizers. See runtime/cgo/sigaction.go.
 
-//go:build (linux && amd64) || (freebsd && amd64) || (linux && arm64)
-// +build linux,amd64 freebsd,amd64 linux,arm64
+//go:build (linux && amd64) || (freebsd && amd64) || (linux && arm64) || (linux && ppc64le)
+// +build linux,amd64 freebsd,amd64 linux,arm64 linux,ppc64le
 
 package runtime
 
index 76f37b1b53506996c3ee04ad11289a4ad22bf4ad..30050efcc78a022bead6ffa9961a9b425a7fe29b 100644 (file)
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build (linux && !amd64 && !arm64) || (freebsd && !amd64)
-// +build linux,!amd64,!arm64 freebsd,!amd64
+//go:build (linux && !amd64 && !arm64 && !ppc64le) || (freebsd && !amd64)
+// +build linux,!amd64,!arm64,!ppc64le freebsd,!amd64
 
 package runtime
 
diff --git a/src/runtime/stubs_ppc64.go b/src/runtime/stubs_ppc64.go
new file mode 100644 (file)
index 0000000..f692947
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2021 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.
+
+//go:build linux
+// +build linux
+
+package runtime
+
+// Called from assembly only; declared for go vet.
+func load_g()
+func save_g()
+func reginit()
+
+//go:noescape
+func callCgoSigaction(sig uintptr, new, old *sigactiont) int32
similarity index 83%
rename from src/runtime/stubs_ppc64x.go
rename to src/runtime/stubs_ppc64le.go
index 0841b413fdb3527d2c5a7b635306c8db66065af8..5b733136e3b57a5722f85ac57b8eb4500bf348a6 100644 (file)
@@ -2,9 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build ppc64 || ppc64le
-// +build ppc64 ppc64le
-
 package runtime
 
 // Called from assembly only; declared for go vet.
index 75da130357a4d5c3aa5da39a19579022b8b737c4..46387288d53d5c14a66ad728efec2d10bb8328d5 100644 (file)
@@ -336,6 +336,26 @@ TEXT runtime·rt_sigaction(SB),NOSPLIT|NOFRAME,$0-36
        MOVW    R3, ret+32(FP)
        RET
 
+#ifdef GOARCH_ppc64le
+// Call the function stored in _cgo_sigaction using the GCC calling convention.
+TEXT runtime·callCgoSigaction(SB),NOSPLIT,$0
+       MOVD    sig+0(FP), R3
+       MOVD    new+8(FP), R4
+       MOVD    old+16(FP), R5
+       MOVD     _cgo_sigaction(SB), R12
+       MOVD    R12, CTR                // R12 should contain the function address
+       MOVD    R1, R15                 // Save R1
+       MOVD    R2, 24(R1)              // Save R2
+       SUB     $48, R1                 // reserve 32 (frame) + 16 bytes for sp-8 where fp may be saved.
+       RLDICR  $0, R1, $59, R1         // Align to 16 bytes for C code
+       BL      (CTR)
+       XOR     R0, R0, R0              // Clear R0 as Go expects
+       MOVD    R15, R1                 // Restore R1
+       MOVD    24(R1), R2              // Restore R2
+       MOVW    R3, ret+24(FP)          // Return result
+       RET
+#endif
+
 TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
        MOVW    sig+8(FP), R3
        MOVD    info+16(FP), R4
@@ -351,15 +371,97 @@ TEXT runtime·sigreturn(SB),NOSPLIT,$0-0
 
 #ifdef GOARCH_ppc64le
 // ppc64le doesn't need function descriptors
-TEXT runtime·sigtramp(SB),NOSPLIT,$64
+// Save callee-save registers in the case of signal forwarding.
+// Same as on ARM64 https://golang.org/issue/31827 .
+TEXT runtime·sigtramp(SB),NOSPLIT|NOFRAME,$0
 #else
 // function descriptor for the real sigtramp
 TEXT runtime·sigtramp(SB),NOSPLIT|NOFRAME,$0
        DWORD   $sigtramp<>(SB)
        DWORD   $0
        DWORD   $0
-TEXT sigtramp<>(SB),NOSPLIT,$64
+TEXT sigtramp<>(SB),NOSPLIT|NOFRAME,$0
 #endif
+       // Start with standard C stack frame layout and linkage.
+       MOVD    LR, R0
+       MOVD    R0, 16(R1) // Save LR in caller's frame.
+       MOVW    CR, R0     // Save CR in caller's frame
+       MOVD    R0, 8(R1)
+       // The stack must be acquired here and not
+       // in the automatic way based on stack size
+       // since that sequence clobbers R31 before it
+       // gets saved.
+       // We are being ultra safe here in saving the
+       // Vregs. The case where they might need to
+       // be saved is very unlikely.
+       MOVDU   R1, -544(R1)
+       MOVD    R14, 64(R1)
+       MOVD    R15, 72(R1)
+       MOVD    R16, 80(R1)
+       MOVD    R17, 88(R1)
+       MOVD    R18, 96(R1)
+       MOVD    R19, 104(R1)
+       MOVD    R20, 112(R1)
+       MOVD    R21, 120(R1)
+       MOVD    R22, 128(R1)
+       MOVD    R23, 136(R1)
+       MOVD    R24, 144(R1)
+       MOVD    R25, 152(R1)
+       MOVD    R26, 160(R1)
+       MOVD    R27, 168(R1)
+       MOVD    R28, 176(R1)
+       MOVD    R29, 184(R1)
+       MOVD    g, 192(R1) // R30
+       MOVD    R31, 200(R1)
+       FMOVD   F14, 208(R1)
+       FMOVD   F15, 216(R1)
+       FMOVD   F16, 224(R1)
+       FMOVD   F17, 232(R1)
+       FMOVD   F18, 240(R1)
+       FMOVD   F19, 248(R1)
+       FMOVD   F20, 256(R1)
+       FMOVD   F21, 264(R1)
+       FMOVD   F22, 272(R1)
+       FMOVD   F23, 280(R1)
+       FMOVD   F24, 288(R1)
+       FMOVD   F25, 296(R1)
+       FMOVD   F26, 304(R1)
+       FMOVD   F27, 312(R1)
+       FMOVD   F28, 320(R1)
+       FMOVD   F29, 328(R1)
+       FMOVD   F30, 336(R1)
+       FMOVD   F31, 344(R1)
+       // Save V regs
+       // STXVD2X and LXVD2X used since
+       // we aren't sure of alignment.
+       // Endianness doesn't matter
+       // if we are just loading and
+       // storing values.
+       MOVD    $352, R7 // V20
+       STXVD2X VS52, (R7)(R1)
+       ADD     $16, R7 // V21 368
+       STXVD2X VS53, (R7)(R1)
+       ADD     $16, R7 // V22 384
+       STXVD2X VS54, (R7)(R1)
+       ADD     $16, R7 // V23 400
+       STXVD2X VS55, (R7)(R1)
+       ADD     $16, R7 // V24 416
+       STXVD2X VS56, (R7)(R1)
+       ADD     $16, R7 // V25 432
+       STXVD2X VS57, (R7)(R1)
+       ADD     $16, R7 // V26 448
+       STXVD2X VS58, (R7)(R1)
+       ADD     $16, R7 // V27 464
+       STXVD2X VS59, (R7)(R1)
+       ADD     $16, R7 // V28 480
+       STXVD2X VS60, (R7)(R1)
+       ADD     $16, R7 // V29 496
+       STXVD2X VS61, (R7)(R1)
+       ADD     $16, R7 // V30 512
+       STXVD2X VS62, (R7)(R1)
+       ADD     $16, R7 // V31 528
+       STXVD2X VS63, (R7)(R1)
+
        // initialize essential registers (just in case)
        BL      runtime·reginit(SB)
 
@@ -376,7 +478,74 @@ TEXT sigtramp<>(SB),NOSPLIT,$64
        MOVD    $runtime·sigtrampgo(SB), R12
        MOVD    R12, CTR
        BL      (CTR)
-       MOVD    24(R1), R2
+       MOVD    24(R1), R2 // Should this be here? Where is it saved?
+       // Starts at 64; FIXED_FRAME is 32
+       MOVD    64(R1), R14
+       MOVD    72(R1), R15
+       MOVD    80(R1), R16
+       MOVD    88(R1), R17
+       MOVD    96(R1), R18
+       MOVD    104(R1), R19
+       MOVD    112(R1), R20
+       MOVD    120(R1), R21
+       MOVD    128(R1), R22
+       MOVD    136(R1), R23
+       MOVD    144(R1), R24
+       MOVD    152(R1), R25
+       MOVD    160(R1), R26
+       MOVD    168(R1), R27
+       MOVD    176(R1), R28
+       MOVD    184(R1), R29
+       MOVD    192(R1), g // R30
+       MOVD    200(R1), R31
+       FMOVD   208(R1), F14
+       FMOVD   216(R1), F15
+       FMOVD   224(R1), F16
+       FMOVD   232(R1), F17
+       FMOVD   240(R1), F18
+       FMOVD   248(R1), F19
+       FMOVD   256(R1), F20
+       FMOVD   264(R1), F21
+       FMOVD   272(R1), F22
+       FMOVD   280(R1), F23
+       FMOVD   288(R1), F24
+       FMOVD   292(R1), F25
+       FMOVD   300(R1), F26
+       FMOVD   308(R1), F27
+       FMOVD   316(R1), F28
+       FMOVD   328(R1), F29
+       FMOVD   336(R1), F30
+       FMOVD   344(R1), F31
+       MOVD    $352, R7
+       LXVD2X  (R7)(R1), VS52
+       ADD     $16, R7 // 368 V21
+       LXVD2X  (R7)(R1), VS53
+       ADD     $16, R7 // 384 V22
+       LXVD2X  (R7)(R1), VS54
+       ADD     $16, R7 // 400 V23
+       LXVD2X  (R7)(R1), VS55
+       ADD     $16, R7 // 416 V24
+       LXVD2X  (R7)(R1), VS56
+       ADD     $16, R7 // 432 V25
+       LXVD2X  (R7)(R1), VS57
+       ADD     $16, R7 // 448 V26
+       LXVD2X  (R7)(R1), VS58
+       ADD     $16, R8 // 464 V27
+       LXVD2X  (R7)(R1), VS59
+       ADD     $16, R7 // 480 V28
+       LXVD2X  (R7)(R1), VS60
+       ADD     $16, R7 // 496 V29
+       LXVD2X  (R7)(R1), VS61
+       ADD     $16, R7 // 512 V30
+       LXVD2X  (R7)(R1), VS62
+       ADD     $16, R7 // 528 V31
+       LXVD2X  (R7)(R1), VS63
+       ADD     $544, R1
+       MOVD    8(R1), R0
+       MOVFL   R0, $0xff
+       MOVD    16(R1), R0
+       MOVD    R0, LR
+
        RET
 
 #ifdef GOARCH_ppc64le
@@ -406,6 +575,7 @@ TEXT runtime·cgoSigtramp(SB),NOSPLIT|NOFRAME,$0
 
        // Figure out if we are currently in a cgo call.
        // If not, just do usual sigtramp.
+       // compared to ARM64 and others.
        CMP     $0, g
        BEQ     sigtrampnog // g == nil
        MOVD    g_m(g), R6