]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: use libc's signal functions on Darwin
authorKeith Randall <khr@golang.org>
Sun, 20 May 2018 15:57:53 +0000 (08:57 -0700)
committerKeith Randall <khr@golang.org>
Tue, 12 Jun 2018 17:05:39 +0000 (17:05 +0000)
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>
src/runtime/defs_darwin.go
src/runtime/os_darwin.go
src/runtime/sys_darwin.go
src/runtime/sys_darwin_386.s
src/runtime/sys_darwin_amd64.s

index e3a25c531289cee654ab7f42eb035d643cc62acb..92f78227967877a15f005e2a192ee832649b6bbe 100644 (file)
@@ -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
index 55f938cd800999fb548b7b4dfa864a5cd1ca592d..cf57cc90205b98d79a8d578c34bd8d6156f91d58 100644 (file)
@@ -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)
index d8b5441b31743c018311b4feaa8959c8490b1ae1..7b4e927b367b1fcd8aefe843363cfbccafe40447 100644 (file)
@@ -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
index 5b29dfe6043f9ee7e573e2f56252a56ec506ec2b..cb60d070b5cd7eb7d370ead54c11aee9a414c722 100644 (file)
@@ -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
index 320d56499ac5f7790a9c6517f803260c9b2fc364..b52e0b52cda98275d703e3823f443ac12aeb2f4b 100644 (file)
@@ -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.