summaryrefslogtreecommitdiff
path: root/libc/sysdeps/linux/i386
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2001-10-05 11:31:48 +0000
committerEric Andersen <andersen@codepoet.org>2001-10-05 11:31:48 +0000
commit8a309c2fde98f9fcba538fcada54248eafdd34ad (patch)
tree7edbb9f5153b509f0e1604abc266ac83f738d85f /libc/sysdeps/linux/i386
parentab79ee6808a768bc72cd1158f93ba8a50a0615e5 (diff)
Wohoo! David McCullough found the bug! His comments follow:
I had a look at it and you won't believe it was always broken. I'll try and explain it, let me know if it doesn't make sense. * ash calls setjmp, which messes with the stack to look like it has two args instead of one and then jmps (actually falls) into sigsetjmp. BUG * sigsetjmp then saves the registers and "jumps" to __sigset_save, a C function. BUG1 - because the caller pops its args off the stack, a program that changes it's number of args is broken because the caller will not pop the correct number of args. I think that jumping from the sigsetjmp asm to the 'C' code is unsafe but I can't think of an example. Anyway, I have attached what I think is a working fix. The reason this worked without -fomit-frame-pointer is that the _sigset_save 'C' code would restore the stack pointer from %ebp (the frame pointer) and because none of the asm had moded it, when we returned from __sigset_save the stack was back to it's correct position for 1 argument despite our best attempts to stuff it up ;-)
Diffstat (limited to 'libc/sysdeps/linux/i386')
-rw-r--r--libc/sysdeps/linux/i386/setjmp.S32
1 files changed, 20 insertions, 12 deletions
diff --git a/libc/sysdeps/linux/i386/setjmp.S b/libc/sysdeps/linux/i386/setjmp.S
index 729414390..d38437b6b 100644
--- a/libc/sysdeps/linux/i386/setjmp.S
+++ b/libc/sysdeps/linux/i386/setjmp.S
@@ -21,16 +21,6 @@
#define _SETJMP_H
#include <bits/setjmp.h>
-.globl _setjmp;
-.type _setjmp,@function
-.align 4; \
-_setjmp:
- popl %eax /* Pop return address. */
- popl %ecx /* Pop jmp_buf. */
- pushl $0 /* Push zero argument. */
- pushl %ecx /* Push jmp_buf. */
- pushl %eax /* Push back return address. */
-
.globl __sigsetjmp;
.type __sigsetjmp,@function
.align 4; \
@@ -46,6 +36,9 @@ __sigsetjmp:
movl 0(%esp), %ecx /* Save PC we are returning to now. */
movl %ecx, (JB_PC*4)(%eax)
+ pushl 0x8(%esp) /* save mask */
+ pushl 0x8(%esp) /* jump buf */
+
/* Make a tail call to __sigjmp_save; it takes the same args. */
#if defined(PIC)
/* We cannot use the PLT, because it requires that %ebx be set, but
@@ -57,8 +50,23 @@ Lhere:
popl %ecx
addl $_GLOBAL_OFFSET_TABLE_+[.-Lhere], %ecx
movl (__sigjmp_save)(%ecx), %ecx
- jmp *%ecx
+ call *%ecx
#else
- jmp __sigjmp_save
+ call __sigjmp_save
#endif
+
+ add $8, %esp
+ ret
.size __sigsetjmp,.-__sigsetjmp;
+
+.globl _setjmp;
+.type _setjmp,@function
+.align 4; \
+_setjmp:
+ pushl $0 /* Push zero argument. */
+ pushl 0x8(%esp) /* Push jmp_buf. */
+ call __sigsetjmp
+ add $8, %esp
+ ret
+.size _setjmp,.-_setjmp;
+