i386 longjmp: Restore stack first, then signal mask.

Otherwise, a pending signal may be delivered on the wrong stack when
we restore the signal mask.

While here:

- Tidy the code a little bit.
- Sprinkle comments to explain what's going on.
- Use forward branches for statically predicted not-taken.
  => val==0 is unlikely in longjmp

PR lib/57946
This commit is contained in:
riastradh 2024-04-04 00:46:41 +00:00
parent df443a3d17
commit 3e7604f627
3 changed files with 148 additions and 84 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: setjmp.S,v 1.17 2014/05/23 03:05:56 uebayasi Exp $ */
/* $NetBSD: setjmp.S,v 1.18 2024/04/04 00:46:41 riastradh Exp $ */
/*-
* Copyright (c) 1990 The Regents of the University of California.
@ -36,7 +36,7 @@
#include <machine/asm.h>
#if defined(LIBC_SCCS)
RCSID("$NetBSD: setjmp.S,v 1.17 2014/05/23 03:05:56 uebayasi Exp $")
RCSID("$NetBSD: setjmp.S,v 1.18 2024/04/04 00:46:41 riastradh Exp $")
#endif
/*
@ -49,12 +49,24 @@
* The previous signal state is restored.
*/
/*
* setjmp(jmp_buf env@esp[4,8))
*
* ELF symbol: __setjmp14, because the size of jmp_buf changed on some
* platforms in 1.4.
*/
ENTRY(__setjmp14)
movl 4(%esp),%ecx
movl 0(%esp),%edx
movl %edx, 0(%ecx)
movl %ebx, 4(%ecx)
movl %esp, 8(%ecx)
/*
* Save the callee-saves registers: %ebp, %ebx, %edi, %esi,
* plus %esp and the return address on the stack since it
* will be overwritten if the caller makes any subroutine
* calls before longjmp.
*/
movl 4(%esp),%ecx /* ecx := env */
movl 0(%esp),%edx /* edx := return address */
movl %edx,0(%ecx)
movl %ebx,4(%ecx)
movl %esp,8(%ecx)
movl %ebp,12(%ecx)
movl %esi,16(%ecx)
movl %edi,20(%ecx)
@ -63,49 +75,65 @@ ENTRY(__setjmp14)
leal 24(%ecx),%edx
PIC_PROLOGUE
pushl %edx
pushl $0
pushl $0
pushl %edx /* oset (signal mask saved to) */
pushl $0 /* set := NULL */
pushl $0 /* how := 0 (ignored) */
#ifdef __PIC__
call PIC_PLT(_C_LABEL(__sigprocmask14))
#else
call _C_LABEL(__sigprocmask14)
#endif
addl $12,%esp
addl $12,%esp /* pop sigprocmask args */
PIC_EPILOGUE
xorl %eax,%eax
xorl %eax,%eax /* return 0 first time around */
ret
END(__setjmp14)
/*
* longjmp(jmp_buf env@esp[4,8), int val@[8,12))
*
* ELF symbol: __longjmp14, because the size of jmp_buf changed on some
* platforms in 1.4.
*/
ENTRY(__longjmp14)
/* Restore the signal mask. */
movl 4(%esp),%ecx
leal 24(%ecx),%edx
PIC_PROLOGUE
pushl $0
pushl %edx
pushl $3 /* SIG_SETMASK */
#ifdef __PIC__
call PIC_PLT(_C_LABEL(__sigprocmask14))
#else
call _C_LABEL(__sigprocmask14)
#endif
addl $12,%esp
PIC_EPILOGUE
movl 4(%esp),%edx
movl 8(%esp),%eax
movl 0(%edx),%ecx
/*
* Restore the callee-saves registers: %ebp, %ebx, %edi, %esi,
* plus %esp and the return address on the stack.
*/
movl 4(%esp),%edx /* edx := env */
movl 8(%esp),%eax /* eax := val */
movl 0(%edx),%ecx /* ecx := return address */
movl 4(%edx),%ebx
movl 8(%edx),%esp
movl 12(%edx),%ebp
movl 16(%edx),%esi
movl 20(%edx),%edi
testl %eax,%eax
jnz 1f
incl %eax
1: movl %ecx,0(%esp)
ret
movl %ecx,0(%esp) /* restore return address */
/* Restore the signal mask. */
leal 24(%edx),%edx
pushl %eax /* save val@eax */
PIC_PROLOGUE
pushl $0 /* oset := NULL */
pushl %edx /* set (signal mask restored from) */
pushl $3 /* how := SIG_SETMASK */
#ifdef __PIC__
call PIC_PLT(_C_LABEL(__sigprocmask14))
#else
call _C_LABEL(__sigprocmask14)
#endif
addl $12,%esp /* pop sigprocmask args */
PIC_EPILOGUE
popl %eax /* restore val@eax */
testl %eax,%eax /* val == 0? */
jz 3f /* jump if val == 0 */
ret /* return val@eax */
3: incl %eax /* val@eax := 1 */
ret /* return val@eax */
END(__longjmp14)

