Module Name: src
Committed By: riastradh
Date: Thu Apr 4 00:46:30 UTC 2024
Modified Files:
src/lib/libc/arch/x86_64/gen: __setjmp14.S __sigsetjmp14.S
src/tests/lib/libc/setjmp: t_sigstack.c
Log Message:
amd64 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 `xorl %eXX,%eXX' instead of `xorq %rXX,%rXX'.
=> Same effect, one byte shorter, breaks dep chain on more uarches.
- Use forward branches for statically predicted not-taken.
=> val==0 is unlikely in longjmp
PR lib/57946
To generate a diff of this commit:
cvs rdiff -u -r1.3 -r1.4 src/lib/libc/arch/x86_64/gen/__setjmp14.S \
src/lib/libc/arch/x86_64/gen/__sigsetjmp14.S
cvs rdiff -u -r1.7 -r1.8 src/tests/lib/libc/setjmp/t_sigstack.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/lib/libc/arch/x86_64/gen/__setjmp14.S
diff -u src/lib/libc/arch/x86_64/gen/__setjmp14.S:1.3 src/lib/libc/arch/x86_64/gen/__setjmp14.S:1.4
--- src/lib/libc/arch/x86_64/gen/__setjmp14.S:1.3 Thu May 22 15:01:56 2014
+++ src/lib/libc/arch/x86_64/gen/__setjmp14.S Thu Apr 4 00:46:30 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: __setjmp14.S,v 1.3 2014/05/22 15:01:56 uebayasi Exp $ */
+/* $NetBSD: __setjmp14.S,v 1.4 2024/04/04 00:46:30 riastradh Exp $ */
/*
* Copyright (c) 2001 Wasabi Systems, Inc.
@@ -40,7 +40,7 @@
#include <machine/setjmp.h>
#if defined(LIBC_SCCS)
- RCSID("$NetBSD: __setjmp14.S,v 1.3 2014/05/22 15:01:56 uebayasi Exp $")
+ RCSID("$NetBSD: __setjmp14.S,v 1.4 2024/04/04 00:46:30 riastradh Exp $")
#endif
/*
@@ -53,7 +53,19 @@
* The previous signal state is restored.
*/
+/*
+ * setjmp(jmp_buf env@rdi)
+ *
+ * ELF symbol: __setjmp14, because the size of jmp_buf changed on some
+ * platforms in 1.4.
+ */
ENTRY(__setjmp14)
+ /*
+ * Save the callee-saves registers: %rbx, %rbp, %r12-r15,
+ * plus %rsp and the return address on the stack since it
+ * will be overwritten if the caller makes any subroutine
+ * calls before longjmp.
+ */
movq (%rsp),%r11
movq %rbx,(_JB_RBX * 8)(%rdi)
movq %rbp,(_JB_RBP * 8)(%rdi)
@@ -64,47 +76,62 @@ ENTRY(__setjmp14)
movq %rsp,(_JB_RSP * 8)(%rdi)
movq %r11,(_JB_PC * 8)(%rdi)
- leaq (_JB_SIGMASK * 8)(%rdi),%rdx
- xorl %edi,%edi
- xorq %rsi,%rsi
+ leaq (_JB_SIGMASK * 8)(%rdi),%rdx /* oset@rdx */
+ xorl %edi,%edi /* how@edi := 0 (ignored) */
+ xorl %esi,%esi /* set@rsi := NULL */
#ifdef __PIC__
call PIC_PLT(_C_LABEL(__sigprocmask14))
#else
call _C_LABEL(__sigprocmask14)
#endif
-2: xorl %eax,%eax
+ xorl %eax,%eax
ret
END(__setjmp14)
+/*
+ * longjmp(jmp_buf env@rdi, int val@esi)
+ *
+ * ELF symbol: __longjmp14, because the size of jmp_buf changed on some
+ * platforms in 1.4
+ */
ENTRY(__longjmp14)
- movq %rdi,%r12
- movl %esi,%r8d
-
- leaq (_JB_SIGMASK * 8)(%rdi),%rsi
- movl $3,%edi /* SIG_SETMASK */
- xorq %rdx,%rdx
+ /*
+ * Restore the callee-saves registers: %rbx, %rbp, %r12-r15,
+ * plus %rsp and the return address on the stack.
+ */
+ movq (_JB_RBX * 8)(%rdi),%rbx
+ movq (_JB_RBP * 8)(%rdi),%rbp
+ movq (_JB_R12 * 8)(%rdi),%r12
+ movq (_JB_R13 * 8)(%rdi),%r13
+ movq (_JB_R14 * 8)(%rdi),%r14
+ movq (_JB_R15 * 8)(%rdi),%r15
+ movq (_JB_RSP * 8)(%rdi),%rsp
+ movq (_JB_PC * 8)(%rdi),%r11
+ movq %r11,0(%rsp)
+
+ /*
+ * Use pushq %rsi instead of pushl %esi in order to keep
+ * 16-byte stack alignment, even though we only care about the
+ * 32-bit int in esi.
+ */
+ pushq %rsi /* save val@esi */
+
+ leaq (_JB_SIGMASK * 8)(%rdi),%rsi /* set@rsi */
+ movl $3,%edi /* how@edi := SIG_SETMASK */
+ xorl %edx,%edx /* oset@rdx := NULL */
- pushq %r8
#ifdef __PIC__
call PIC_PLT(_C_LABEL(__sigprocmask14))
#else
call _C_LABEL(__sigprocmask14)
#endif
- popq %r8
- movq (_JB_RBX * 8)(%r12),%rbx
- movq (_JB_RBP * 8)(%r12),%rbp
- movq (_JB_R13 * 8)(%r12),%r13
- movq (_JB_R14 * 8)(%r12),%r14
- movq (_JB_R15 * 8)(%r12),%r15
- movq (_JB_RSP * 8)(%r12),%rsp
- movq (_JB_PC * 8)(%r12),%r11
- movq (_JB_R12 * 8)(%r12),%r12
-
- movl %r8d,%eax
- testl %eax,%eax
- jnz 1f
- incl %eax
-1: movq %r11,0(%rsp)
- ret
+
+ popq %rax /* restore val@eax */
+
+ testl %eax,%eax /* val@eax == 0? */
+ jz 1f /* jump if val@eax == 0 */
+ ret /* return val@eax */
+1: incl %eax /* val@eax := 1 */
+ ret /* return val@eax */
END(__longjmp14)
Index: src/lib/libc/arch/x86_64/gen/__sigsetjmp14.S
diff -u src/lib/libc/arch/x86_64/gen/__sigsetjmp14.S:1.3 src/lib/libc/arch/x86_64/gen/__sigsetjmp14.S:1.4
--- src/lib/libc/arch/x86_64/gen/__sigsetjmp14.S:1.3 Thu May 22 15:01:56 2014
+++ src/lib/libc/arch/x86_64/gen/__sigsetjmp14.S Thu Apr 4 00:46:30 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: __sigsetjmp14.S,v 1.3 2014/05/22 15:01:56 uebayasi Exp $ */
+/* $NetBSD: __sigsetjmp14.S,v 1.4 2024/04/04 00:46:30 riastradh Exp $ */
/*
* Copyright (c) 2001 Wasabi Systems, Inc.
@@ -40,7 +40,7 @@
#include <machine/setjmp.h>
#if defined(LIBC_SCCS)
- RCSID("$NetBSD: __sigsetjmp14.S,v 1.3 2014/05/22 15:01:56 uebayasi Exp $")
+ RCSID("$NetBSD: __sigsetjmp14.S,v 1.4 2024/04/04 00:46:30 riastradh Exp $")
#endif
/*
@@ -53,7 +53,19 @@
* The previous signal state is restored.
*/
+/*
+ * sigsetjmp(sigjmp_buf env@rdi, int savemask@esi)
+ *
+ * ELF symbol: __sigsetjmp14, because the size of sigjmp_buf changed on
+ * some platforms in 1.4.
+ */
ENTRY(__sigsetjmp14)
+ /*
+ * Save the callee-saves registers: %rbx, %rbp, %r12-r15,
+ * plus %rsp and the return address on the stack since it
+ * will be overwritten if the caller makes any subroutine
+ * calls before siglongjmp.
+ */
movq (%rsp),%r11
movq %rbx,(_JB_RBX * 8)(%rdi)
movq %rbp,(_JB_RBP * 8)(%rdi)
@@ -64,51 +76,69 @@ ENTRY(__sigsetjmp14)
movq %rsp,(_JB_RSP * 8)(%rdi)
movq %r11,(_JB_PC * 8)(%rdi)
- movq %rsi,(_JB_SIGFLAG * 8)(%rdi)
- testl %esi,%esi
- jz 2f
-
- leaq (_JB_SIGMASK * 8)(%rdi),%rdx
- xorl %edi,%edi
- xorq %rsi,%rsi
+ movq %rsi,(_JB_SIGFLAG * 8)(%rdi) /* store savemask */
+ testl %esi,%esi /* savemask == 0? */
+ jz 2f /* jump if savemask == 0 */
+
+ leaq (_JB_SIGMASK * 8)(%rdi),%rdx /* oset@rdx */
+ xorl %edi,%edi /* how@edi := 0 (ignored) */
+ xorl %esi,%esi /* set@rsi := NULL */
#ifdef __PIC__
call PIC_PLT(_C_LABEL(__sigprocmask14))
#else
call _C_LABEL(__sigprocmask14)
#endif
-2: xorl %eax,%eax
+2: xorl %eax,%eax /* return 0 first time around */
ret
END(__sigsetjmp14)
+/*
+ * siglongjmp(sigjmp_buf env@rdi, int val@esi)
+ *
+ * ELF symbol: __siglongjmp14, because the size of sigjmp_buf changed
+ * on some platforms in 1.4.
+ */
ENTRY(__siglongjmp14)
- movq %rdi,%r12
- pushq %rsi
- cmpl $0, (_JB_SIGFLAG * 8)(%rdi)
-
- jz 2f
- leaq (_JB_SIGMASK * 8)(%rdi),%rsi
- movl $3,%edi /* SIG_SETMASK */
- xorq %rdx,%rdx
+ /*
+ * Restore the callee-saves registers: %rbx, %rbp, %r12-r15,
+ * plus %rsp and the return address on the stack.
+ */
+ movq (_JB_RBX * 8)(%rdi),%rbx
+ movq (_JB_RBP * 8)(%rdi),%rbp
+ movq (_JB_R12 * 8)(%rdi),%r12
+ movq (_JB_R13 * 8)(%rdi),%r13
+ movq (_JB_R14 * 8)(%rdi),%r14
+ movq (_JB_R15 * 8)(%rdi),%r15
+ movq (_JB_RSP * 8)(%rdi),%rsp
+ movq (_JB_PC * 8)(%rdi),%r11
+ movq %r11,0(%rsp)
+
+ /*
+ * Use pushq %rsi instead of pushl %esi in order to keep
+ * 16-byte stack alignment, even though we only care about the
+ * 32-bit int in esi.
+ */
+ pushq %rsi /* save val@esi */
+
+ cmpl $0, (_JB_SIGFLAG * 8)(%rdi) /* test savemask == 0? */
+ jz 2f /* jump if savemask == 0 */
+
+ leaq (_JB_SIGMASK * 8)(%rdi),%rsi /* set@rsi */
+ movl $3,%edi /* how@edi := SIG_SETMASK */
+ xorl %edx,%edx /* oset@rdx := NULL */
#ifdef __PIC__
call PIC_PLT(_C_LABEL(__sigprocmask14))
#else
call _C_LABEL(__sigprocmask14)
#endif
-2: popq %rax
- movq (_JB_RBX * 8)(%r12),%rbx
- movq (_JB_RBP * 8)(%r12),%rbp
- movq (_JB_R13 * 8)(%r12),%r13
- movq (_JB_R14 * 8)(%r12),%r14
- movq (_JB_R15 * 8)(%r12),%r15
- movq (_JB_RSP * 8)(%r12),%rsp
- movq (_JB_PC * 8)(%r12),%r11
- movq (_JB_R12 * 8)(%r12),%r12
-
- testl %eax,%eax
- jnz 1f
- incl %eax
-1: movq %r11,0(%rsp)
- ret
+
+2: popq %rax /* restore val@eax */
+
+ testl %eax,%eax /* val@eax == 0? */
+ jz 1f /* jump if val@eax == 0 */
+ ret /* return val@eax */
+1: incl %eax /* val@eax := 1 */
+ ret /* return val@eax */
END(__siglongjmp14)
Index: src/tests/lib/libc/setjmp/t_sigstack.c
diff -u src/tests/lib/libc/setjmp/t_sigstack.c:1.7 src/tests/lib/libc/setjmp/t_sigstack.c:1.8
--- src/tests/lib/libc/setjmp/t_sigstack.c:1.7 Mon Feb 19 19:43:27 2024
+++ src/tests/lib/libc/setjmp/t_sigstack.c Thu Apr 4 00:46:30 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: t_sigstack.c,v 1.7 2024/02/19 19:43:27 riastradh Exp $ */
+/* $NetBSD: t_sigstack.c,v 1.8 2024/04/04 00:46:30 riastradh Exp $ */
/*-
* Copyright (c) 2024 The NetBSD Foundation, Inc.
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__RCSID("$NetBSD: t_sigstack.c,v 1.7 2024/02/19 19:43:27 riastradh Exp $");
+__RCSID("$NetBSD: t_sigstack.c,v 1.8 2024/04/04 00:46:30 riastradh Exp $");
#include <setjmp.h>
#include <signal.h>
@@ -81,11 +81,12 @@ on_sigusr1(int signo, siginfo_t *si, voi
* On some architectures, this is broken. Those that appear to
* get this right are:
*
- * aarch64, alpha, m68k, or1k, powerpc, powerpc64, riscv, vax
+ * aarch64, alpha, m68k, or1k, powerpc, powerpc64, riscv,
+ * vax, x86_64
*/
#if defined __arm__ || defined __hppa__ || defined __i386__ || \
defined __ia64__ || defined __mips__ || defined __sh3__ || \
- defined __sparc__ || defined __sparc64__ || defined __x86_64__
+ defined __sparc__ || defined __sparc64__
if (nentries > 0)
atf_tc_expect_fail("PR lib/57946");
#endif