[uClibc]subtle bug in arm version of setjmp/longjmp
Vadim Lebedev
vadim at 7chips.com
Sat Feb 22 16:04:54 UTC 2003
Hello i think i've descovered a serious buf in the arm version of setjmp/longjmp
when configured without float support or wth soft float support
here is the code setjmp.S part:
====================================
.globl __sigsetjmp;
.type __sigsetjmp,%function
.align 4;
__sigsetjmp:
/* Save registers */
#if defined __UCLIBC_HAS_FLOATS__ && ! defined __UCLIBC_HAS_SOFT_FLOAT__
sfmea f4, 4, [r0]!
#endif
stmia r0, {v1-v6, sl, fp, sp, lr}
/* Restore pointer to jmp_buf */
sub r0, r0, #48
/* Make a tail call to __sigjmp_save; it takes the same args. */
B __sigjmp_save (PLT)
.size __sigsetjmp,.-__sigsetjmp;
============================
On entry r0 points to the sigjmp_env
with HW float support the cpu regs are stored after FP context (48 bytes)
but when #if result is false
the cpu regs are stored at the beginnig of the buffer AND the sub instruction adjust r0 to point 48 bytes
BEFORE the beginning of the buffer, so when sigjmp_save is called it stores signal mask info
not where are they expected but 48 bytes earlier.
in the longjmp.S we see:
==========================
.globl __longjmp;
.type __longjmp,%function
.align 4;
__longjmp:
mov ip, r0 /* save jmp_buf pointer */
movs r0, r1 /* get the return value in place */
moveq r0, #1 /* can't let setjmp() return zero! */
#if defined __UCLIBC_HAS_FLOATS__ && ! defined __UCLIBC_HAS_SOFT_FLOAT__
lfmfd f4, 4, [ip] ! /* load the floating point regs */
#endif
ldmia ip , {v1-v6, sl, fp, sp, pc}
.size __longjmp,.-__longjmp;
===========================
so if HW FP is enabled the cpu regs are restored from area after FP regs, otherwise they are restored
from the beginning of the buffer
This matches well the setjmp.S stuff so the progams using the calls works however signal saving ad restoring
part is completely screwed because __sigjmp_save, stored signal mask in wrong place.
the code which use __JMPBUF_UNWINDS macro is also screwed becuase it exepcts to find stack ptr value
at jmp_buf[20] but without HW FP it is stored in jmp_buf[20 - 48/4]
Suggested fix would be:
#setjmp.S
=======================
__sigsetjmp:
/* Save registers */
#if defined __UCLIBC_HAS_FLOATS__ && ! defined __UCLIBC_HAS_SOFT_FLOAT__
sfmea f4, 4, [r0]!
#else
/* skip past FP regs area */
add r0, r0, #48
#endif
stmia r0, {v1-v6, sl, fp, sp, lr}
/* Restore pointer to jmp_buf */
sub r0, r0, #48
/* Make a tail call to __sigjmp_save; it takes the same args. */
B __sigjmp_save (PLT)
.size __sigsetjmp,.-__sigsetjmp;
==============================
#longjmp.S
.globl __longjmp;
.type __longjmp,%function
.align 4;
__longjmp:
mov ip, r0 /* save jmp_buf pointer */
movs r0, r1 /* get the return value in place */
moveq r0, #1 /* can't let setjmp() return zero! */
#if defined __UCLIBC_HAS_FLOATS__ && ! defined __UCLIBC_HAS_SOFT_FLOAT__
lfmfd f4, 4, [ip] ! /* load the floating point regs */
#else
/* skip past FP regs area */
add ip, ip, #48
#endif
ldmia ip , {v1-v6, sl, fp, sp, pc}
.size __longjmp,.-__longjmp;
Best regard
Vadim
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.busybox.net/pipermail/uclibc/attachments/20030222/2eeff9de/attachment-0001.htm
More information about the uClibc
mailing list