sigaction, sigprocmask, sigaltstack, and raiseproc.
Fix bug in mstart_stub where we weren't saving callee-saved registers,
so if an m finished the pthread library calling mstart_stub would
sometimes fail.
Update #17490
Update #22805
Change-Id: Ie297ede0997910aa956834e49e85711b90cdfaa7
Reviewed-on: https://go-review.googlesource.com/116875
Run-TryBot: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
type Sigaction C.struct___sigaction // used in syscalls
type Usigaction C.struct_sigaction // used by sigaction second argument
+type Sigset C.sigset_t
type Sigval C.union_sigval
type Siginfo C.siginfo_t
type Timeval C.struct_timeval
func minit() {
// The alternate signal stack is buggy on arm and arm64.
// The signal handler handles it directly.
- // The sigaltstack assembly function does nothing.
if GOARCH != "arm" && GOARCH != "arm64" {
minitSignalStack()
}
_SS_DISABLE = 4
)
-//go:noescape
-func sigprocmask(how int32, new, old *sigset)
-
-//go:noescape
-func sigaction(mode uint32, new *sigactiont, old *usigactiont)
-
-//go:noescape
-func sigaltstack(new, old *stackt)
-
-// darwin/arm64 uses registers instead of stack-based arguments.
-// TODO: does this matter?
-func sigtramp(fn uintptr, infostyle, sig uint32, info *siginfo, ctx unsafe.Pointer)
-
//go:noescape
func setitimer(mode int32, new, old *itimerval)
-func raiseproc(sig uint32)
-
//extern SigTabTT runtime·sigtab[];
type sigset uint32
//go:nosplit
//go:nowritebarrierrec
func setsig(i uint32, fn uintptr) {
- var sa sigactiont
+ var sa usigactiont
sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
sa.sa_mask = ^uint32(0)
- sa.sa_tramp = unsafe.Pointer(funcPC(sigtramp)) // runtime·sigtramp's job is to call into real handler
+ if fn == funcPC(sighandler) {
+ fn = funcPC(sigtramp)
+ }
*(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = fn
sigaction(i, &sa, nil)
}
+// sigtramp is the callback from libc when a signal is received.
+// It is called with the C calling convention.
+func sigtramp()
+
//go:nosplit
//go:nowritebarrierrec
func setsigstack(i uint32) {
if osa.sa_flags&_SA_ONSTACK != 0 {
return
}
- var sa sigactiont
+ var sa usigactiont
*(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = handler
- sa.sa_tramp = unsafe.Pointer(funcPC(sigtramp))
sa.sa_mask = osa.sa_mask
sa.sa_flags = osa.sa_flags | _SA_ONSTACK
sigaction(i, &sa, nil)
}
func walltime_trampoline()
+//go:nosplit
+//go:cgo_unsafe_args
+func sigaction(sig uint32, new *usigactiont, old *usigactiont) {
+ asmcgocall(unsafe.Pointer(funcPC(sigaction_trampoline)), unsafe.Pointer(&sig))
+}
+func sigaction_trampoline()
+
+//go:nosplit
+//go:cgo_unsafe_args
+func sigprocmask(how uint32, new *sigset, old *sigset) {
+ asmcgocall(unsafe.Pointer(funcPC(sigprocmask_trampoline)), unsafe.Pointer(&how))
+}
+func sigprocmask_trampoline()
+
+//go:nosplit
+//go:cgo_unsafe_args
+func sigaltstack(new *stackt, old *stackt) {
+ if new != nil && new.ss_flags&_SS_DISABLE != 0 && new.ss_size == 0 {
+ // Despite the fact that Darwin's sigaltstack man page says it ignores the size
+ // when SS_DISABLE is set, it doesn't. sigaltstack returns ENOMEM
+ // if we don't give it a reasonable size.
+ // ref: http://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20140421/214296.html
+ new.ss_size = 32768
+ }
+ asmcgocall(unsafe.Pointer(funcPC(sigaltstack_trampoline)), unsafe.Pointer(&new))
+}
+func sigaltstack_trampoline()
+
+//go:nosplit
+//go:cgo_unsafe_args
+func raiseproc(sig uint32) {
+ asmcgocall(unsafe.Pointer(funcPC(raiseproc_trampoline)), unsafe.Pointer(&sig))
+}
+func raiseproc_trampoline()
+
// Not used on Darwin, but must be defined.
func exitThread(wait *uint32) {
}
//go:cgo_import_dynamic libc_mach_timebase_info mach_timebase_info "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_mach_absolute_time mach_absolute_time "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_gettimeofday gettimeofday "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic libc_sigaction sigaction "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic libc_pthread_sigmask pthread_sigmask "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic libc_sigaltstack sigaltstack "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic libc_getpid getpid "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic libc_kill kill "/usr/lib/libSystem.B.dylib"
// Magic incantation to get libSystem actually dynamically linked.
// TODO: Why does the code require this? See cmd/compile/internal/ld/go.go:210
POPL BP
RET
-TEXT runtime·raiseproc(SB),NOSPLIT,$16
- MOVL $20, AX // getpid
- INT $0x80
- MOVL AX, 4(SP) // pid
- MOVL sig+0(FP), AX
- MOVL AX, 8(SP) // signal
- MOVL $1, 12(SP) // posix
- MOVL $37, AX // kill
- INT $0x80
- RET
-
TEXT runtime·mmap_trampoline(SB),NOSPLIT,$0
PUSHL BP
MOVL SP, BP
POPL BP
RET
-TEXT runtime·sigprocmask(SB),NOSPLIT,$0
- MOVL $329, AX // pthread_sigmask (on OS X, sigprocmask==entire process)
- INT $0x80
- JAE 2(PC)
+TEXT runtime·sigaction_trampoline(SB),NOSPLIT,$0
+ PUSHL BP
+ MOVL SP, BP
+ SUBL $24, SP
+ MOVL 32(SP), CX
+ MOVL 0(CX), AX // arg 1 sig
+ MOVL AX, 0(SP)
+ MOVL 4(CX), AX // arg 2 new
+ MOVL AX, 4(SP)
+ MOVL 8(CX), AX // arg 3 old
+ MOVL AX, 8(SP)
+ CALL libc_sigaction(SB)
+ TESTL AX, AX
+ JEQ 2(PC)
MOVL $0xf1, 0xf1 // crash
+ MOVL BP, SP
+ POPL BP
RET
-TEXT runtime·sigaction(SB),NOSPLIT,$0
- MOVL $46, AX
- INT $0x80
- JAE 2(PC)
+TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0
+ PUSHL BP
+ MOVL SP, BP
+ SUBL $24, SP
+ MOVL 32(SP), CX
+ MOVL 0(CX), AX // arg 1 how
+ MOVL AX, 0(SP)
+ MOVL 4(CX), AX // arg 2 new
+ MOVL AX, 4(SP)
+ MOVL 8(CX), AX // arg 3 old
+ MOVL AX, 8(SP)
+ CALL libc_pthread_sigmask(SB)
+ TESTL AX, AX
+ JEQ 2(PC)
+ MOVL $0xf1, 0xf1 // crash
+ MOVL BP, SP
+ POPL BP
+ RET
+
+TEXT runtime·sigaltstack_trampoline(SB),NOSPLIT,$0
+ PUSHL BP
+ MOVL SP, BP
+ SUBL $8, SP
+ MOVL 16(SP), CX
+ MOVL 0(CX), AX // arg 1 new
+ MOVL AX, 0(SP)
+ MOVL 4(CX), AX // arg 2 old
+ MOVL AX, 4(SP)
+ CALL libc_sigaltstack(SB)
+ TESTL AX, AX
+ JEQ 2(PC)
MOVL $0xf1, 0xf1 // crash
+ MOVL BP, SP
+ POPL BP
+ RET
+
+TEXT runtime·raiseproc_trampoline(SB),NOSPLIT,$0
+ PUSHL BP
+ MOVL SP, BP
+ SUBL $8, SP
+ CALL libc_getpid(SB)
+ MOVL AX, 0(SP) // arg 1 pid
+ MOVL 16(SP), CX
+ MOVL 0(CX), AX
+ MOVL AX, 4(SP) // arg 2 signal
+ CALL libc_kill(SB)
+ MOVL BP, SP
+ POPL BP
RET
TEXT runtime·sigfwd(SB),NOSPLIT,$0-16
RET
// 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) siginfo style
-// 12(SP) signal number
-// 16(SP) siginfo
-// 20(SP) context
-TEXT runtime·sigtramp(SB),NOSPLIT,$20
- MOVL sig+8(FP), BX
- MOVL BX, 0(SP)
- MOVL info+12(FP), BX
- MOVL BX, 4(SP)
- MOVL ctx+16(FP), BX
- MOVL BX, 8(SP)
+// It is called with the C calling convention, and calls out
+// to sigtrampgo with the Go calling convention.
+TEXT runtime·sigtramp(SB),NOSPLIT,$0
+ SUBL $28, SP
+
+ // Save callee-save registers.
+ MOVL BP, 12(SP)
+ MOVL BX, 16(SP)
+ MOVL SI, 20(SP)
+ MOVL DI, 24(SP)
+
+ MOVL 32(SP), AX
+ MOVL AX, 0(SP) // arg 1 signal number
+ MOVL 36(SP), AX
+ MOVL AX, 4(SP) // arg 2 siginfo
+ MOVL 40(SP), AX
+ MOVL AX, 8(SP) // arg 3 ctxt
CALL runtime·sigtrampgo(SB)
- // call sigreturn
- MOVL ctx+16(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
+ // Restore callee-save registers.
+ MOVL 12(SP), BP
+ MOVL 16(SP), BX
+ MOVL 20(SP), SI
+ MOVL 24(SP), DI
-TEXT runtime·sigaltstack(SB),NOSPLIT,$0
- MOVL $53, AX
- INT $0x80
- JAE 2(PC)
- MOVL $0xf1, 0xf1 // crash
+ ADDL $28, SP
RET
TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0
// The value at SP+4 points to the m.
// We are already on m's g0 stack.
+ // Save callee-save registers.
+ SUBL $16, SP
+ MOVL BP, 0(SP)
+ MOVL BX, 4(SP)
+ MOVL SI, 8(SP)
+ MOVL DI, 12(SP)
+
MOVL SP, AX // hide argument read from vet (vet thinks this function is using the Go calling convention)
- MOVL 4(AX), DI // m
+ MOVL 20(AX), DI // m
MOVL m_g0(DI), DX // g
// Initialize TLS entry.
CALL runtime·mstart(SB)
+ // Restore callee-save registers.
+ MOVL 0(SP), BP
+ MOVL 4(SP), BX
+ MOVL 8(SP), SI
+ MOVL 12(SP), DI
+
// Go is all done with this OS thread.
// Tell pthread everything is ok (we never join with this thread, so
// the value here doesn't really matter).
XORL AX, AX
+
+ ADDL $16, SP
RET
TEXT runtime·pthread_attr_init_trampoline(SB),NOSPLIT,$0
POPQ BP
RET
-TEXT runtime·raiseproc(SB),NOSPLIT,$24
- MOVL $(0x2000000+20), AX // getpid
- SYSCALL
- MOVQ AX, DI // arg 1 - pid
- MOVL sig+0(FP), SI // arg 2 - signal
- MOVL $1, DX // arg 3 - posix
- MOVL $(0x2000000+37), AX // kill
- SYSCALL
- RET
-
TEXT runtime·setitimer(SB), NOSPLIT, $0
MOVL mode+0(FP), DI
MOVQ new+8(FP), SI
POPQ BP
RET
-TEXT runtime·sigprocmask(SB),NOSPLIT,$0
- MOVL how+0(FP), DI
- MOVQ new+8(FP), SI
- MOVQ old+16(FP), DX
- MOVL $(0x2000000+329), AX // pthread_sigmask (on OS X, sigprocmask==entire process)
- SYSCALL
- JCC 2(PC)
+TEXT runtime·sigaction_trampoline(SB),NOSPLIT,$0
+ PUSHQ BP
+ MOVQ SP, BP
+ MOVQ 8(DI), SI // arg 2 new
+ MOVQ 16(DI), DX // arg 3 old
+ MOVL 0(DI), DI // arg 1 sig
+ CALL libc_sigaction(SB)
+ TESTL AX, AX
+ JEQ 2(PC)
MOVL $0xf1, 0xf1 // crash
+ POPQ BP
RET
-TEXT runtime·sigaction(SB),NOSPLIT,$0-24
- MOVL mode+0(FP), DI // arg 1 sig
- MOVQ new+8(FP), SI // arg 2 act
- MOVQ old+16(FP), DX // arg 3 oact
- MOVQ old+16(FP), CX // arg 3 oact
- MOVQ old+16(FP), R10 // arg 3 oact
- MOVL $(0x2000000+46), AX // syscall entry
- SYSCALL
- JCC 2(PC)
+TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0
+ PUSHQ BP
+ MOVQ SP, BP
+ MOVQ 8(DI), SI // arg 2 new
+ MOVQ 16(DI), DX // arg 3 old
+ MOVL 0(DI), DI // arg 1 how
+ CALL libc_pthread_sigmask(SB)
+ TESTL AX, AX
+ JEQ 2(PC)
+ MOVL $0xf1, 0xf1 // crash
+ POPQ BP
+ RET
+
+TEXT runtime·sigaltstack_trampoline(SB),NOSPLIT,$0
+ PUSHQ BP
+ MOVQ SP, BP
+ MOVQ 8(DI), SI // arg 2 old
+ MOVQ 0(DI), DI // arg 1 new
+ CALL libc_sigaltstack(SB)
+ TESTQ AX, AX
+ JEQ 2(PC)
MOVL $0xf1, 0xf1 // crash
+ POPQ BP
+ RET
+
+TEXT runtime·raiseproc_trampoline(SB),NOSPLIT,$0
+ PUSHQ BP
+ MOVQ SP, BP
+ MOVL 0(DI), BX // signal
+ CALL libc_getpid(SB)
+ MOVL AX, DI // arg 1 pid
+ MOVL BX, SI // arg 2 signal
+ CALL libc_kill(SB)
+ POPQ BP
RET
TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
POPQ BP
RET
-TEXT runtime·sigtramp(SB),NOSPLIT,$40
- MOVL SI, 24(SP) // save infostyle for sigreturn below
- MOVQ R8, 32(SP) // save ctx
- MOVL DX, 0(SP) // sig
- MOVQ CX, 8(SP) // info
- MOVQ R8, 16(SP) // ctx
- MOVQ $runtime·sigtrampgo(SB), AX
- CALL AX
- MOVQ 32(SP), DI // ctx
- MOVL 24(SP), SI // infostyle
- MOVL $(0x2000000+184), AX
- SYSCALL
- INT $3 // not reached
-
+// This is the function registered during sigaction and is invoked when
+// a signal is received. It just redirects to the Go function sigtrampgo.
+TEXT runtime·sigtramp(SB),NOSPLIT,$0
+ // This runs on the signal stack, so we have lots of stack available.
+ // We allocate our own stack space, because if we tell the linker
+ // how much we're using, the NOSPLIT check fails.
+ PUSHQ BP
+ MOVQ SP, BP
+ SUBQ $64, SP
+
+ // Save callee-save registers.
+ MOVQ BX, 24(SP)
+ MOVQ R12, 32(SP)
+ MOVQ R13, 40(SP)
+ MOVQ R14, 48(SP)
+ MOVQ R15, 56(SP)
+
+ // Call into the Go signal handler
+ MOVL DI, 0(SP) // sig
+ MOVQ SI, 8(SP) // info
+ MOVQ DX, 16(SP) // ctx
+ CALL runtime·sigtrampgo(SB)
+
+ // Restore callee-save registers.
+ MOVQ 24(SP), BX
+ MOVQ 32(SP), R12
+ MOVQ 40(SP), R13
+ MOVQ 48(SP), R14
+ MOVQ 56(SP), R15
+ MOVQ BP, SP
+ POPQ BP
+ RET
TEXT runtime·mmap_trampoline(SB),NOSPLIT,$0
PUSHQ BP // make a frame; keep stack aligned
POPQ BP
RET
-TEXT runtime·sigaltstack(SB),NOSPLIT,$0
- MOVQ new+0(FP), DI
- MOVQ old+8(FP), SI
- MOVQ $(0x2000000+53), AX
- SYSCALL
- JCC 2(PC)
- MOVL $0xf1, 0xf1 // crash
- RET
-
TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0
PUSHQ BP
MOVQ SP, BP
// DI points to the m.
// We are already on m's g0 stack.
+ // Save callee-save registers.
+ SUBQ $40, SP
+ MOVQ BX, 0(SP)
+ MOVQ R12, 8(SP)
+ MOVQ R13, 16(SP)
+ MOVQ R14, 24(SP)
+ MOVQ R15, 32(SP)
+
MOVQ m_g0(DI), DX // g
// Initialize TLS entry.
CALL runtime·mstart(SB)
+ // Restore callee-save registers.
+ MOVQ 0(SP), BX
+ MOVQ 8(SP), R12
+ MOVQ 16(SP), R13
+ MOVQ 24(SP), R14
+ MOVQ 32(SP), R15
+
// Go is all done with this OS thread.
// Tell pthread everything is ok (we never join with this thread, so
// the value here doesn't really matter).
XORL AX, AX
+
+ ADDQ $40, SP
RET
// These trampolines help convert from Go calling convention to C calling convention.