about summary refs log tree commit diff
path: root/src/signal/sh/sigsetjmp.s
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2015-04-17 21:54:42 -0400
committerRich Felker <dalias@aerifal.cx>2015-04-17 21:54:42 -0400
commit583e55122e767b1586286a0d9c35e2a4027998ab (patch)
tree369bc1f292ee44f7bdd702203aaf535d97569caf /src/signal/sh/sigsetjmp.s
parent81e18eb3cd61f7b68a8f99b3e6c728f2a4d79221 (diff)
downloadmusl-583e55122e767b1586286a0d9c35e2a4027998ab.tar.gz
musl-583e55122e767b1586286a0d9c35e2a4027998ab.tar.xz
musl-583e55122e767b1586286a0d9c35e2a4027998ab.zip
redesign sigsetjmp so that signal mask is restored after longjmp
the conventional way to implement sigsetjmp is to save the signal mask
then tail-call to setjmp; siglongjmp then restores the signal mask and
calls longjmp. the problem with this approach is that a signal already
pending, or arriving between unmasking of signals and restoration of
the saved stack pointer, will have its signal handler run on the stack
that was active before siglongjmp was called. this can lead to
unbounded stack usage when siglongjmp is used to leave a signal
handler.

in the new design, sigsetjmp saves its own return address inside the
extended part of the sigjmp_buf (outside the __jmp_buf part used by
setjmp) then calls setjmp to save a jmp_buf inside its own execution.
it then tail-calls to __sigsetjmp_tail, which uses the return value of
setjmp to determine whether to save the current signal mask or restore
a previously-saved mask.

as an added bonus, this design makes it so that siglongjmp and longjmp
are identical. this is useful because the __longjmp_chk function we
need to add for ABI-compatibility assumes siglongjmp and longjmp are
the same, but for different reasons -- it was designed assuming either
can access a flag just past the __jmp_buf indicating whether the
signal masked was saved, and act on that flag. however, early versions
of musl did not have space past the __jmp_buf for the non-sigjmp_buf
version of jmp_buf, so our setjmp cannot store such a flag without
risking clobbering memory on (very) old binaries.
Diffstat (limited to 'src/signal/sh/sigsetjmp.s')
-rw-r--r--src/signal/sh/sigsetjmp.s44
1 files changed, 27 insertions, 17 deletions
diff --git a/src/signal/sh/sigsetjmp.s b/src/signal/sh/sigsetjmp.s
index 7951f07e..7d1e7c95 100644
--- a/src/signal/sh/sigsetjmp.s
+++ b/src/signal/sh/sigsetjmp.s
@@ -4,27 +4,37 @@
 .type __sigsetjmp,@function
 sigsetjmp:
 __sigsetjmp:
-	mov.l r5, @(36,r4)
 	tst r5, r5
-	bf  2f
+	bt 9f
 
-	sts.l pr, @-r15
-	mov.l r4, @-r15
 	mov r4, r6
-	add #40, r6
-	mov #0, r5
-	mov #2, r4
-	mov.l L1, r0
-	bsrf  r0
-	 nop
-1:	mov.l @r15+, r4
-	lds.l @r15+, pr
+	add #52, r6
+	sts pr, r0
+	mov.l r0, @r6
+	mov.l r8, @(4+8,r6)
+
+	mov.l 1f, r0
+2:	bsrf r0
+	 mov r4, r8
+
+	mov r0, r5
+	mov r8, r4
+	mov r4, r6
+	add #52, r6
+
+	mov.l @r6, r0
+	lds r0, pr
+
+	mov.l 3f, r0
+4:	braf r0
+	 mov.l @(4+8,r4), r8
 
-2:	mov.l L2, r0
-	braf  r0
+9:	mov.l 5f, r0
+6:	braf r0
 	 nop
-3:
 
 .align 2
-L1:	.long pthread_sigmask@PLT-(1b-.)
-L2:	.long setjmp@PLT-(3b-.)
+1:	.long setjmp@PLT-(2b+4-.)
+.hidden __sigsetjmp_tail
+3:	.long __sigsetjmp_tail@PLT-(4b+4-.)
+5:	.long setjmp@PLT-(6b+4-.)