View File

@ -1,4 +1,4 @@
/* $NetBSD: sigsetjmp.S,v 1.18 2014/05/23 02:34:19 uebayasi Exp $ */
/* $NetBSD: sigsetjmp.S,v 1.19 2024/04/04 00:46:41 riastradh Exp $ */
/*-
* Copyright (c) 1990 The Regents of the University of California.
@ -36,76 +36,104 @@
#include <machine/asm.h>
#if defined(LIBC_SCCS)
RCSID("$NetBSD: sigsetjmp.S,v 1.18 2014/05/23 02:34:19 uebayasi Exp $")
RCSID("$NetBSD: sigsetjmp.S,v 1.19 2024/04/04 00:46:41 riastradh Exp $")
#endif
/*
* sigsetjmp(sigjmp_buf env@esp[4,8), savemask@esp[8,12))
*
* ELF symbol: __sigsetjmp14, because the size of sigjmp_buf changed on
* some platforms in 1.4.
*/
ENTRY(__sigsetjmp14)
movl 4(%esp),%ecx
movl 0(%esp),%edx
movl %edx, 0(%ecx)
movl %ebx, 4(%ecx)
movl %esp, 8(%ecx)
/*
* Save the callee-saves registers: %ebp, %ebx, %edi, %esi,
* plus %esp and the return address on the stack since it
* will be overwritten if the caller makes any subroutine
* calls before siglongjmp.
*/
movl 4(%esp),%ecx /* ecx := env */
movl 0(%esp),%edx /* edx := return address */
movl %edx,0(%ecx)
movl %ebx,4(%ecx)
movl %esp,8(%ecx)
movl %ebp,12(%ecx)
movl %esi,16(%ecx)
movl %edi,20(%ecx)
/* Check if we should save the signal mask, and remember it. */
movl 8(%esp),%eax
movl 8(%esp),%eax /* eax := savemask */
movl %eax,40(%ecx)
testl %eax,%eax
jz 2f /* no, skip */
testl %eax,%eax /* savemask == 0? */
jz 2f /* jump if savemask == 0 */
/* Get the signal mask. */
leal 24(%ecx),%edx
PIC_PROLOGUE
pushl %edx
pushl $0
pushl $0
pushl %edx /* oset (signal mask saved to) */
pushl $0 /* set := NULL */
pushl $0 /* how := 0 (ignored) */
#ifdef __PIC__
call PIC_PLT(_C_LABEL(__sigprocmask14))
#else
call _C_LABEL(__sigprocmask14)
#endif
addl $12,%esp
addl $12,%esp /* pop sigprocmask args */
PIC_EPILOGUE
2: xorl %eax,%eax
2: xorl %eax,%eax /* return 0 first time around */
ret
END(__sigsetjmp14)
/*
* siglongjmp(sigjmp_buf env@esp[4,8), int val@[8,12))
*
* ELF symbol: __siglongjmp14, because the size of sigjmp_buf changed
* on some platforms in 1.4.
*/
ENTRY(__siglongjmp14)
/* Check to see if we need to restore the signal mask. */
movl 4(%esp),%ecx
cmpl $0,40(%ecx)
jz 2f /* no, skip */
/* Restore the signal mask. */
leal 24(%ecx),%edx
PIC_PROLOGUE
pushl $0
pushl %edx
pushl $3 /* SIG_SETMASK */
#ifdef __PIC__
call PIC_PLT(_C_LABEL(__sigprocmask14))
#else
call _C_LABEL(__sigprocmask14)
#endif
addl $12,%esp
PIC_EPILOGUE
2: movl 4(%esp),%edx
movl 8(%esp),%eax
movl 0(%edx),%ecx
/*
* Restore the callee-saves registers: %ebp, %ebx, %edi, %esi,
* plus %esp and the return address on the stack.
*/
movl 4(%esp),%edx /* edx := env */
movl 8(%esp),%eax /* eax := val */
movl 0(%edx),%ecx /* ecx := return address */
movl 4(%edx),%ebx
movl 8(%edx),%esp
movl 12(%edx),%ebp
movl 16(%edx),%esi
movl 20(%edx),%edi
testl %eax,%eax
jnz 3f
incl %eax
3: movl %ecx,0(%esp)
ret
movl %ecx,0(%esp) /* restore return address */
/* Check to see if we need to restore the signal mask. */
cmpl $0,40(%edx) /* savemask == 0 */
jz 2f /* jump if savemask == 0 */
/* Restore the signal mask. */
leal 24(%edx),%edx
pushl %eax /* save val@eax */
PIC_PROLOGUE
pushl $0 /* oset := NULL */
pushl %edx /* set (signal mask restored from) */
pushl $3 /* how := SIG_SETMASK */
#ifdef __PIC__
call PIC_PLT(_C_LABEL(__sigprocmask14))
#else
call _C_LABEL(__sigprocmask14)
#endif
addl $12,%esp /* pop sigprocmask args */
PIC_EPILOGUE
popl %eax /* restore val@eax */
2: testl %eax,%eax /* val == 0? */
jz 3f /* jump if val == 0 */
ret /* return val@eax */
3: incl %eax /* val@eax := 1 */
ret /* return val@eax */
END(__siglongjmp14)

