From ec989337c5d3203d52de1a2314813996c711fce6 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Sun, 20 May 2018 08:57:53 -0700 Subject: [PATCH] runtime: use libc's signal functions on Darwin 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 Reviewed-by: Ian Lance Taylor --- src/runtime/defs_darwin.go | 1 + src/runtime/os_darwin.go | 29 ++----- src/runtime/sys_darwin.go | 40 +++++++++ src/runtime/sys_darwin_386.s | 151 ++++++++++++++++++++++----------- src/runtime/sys_darwin_amd64.s | 141 +++++++++++++++++++----------- 5 files changed, 244 insertions(+), 118 deletions(-) diff --git a/src/runtime/defs_darwin.go b/src/runtime/defs_darwin.go index e3a25c531289ce..92f78227967877 100644 --- a/src/runtime/defs_darwin.go +++ b/src/runtime/defs_darwin.go @@ -158,6 +158,7 @@ type Sighandler C.union___sigaction_u 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 diff --git a/src/runtime/os_darwin.go b/src/runtime/os_darwin.go index 55f938cd800999..cf57cc90205b98 100644 --- a/src/runtime/os_darwin.go +++ b/src/runtime/os_darwin.go @@ -206,7 +206,6 @@ func mpreinit(mp *m) { 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() } @@ -499,24 +498,9 @@ const ( _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 @@ -526,14 +510,20 @@ var sigset_all = ^sigset(0) //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) { @@ -543,9 +533,8 @@ 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) diff --git a/src/runtime/sys_darwin.go b/src/runtime/sys_darwin.go index d8b5441b31743c..7b4e927b367b1f 100644 --- a/src/runtime/sys_darwin.go +++ b/src/runtime/sys_darwin.go @@ -179,6 +179,41 @@ func walltime() (int64, int32) { } 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) { } @@ -207,6 +242,11 @@ 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 diff --git a/src/runtime/sys_darwin_386.s b/src/runtime/sys_darwin_386.s index 5b29dfe6043f9e..cb60d070b5cd7e 100644 --- a/src/runtime/sys_darwin_386.s +++ b/src/runtime/sys_darwin_386.s @@ -84,17 +84,6 @@ TEXT runtime·write_trampoline(SB),NOSPLIT,$0 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 @@ -211,18 +200,73 @@ initialized: 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 @@ -243,38 +287,32 @@ 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 @@ -409,8 +447,15 @@ TEXT runtime·mstart_stub(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. @@ -422,10 +467,18 @@ TEXT runtime·mstart_stub(SB),NOSPLIT,$0 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 diff --git a/src/runtime/sys_darwin_amd64.s b/src/runtime/sys_darwin_amd64.s index 320d56499ac5f7..b52e0b52cda982 100644 --- a/src/runtime/sys_darwin_amd64.s +++ b/src/runtime/sys_darwin_amd64.s @@ -63,16 +63,6 @@ TEXT runtime·write_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 @@ -132,26 +122,53 @@ TEXT runtime·walltime_trampoline(SB),NOSPLIT,$0 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 @@ -167,21 +184,39 @@ 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 @@ -218,15 +253,6 @@ TEXT runtime·munmap_trampoline(SB),NOSPLIT,$0 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 @@ -372,6 +398,14 @@ TEXT runtime·mstart_stub(SB),NOSPLIT,$0 // 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. @@ -383,10 +417,19 @@ TEXT runtime·mstart_stub(SB),NOSPLIT,$0 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.