--- /dev/null
+// Copyright 2015 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.
+
+// +build !windows
+
+package cgotest
+
+import "testing"
+
+func TestSigaltstack(t *testing.T) { testSigaltstack(t) }
--- /dev/null
+// Copyright 2015 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.
+
+// +build !windows
+
+// Test that the Go runtime still works if C code changes the signal stack.
+
+package cgotest
+
+/*
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static stack_t oss;
+static char signalStack[SIGSTKSZ];
+
+static void changeSignalStack() {
+ stack_t ss;
+ memset(&ss, 0, sizeof ss);
+ ss.ss_sp = signalStack;
+ ss.ss_flags = 0;
+ ss.ss_size = SIGSTKSZ;
+ if (sigaltstack(&ss, &oss) < 0) {
+ perror("sigaltstack");
+ abort();
+ }
+}
+
+static void restoreSignalStack() {
+#if defined(__x86_64__) && defined(__APPLE__)
+ // The Darwin C library enforces a minimum that the kernel does not.
+ // This is OK since we allocated this much space in mpreinit,
+ // it was just removed from the buffer by stackalloc.
+ oss.ss_size = MINSIGSTKSZ;
+#endif
+ if (sigaltstack(&oss, NULL) < 0) {
+ perror("sigaltstack restore");
+ abort();
+ }
+}
+
+static int zero() {
+ return 0;
+}
+*/
+import "C"
+
+import (
+ "runtime"
+ "testing"
+)
+
+func testSigaltstack(t *testing.T) {
+ switch {
+ case runtime.GOOS == "solaris", runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64"):
+ t.Skipf("switching signal stack not implemented on %s/s", runtime.GOOS, runtime.GOARCH)
+ }
+
+ C.changeSignalStack()
+ defer C.restoreSignalStack()
+ defer func() {
+ if recover() == nil {
+ t.Error("did not see expected panic")
+ }
+ }()
+ v := 1 / int(C.zero())
+ t.Errorf("unexpected success of division by zero == %d", v)
+}
}
}()
}
+
+// This is called when we receive a signal when there is no signal stack.
+// This can only happen if non-Go code calls sigaltstack to disable the
+// signal stack. This is called via cgocallback to establish a stack.
+func noSignalStack(sig uint32) {
+ println("signal", sig, "received on thread with no signal stack")
+ throw("non-Go code disabled sigaltstack")
+}
+
+// This is called if we receive a signal when there is a signal stack
+// but we are not on it. This can only happen if non-Go code called
+// sigaction without setting the SS_ONSTACK flag.
+func sigNotOnStack(sig uint32) {
+ println("signal", sig, "received but handler not on signal stack")
+ throw("non-Go code set up signal handler without SA_ONSTACK flag")
+}
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin linux
+// +build darwin dragonfly freebsd linux netbsd openbsd
package runtime
sigreturn(ctx, infostyle)
return
}
+
+ // If some non-Go code called sigaltstack, adjust.
+ sp := uintptr(unsafe.Pointer(&sig))
+ if sp < g.m.gsignal.stack.lo || sp >= g.m.gsignal.stack.hi {
+ var st stackt
+ sigaltstack(nil, &st)
+ if st.ss_flags&_SS_DISABLE != 0 {
+ setg(nil)
+ cgocallback(unsafe.Pointer(funcPC(noSignalStack)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig))
+ }
+ stsp := uintptr(unsafe.Pointer(st.ss_sp))
+ if sp < stsp || sp >= stsp+st.ss_size {
+ setg(nil)
+ cgocallback(unsafe.Pointer(funcPC(sigNotOnStack)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig))
+ }
+ g.m.gsignal.stack.lo = stsp
+ g.m.gsignal.stack.hi = stsp + st.ss_size
+ g.m.gsignal.stackguard0 = stsp + _StackGuard
+ g.m.gsignal.stackguard1 = stsp + _StackGuard
+ g.m.gsignal.stackAlloc = st.ss_size
+ g.m.gsignal.stktopsp = getcallersp(unsafe.Pointer(&sig))
+ }
+
setg(g.m.gsignal)
sighandler(sig, info, ctx, g)
setg(g)
package runtime
+import "unsafe"
+
type sigTabT struct {
flags int32
name string
/* 31 */ {_SigNotify, "SIGUSR2: user-defined signal 2"},
/* 32 */ {_SigNotify, "SIGTHR: reserved"},
}
+
+//go:nosplit
+func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
+ if sigfwdgo(sig, info, ctx) {
+ return
+ }
+ g := getg()
+ if g == nil {
+ badsignal(uintptr(sig))
+ return
+ }
+
+ // If some non-Go code called sigaltstack, adjust.
+ sp := uintptr(unsafe.Pointer(&sig))
+ if sp < g.m.gsignal.stack.lo || sp >= g.m.gsignal.stack.hi {
+ var st stackt
+ sigaltstack(nil, &st)
+ if st.ss_flags&_SS_DISABLE != 0 {
+ setg(nil)
+ cgocallback(unsafe.Pointer(funcPC(noSignalStack)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig))
+ }
+ stsp := uintptr(unsafe.Pointer(st.ss_sp))
+ if sp < stsp || sp >= stsp+st.ss_size {
+ setg(nil)
+ cgocallback(unsafe.Pointer(funcPC(sigNotOnStack)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig))
+ }
+ g.m.gsignal.stack.lo = stsp
+ g.m.gsignal.stack.hi = stsp + st.ss_size
+ g.m.gsignal.stackguard0 = stsp + _StackGuard
+ g.m.gsignal.stackguard1 = stsp + _StackGuard
+ g.m.gsignal.stackAlloc = st.ss_size
+ g.m.gsignal.stktopsp = getcallersp(unsafe.Pointer(&sig))
+ }
+
+ setg(g.m.gsignal)
+ sighandler(sig, info, ctx, g)
+ setg(g)
+}
+++ /dev/null
-// Copyright 2009 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 runtime
-
-import "unsafe"
-
-// Continuation of the (assembly) sigtramp() logic.
-//go:nosplit
-func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
- if sigfwdgo(sig, info, ctx) {
- return
- }
- g := getg()
- if g == nil {
- badsignal(uintptr(sig))
- return
- }
- setg(g.m.gsignal)
- sighandler(sig, info, ctx, g)
- setg(g)
-}
package runtime
+import "unsafe"
+
type sigTabT struct {
flags int32
name string
/* 31 */ {_SigNotify, "SIGUSR2: user-defined signal 2"},
/* 32 */ {_SigNotify, "SIGTHR: reserved"},
}
+
+//go:nosplit
+func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
+ if sigfwdgo(sig, info, ctx) {
+ return
+ }
+ g := getg()
+ if g == nil {
+ badsignal(uintptr(sig))
+ return
+ }
+
+ // If some non-Go code called sigaltstack, adjust.
+ sp := uintptr(unsafe.Pointer(&sig))
+ if sp < g.m.gsignal.stack.lo || sp >= g.m.gsignal.stack.hi {
+ var st stackt
+ sigaltstack(nil, &st)
+ if st.ss_flags&_SS_DISABLE != 0 {
+ setg(nil)
+ cgocallback(unsafe.Pointer(funcPC(noSignalStack)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig))
+ }
+ stsp := uintptr(unsafe.Pointer(st.ss_sp))
+ if sp < stsp || sp >= stsp+st.ss_size {
+ setg(nil)
+ cgocallback(unsafe.Pointer(funcPC(sigNotOnStack)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig))
+ }
+ g.m.gsignal.stack.lo = stsp
+ g.m.gsignal.stack.hi = stsp + st.ss_size
+ g.m.gsignal.stackguard0 = stsp + _StackGuard
+ g.m.gsignal.stackguard1 = stsp + _StackGuard
+ g.m.gsignal.stackAlloc = st.ss_size
+ g.m.gsignal.stktopsp = getcallersp(unsafe.Pointer(&sig))
+ }
+
+ setg(g.m.gsignal)
+ sighandler(sig, info, ctx, g)
+ setg(g)
+}
--- /dev/null
+// Copyright 2009 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.
+
+// +build dragonfly linux netbsd
+
+package runtime
+
+import "unsafe"
+
+// Continuation of the (assembly) sigtramp() logic.
+//go:nosplit
+func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
+ if sigfwdgo(sig, info, ctx) {
+ return
+ }
+ g := getg()
+ if g == nil {
+ badsignal(uintptr(sig))
+ return
+ }
+
+ // If some non-Go code called sigaltstack, adjust.
+ sp := uintptr(unsafe.Pointer(&sig))
+ if sp < g.m.gsignal.stack.lo || sp >= g.m.gsignal.stack.hi {
+ var st sigaltstackt
+ sigaltstack(nil, &st)
+ if st.ss_flags&_SS_DISABLE != 0 {
+ setg(nil)
+ cgocallback(unsafe.Pointer(funcPC(noSignalStack)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig))
+ }
+ stsp := uintptr(unsafe.Pointer(st.ss_sp))
+ if sp < stsp || sp >= stsp+st.ss_size {
+ setg(nil)
+ cgocallback(unsafe.Pointer(funcPC(sigNotOnStack)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig))
+ }
+ g.m.gsignal.stack.lo = stsp
+ g.m.gsignal.stack.hi = stsp + st.ss_size
+ g.m.gsignal.stackguard0 = stsp + _StackGuard
+ g.m.gsignal.stackguard1 = stsp + _StackGuard
+ g.m.gsignal.stackAlloc = st.ss_size
+ g.m.gsignal.stktopsp = getcallersp(unsafe.Pointer(&sig))
+ }
+
+ setg(g.m.gsignal)
+ sighandler(sig, info, ctx, g)
+ setg(g)
+}
MOVL $0xf1, 0xf1 // crash
RET
-// Sigtramp's job is to call the actual signal handler.
-// It is called with the following arguments on the stack:
-// 0(FP) "return address" - ignored
-// 4(FP) actual handler
-// 8(FP) signal number
-// 12(FP) siginfo style
-// 16(FP) siginfo
-// 20(FP) context
-TEXT runtime·sigtramp(SB),NOSPLIT,$40
- get_tls(CX)
-
- // check that g exists
- MOVL g(CX), DI
- CMPL DI, $0
- JNE 6(PC)
- MOVL sig+8(FP), BX
- MOVL BX, 0(SP)
- MOVL $runtime·badsignal(SB), AX
+TEXT runtime·sigfwd(SB),NOSPLIT,$12-16
+ MOVL sig+4(FP), AX
+ MOVL AX, 0(SP)
+ MOVL info+8(FP), AX
+ MOVL AX, 4(SP)
+ MOVL ctx+12(FP), AX
+ MOVL AX, 8(SP)
+ MOVL fn+0(FP), AX
CALL AX
- JMP ret
-
- // save g
- MOVL DI, 20(SP)
+ RET
- // g = m->gsignal
- MOVL g_m(DI), BP
- MOVL m_gsignal(BP), BP
- MOVL BP, g(CX)
+TEXT runtime·sigreturn(SB),NOSPLIT,$12-8
+ MOVL ctx+0(FP), CX
+ MOVL infostyle+4(FP), BX
+ MOVL $0, 0(SP) // "caller PC" - ignored
+ MOVL CX, 4(SP)
+ MOVL BX, 8(SP)
+ MOVL $184, AX // sigreturn(ucontext, infostyle)
+ INT $0x80
+ MOVL $0xf1, 0xf1 // crash
+ RET
- // copy arguments to sighandler
- MOVL sig+8(FP), BX
+// Sigtramp's job is to call the actual signal handler.
+// It is called with the following arguments on the stack:
+// 0(SP) "return address" - ignored
+// 4(SP) actual handler
+// 8(SP) signal number
+// 12(SP) siginfo style
+// 16(SP) siginfo
+// 20(SP) context
+TEXT runtime·sigtramp(SB),NOSPLIT,$20
+ MOVL fn+0(FP), BX
MOVL BX, 0(SP)
- MOVL info+12(FP), BX
+ MOVL style+4(FP), BX
MOVL BX, 4(SP)
- MOVL context+16(FP), BX
+ MOVL sig+8(FP), BX
MOVL BX, 8(SP)
- MOVL DI, 12(SP)
-
- MOVL handler+0(FP), BX
- CALL BX
-
- // restore g
- get_tls(CX)
- MOVL 20(SP), DI
- MOVL DI, g(CX)
+ MOVL info+12(FP), BX
+ MOVL BX, 12(SP)
+ MOVL context+16(FP), BX
+ MOVL BX, 16(SP)
+ CALL runtime·sigtrampgo(SB)
-ret:
// call sigreturn
MOVL context+16(FP), CX
MOVL style+4(FP), BX
MOVW R1, ret_hi+4(FP)
RET
+TEXT runtime·sigfwd(SB),NOSPLIT,$0-16
+ MOVW sig+4(FP), R0
+ MOVW info+8(FP), R1
+ MOVW ctx+12(FP), R2
+ MOVW fn+0(FP), R11
+ MOVW R13, R4
+ SUB $24, R13
+ BIC $0x7, R13 // alignment for ELF ABI
+ BL (R11)
+ MOVW R4, R13
+ RET
+
// Sigtramp's job is to call the actual signal handler.
// It is called with the following arguments on the stack:
// LR "return address" - ignored
MOVD R0, ret+0(FP)
RET
+TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
+ MOVW sig+8(FP), R0
+ MOVD info+16(FP), R1
+ MOVD ctx+24(FP), R2
+ MOVD fn+0(FP), R11
+ BL (R11)
+ RET
+
// Sigtramp's job is to call the actual signal handler.
// It is called with the following arguments on the stack:
// LR "return address" - ignored
MOVL $0xf1, 0xf1 // crash
RET
-TEXT runtime·sigtramp(SB),NOSPLIT,$64
- get_tls(BX)
-
- // check that g exists
- MOVQ g(BX), R10
- CMPQ R10, $0
- JNE 5(PC)
- MOVQ DI, 0(SP)
- MOVQ $runtime·badsignal(SB), AX
+TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
+ MOVL sig+8(FP), DI
+ MOVQ info+16(FP), SI
+ MOVQ ctx+24(FP), DX
+ MOVQ fn+0(FP), AX
CALL AX
RET
- // save g
- MOVQ R10, 40(SP)
-
- // g = m->signal
- MOVQ g_m(R10), AX
- MOVQ m_gsignal(AX), AX
- MOVQ AX, g(BX)
-
+TEXT runtime·sigtramp(SB),NOSPLIT,$24
MOVQ DI, 0(SP)
MOVQ SI, 8(SP)
MOVQ DX, 16(SP)
- MOVQ R10, 24(SP)
-
- CALL runtime·sighandler(SB)
-
- // restore g
- get_tls(BX)
- MOVQ 40(SP), R10
- MOVQ R10, g(BX)
+ CALL runtime·sigtrampgo(SB)
RET
TEXT runtime·mmap(SB),NOSPLIT,$0
MOVL $0xf1, 0xf1 // crash
RET
-TEXT runtime·sigtramp(SB),NOSPLIT,$44
- get_tls(CX)
-
- // check that g exists
- MOVL g(CX), DI
- CMPL DI, $0
- JNE 6(PC)
- MOVL signo+0(FP), BX
- MOVL BX, 0(SP)
- MOVL $runtime·badsignal(SB), AX
+TEXT runtime·sigfwd(SB),NOSPLIT,$12-16
+ MOVL sig+4(FP), AX
+ MOVL AX, 0(SP)
+ MOVL info+8(FP), AX
+ MOVL AX, 4(SP)
+ MOVL ctx+12(FP), AX
+ MOVL AX, 8(SP)
+ MOVL fn+0(FP), AX
CALL AX
- JMP ret
-
- // save g
- MOVL DI, 20(SP)
-
- // g = m->gsignal
- MOVL g_m(DI), BX
- MOVL m_gsignal(BX), BX
- MOVL BX, g(CX)
+ RET
- // copy arguments for call to sighandler
+TEXT runtime·sigtramp(SB),NOSPLIT,$12
MOVL signo+0(FP), BX
MOVL BX, 0(SP)
MOVL info+4(FP), BX
MOVL BX, 4(SP)
MOVL context+8(FP), BX
MOVL BX, 8(SP)
- MOVL DI, 12(SP)
-
- CALL runtime·sighandler(SB)
-
- // restore g
- get_tls(CX)
- MOVL 20(SP), BX
- MOVL BX, g(CX)
+ CALL runtime·sigtrampgo(SB)
-ret:
// call sigreturn
MOVL context+8(FP), AX
MOVL $0, 0(SP) // syscall gap
MOVL $0xf1, 0xf1 // crash
RET
-TEXT runtime·sigtramp(SB),NOSPLIT,$64
- get_tls(BX)
-
- // check that g exists
- MOVQ g(BX), R10
- CMPQ R10, $0
- JNE 5(PC)
- MOVQ DI, 0(SP)
- MOVQ $runtime·badsignal(SB), AX
+TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
+ MOVL sig+8(FP), DI
+ MOVQ info+16(FP), SI
+ MOVQ ctx+24(FP), DX
+ MOVQ fn+0(FP), AX
CALL AX
RET
- // save g
- MOVQ R10, 40(SP)
-
- // g = m->signal
- MOVQ g_m(R10), AX
- MOVQ m_gsignal(AX), AX
- MOVQ AX, g(BX)
-
+TEXT runtime·sigtramp(SB),NOSPLIT,$24
MOVQ DI, 0(SP)
MOVQ SI, 8(SP)
MOVQ DX, 16(SP)
- MOVQ R10, 24(SP)
-
- CALL runtime·sighandler(SB)
-
- // restore g
- get_tls(BX)
- MOVQ 40(SP), R10
- MOVQ R10, g(BX)
+ CALL runtime·sigtrampgo(SB)
RET
TEXT runtime·mmap(SB),NOSPLIT,$0
MOVW.CS R8, (R8)
RET
-TEXT runtime·sigtramp(SB),NOSPLIT,$24
+TEXT runtime·sigtramp(SB),NOSPLIT,$12
// this might be called in external code context,
// where g is not set.
// first save R0, because runtime·load_g will clobber it
CMP $0, R0
BL.NE runtime·load_g(SB)
- CMP $0, g
- BNE 4(PC)
- // signal number is already prepared in 4(R13)
- MOVW $runtime·badsignal(SB), R11
- BL (R11)
- RET
-
- // save g
- MOVW g, R4
- MOVW g, 20(R13)
-
- // g = m->signal
- MOVW g_m(g), R8
- MOVW m_gsignal(R8), g
-
- // R0 is already saved
- MOVW R1, 8(R13) // info
- MOVW R2, 12(R13) // context
- MOVW R4, 16(R13) // oldg
-
- BL runtime·sighandler(SB)
-
- // restore g
- MOVW 20(R13), g
+ MOVW R1, 8(R13)
+ MOVW R2, 12(R13)
+ BL runtime·sigtrampgo(SB)
RET
TEXT runtime·mmap(SB),NOSPLIT,$16
MOVW.CS R8, (R8)
RET
+TEXT runtime·sigfwd(SB),NOSPLIT,$0-16
+ MOVW sig+4(FP), R0
+ MOVW info+8(FP), R1
+ MOVW ctx+12(FP), R2
+ MOVW fn+0(FP), R11
+ MOVW R13, R4
+ SUB $24, R13
+ BIC $0x7, R13 // alignment for ELF ABI
+ BL (R11)
+ MOVW R4, R13
+ RET
+
TEXT runtime·usleep(SB),NOSPLIT,$16
MOVW usec+0(FP), R0
CALL runtime·usplitR0(SB)
MOVL $0xf1, 0xf1 // crash
RET
-TEXT runtime·sigtramp(SB),NOSPLIT,$44
- get_tls(CX)
-
- // check that g exists
- MOVL g(CX), DI
- CMPL DI, $0
- JNE 6(PC)
- MOVL signo+0(FP), BX
- MOVL BX, 0(SP)
- MOVL $runtime·badsignal(SB), AX
+TEXT runtime·sigfwd(SB),NOSPLIT,$12-16
+ MOVL sig+4(FP), AX
+ MOVL AX, 0(SP)
+ MOVL info+8(FP), AX
+ MOVL AX, 4(SP)
+ MOVL ctx+12(FP), AX
+ MOVL AX, 8(SP)
+ MOVL fn+0(FP), AX
CALL AX
RET
- // save g
- MOVL DI, 20(SP)
-
- // g = m->gsignal
- MOVL g_m(DI), BX
- MOVL m_gsignal(BX), BX
- MOVL BX, g(CX)
-
- // copy arguments for call to sighandler
+TEXT runtime·sigtramp(SB),NOSPLIT,$12
MOVL signo+0(FP), BX
MOVL BX, 0(SP)
MOVL info+4(FP), BX
MOVL BX, 4(SP)
MOVL context+8(FP), BX
MOVL BX, 8(SP)
- MOVL DI, 12(SP)
-
- CALL runtime·sighandler(SB)
-
- // restore g
- get_tls(CX)
- MOVL 20(SP), BX
- MOVL BX, g(CX)
+ CALL runtime·sigtrampgo(SB)
RET
// int32 lwp_create(void *context, uintptr flags, void *lwpid);
MOVL $0xf1, 0xf1 // crash
RET
-TEXT runtime·sigtramp(SB),NOSPLIT,$64
- get_tls(BX)
-
- // check that g exists
- MOVQ g(BX), R10
- CMPQ R10, $0
- JNE 5(PC)
- MOVQ DI, 0(SP)
- MOVQ $runtime·badsignal(SB), AX
+TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
+ MOVL sig+8(FP), DI
+ MOVQ info+16(FP), SI
+ MOVQ ctx+24(FP), DX
+ MOVQ fn+0(FP), AX
CALL AX
RET
- // save g
- MOVQ R10, 40(SP)
-
- // g = m->signal
- MOVQ g_m(R10), AX
- MOVQ m_gsignal(AX), AX
- MOVQ AX, g(BX)
-
- MOVQ DI, 0(SP)
- MOVQ SI, 8(SP)
- MOVQ DX, 16(SP)
- MOVQ R10, 24(SP)
-
- CALL runtime·sighandler(SB)
-
- // restore g
- get_tls(BX)
- MOVQ 40(SP), R10
- MOVQ R10, g(BX)
+TEXT runtime·sigtramp(SB),NOSPLIT,$24
+ MOVQ DI, 0(SP) // signum
+ MOVQ SI, 8(SP) // info
+ MOVQ DX, 16(SP) // ctx
+ CALL runtime·sigtrampgo(SB)
RET
TEXT runtime·mmap(SB),NOSPLIT,$0
MOVW.CS R8, (R8)
RET
-TEXT runtime·sigtramp(SB),NOSPLIT,$24
+TEXT runtime·sigfwd(SB),NOSPLIT,$0-16
+ MOVW sig+4(FP), R0
+ MOVW info+8(FP), R1
+ MOVW ctx+12(FP), R2
+ MOVW fn+0(FP), R11
+ MOVW R13, R4
+ SUB $24, R13
+ BIC $0x7, R13 // alignment for ELF ABI
+ BL (R11)
+ MOVW R4, R13
+ RET
+
+TEXT runtime·sigtramp(SB),NOSPLIT,$12
// this might be called in external code context,
// where g is not set.
// first save R0, because runtime·load_g will clobber it
CMP $0, R0
BL.NE runtime·load_g(SB)
- CMP $0, g
- BNE 4(PC)
- // signal number is already prepared in 4(R13)
- MOVW $runtime·badsignal(SB), R11
- BL (R11)
- RET
-
- // save g
- MOVW g, R4
- MOVW g, 20(R13)
-
- // g = m->signal
- MOVW g_m(g), R8
- MOVW m_gsignal(R8), g
-
- // R0 is already saved
- MOVW R1, 8(R13) // info
- MOVW R2, 12(R13) // context
- MOVW R4, 16(R13) // gp
-
- BL runtime·sighandler(SB)
-
- // restore g
- MOVW 20(R13), g
+ MOVW R1, 8(R13)
+ MOVW R2, 12(R13)
+ BL runtime·sigtrampgo(SB)
RET
TEXT runtime·mmap(SB),NOSPLIT,$12
MOVL AX, ret+8(FP)
RET
-TEXT runtime·sigtramp(SB),NOSPLIT,$44
- get_tls(CX)
-
- // check that g exists
- MOVL g(CX), DI
- CMPL DI, $0
- JNE 6(PC)
- MOVL signo+0(FP), BX
- MOVL BX, 0(SP)
- MOVL $runtime·badsignal(SB), AX
+TEXT runtime·sigfwd(SB),NOSPLIT,$12-16
+ MOVL sig+4(FP), AX
+ MOVL AX, 0(SP)
+ MOVL info+8(FP), AX
+ MOVL AX, 4(SP)
+ MOVL ctx+12(FP), AX
+ MOVL AX, 8(SP)
+ MOVL fn+0(FP), AX
CALL AX
- JMP ret
-
- // save g
- MOVL DI, 20(SP)
-
- // g = m->gsignal
- MOVL g_m(DI), BX
- MOVL m_gsignal(BX), BX
- MOVL BX, g(CX)
+ RET
- // copy arguments for call to sighandler
+TEXT runtime·sigtramp(SB),NOSPLIT,$12
MOVL signo+0(FP), BX
MOVL BX, 0(SP)
MOVL info+4(FP), BX
MOVL BX, 4(SP)
MOVL context+8(FP), BX
MOVL BX, 8(SP)
- MOVL DI, 12(SP)
-
- CALL runtime·sighandler(SB)
-
- // restore g
- get_tls(CX)
- MOVL 20(SP), BX
- MOVL BX, g(CX)
+ CALL runtime·sigtrampgo(SB)
-ret:
// call sigreturn
MOVL context+8(FP), AX
MOVL $0, 0(SP) // syscall gap
MOVL AX, ret+8(FP)
RET
-TEXT runtime·sigtramp(SB),NOSPLIT,$64
- get_tls(BX)
-
- // check that g exists
- MOVQ g(BX), R10
- CMPQ R10, $0
- JNE 5(PC)
- MOVQ DI, 0(SP)
- MOVQ $runtime·badsignal(SB), AX
+TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
+ MOVL sig+8(FP), DI
+ MOVQ info+16(FP), SI
+ MOVQ ctx+24(FP), DX
+ MOVQ fn+0(FP), AX
CALL AX
RET
- // save g
- MOVQ R10, 40(SP)
-
- // g = m->signal
- MOVQ g_m(R10), AX
- MOVQ m_gsignal(AX), AX
- MOVQ AX, g(BX)
-
+TEXT runtime·sigtramp(SB),NOSPLIT,$24
MOVQ DI, 0(SP)
MOVQ SI, 8(SP)
MOVQ DX, 16(SP)
- MOVQ R10, 24(SP)
-
- CALL runtime·sighandler(SB)
-
- // restore g
- get_tls(BX)
- MOVQ 40(SP), R10
- MOVQ R10, g(BX)
+ CALL runtime·sigtrampgo(SB)
RET
TEXT runtime·mmap(SB),NOSPLIT,$0
MOVW R0, ret+8(FP)
RET
-TEXT runtime·sigtramp(SB),NOSPLIT,$24
+TEXT runtime·sigfwd(SB),NOSPLIT,$0-16
+ MOVW sig+4(FP), R0
+ MOVW info+8(FP), R1
+ MOVW ctx+12(FP), R2
+ MOVW fn+0(FP), R11
+ MOVW R13, R4
+ SUB $24, R13
+ BIC $0x7, R13 // alignment for ELF ABI
+ BL (R11)
+ MOVW R4, R13
+ RET
+
+TEXT runtime·sigtramp(SB),NOSPLIT,$12
// If called from an external code context, g will not be set.
// Save R0, since runtime·load_g will clobber it.
MOVW R0, 4(R13) // signum
CMP $0, R0
BL.NE runtime·load_g(SB)
- CMP $0, g
- BNE 4(PC)
- // Signal number saved in 4(R13).
- MOVW runtime·badsignal(SB), R11
- BL (R11)
- RET
-
- // Save g.
- MOVW g, R3
- MOVW g, 20(R13)
-
- // g = m->signal
- MOVW g_m(g), R8
- MOVW m_gsignal(R8), g
-
- // R0 already saved.
- MOVW R1, 8(R13) // info
- MOVW R2, 12(R13) // context
- MOVW R3, 16(R13) // gp (original g)
-
- BL runtime·sighandler(SB)
-
- // Restore g.
- MOVW 20(R13), g
+ MOVW R1, 8(R13)
+ MOVW R2, 12(R13)
+ BL runtime·sigtrampgo(SB)
RET
// int32 tfork(void *param, uintptr psize, M *mp, G *gp, void (*fn)(void));
MOVQ m_gsignal(BP), BP
MOVQ BP, g(BX)
+ // TODO: If current SP is not in gsignal.stack, then adjust.
+
// prepare call
MOVQ DI, 0(SP)
MOVQ SI, 8(SP)