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
// 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)
} 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
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 */
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 */
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
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:
// 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>
// 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>
// 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
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.
// 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
// 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
--- /dev/null
+// 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
// 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.
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
#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)
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
// 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