View File

@ -1,4 +1,4 @@
/* $NetBSD: t_sigstack.c,v 1.8 2024/04/04 00:46:30 riastradh Exp $ */
/* $NetBSD: t_sigstack.c,v 1.9 2024/04/04 00:46:42 riastradh Exp $ */
/*-
* Copyright (c) 2024 The NetBSD Foundation, Inc.
@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: t_sigstack.c,v 1.8 2024/04/04 00:46:30 riastradh Exp $");
__RCSID("$NetBSD: t_sigstack.c,v 1.9 2024/04/04 00:46:42 riastradh Exp $");
#include <setjmp.h>
#include <signal.h>
@ -81,10 +81,18 @@ on_sigusr1(int signo, siginfo_t *si, void *ctx)
* On some architectures, this is broken. Those that appear to
* get this right are:
*
* aarch64, alpha, m68k, or1k, powerpc, powerpc64, riscv,
* vax, x86_64
* aarch64
* alpha
* i386
* m68k
* or1k
* powerpc
* powerpc64
* riscv
* vax
* x86_64
*/
#if defined __arm__ || defined __hppa__ || defined __i386__ || \
#if defined __arm__ || defined __hppa__ || \
defined __ia64__ || defined __mips__ || defined __sh3__ || \
defined __sparc__ || defined __sparc64__
if (nentries > 0)