diff options
author | Eric Andersen <andersen@codepoet.org> | 2001-10-05 11:31:48 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2001-10-05 11:31:48 +0000 |
commit | 8a309c2fde98f9fcba538fcada54248eafdd34ad (patch) | |
tree | 7edbb9f5153b509f0e1604abc266ac83f738d85f /libc/sysdeps/linux/i386 | |
parent | ab79ee6808a768bc72cd1158f93ba8a50a0615e5 (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.S | 32 |
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; + |