diff --git a/libc/arch-mips/bionic/setjmp.S b/libc/arch-mips/bionic/setjmp.S index 05d0e2567..1c2655385 100644 --- a/libc/arch-mips/bionic/setjmp.S +++ b/libc/arch-mips/bionic/setjmp.S @@ -1,3 +1,30 @@ +/* + * Copyright (C) 2014-2015 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ /* * Copyright (c) 2001-2002 Opsycon AB (www.opsycon.se / www.opsycon.com) * @@ -94,23 +121,31 @@ #include #include -/* On Mips32, jmpbuf begins with optional 4-byte filler so that - * all saved FP regs are aligned on 8-byte boundary, despite this whole - * struct being mis-declared to users as an array of (4-byte) longs. - * All the following offsets are then from the rounded-up base addr +/* jmpbuf is declared to users as an array of longs, which is only + * 4-byte aligned in 32-bit builds. The Mips jmpbuf begins with a + * dynamically-sized 0- or 4-byte unused filler so that double-prec FP regs + * are saved to 8-byte-aligned mem cells. + * All the following jmpbuf offsets are from the rounded-DOWN base addr. */ /* Fields of same size on all MIPS abis: */ -#define SC_MAGIC (0*4) /* 4 bytes, identify jmpbuf */ -#define SC_MASK (1*4) /* 4 bytes, saved signal mask */ -#define SC_FPSR (2*4) /* 4 bytes, floating point control/status reg */ -/* filler2 (3*4) 4 bytes, pad to 8-byte boundary */ +/* field: byte offset: size: */ +/* dynam filler (0*4) 0-4 bytes of rounddown filler, DON'T TOUCH!! + often overlays user storage!! */ +#define SC_MAGIC_OFFSET (1*4) /* 4 bytes, identify jmpbuf, first actual field */ +#define SC_FLAG_OFFSET (2*4) /* 4 bytes, savesigs flag */ +#define SC_FPSR_OFFSET (3*4) /* 4 bytes, floating point control/status reg */ +/* following fields are 8-byte aligned */ +#define SC_MASK_OFFSET (4*4) /* 16 bytes, mips32/mips64 version of sigset_t */ +#define SC_SPARE_OFFSET (8*4) /* 8 bytes, reserved for future uses */ /* Registers that are 4-byte on mips32 o32, and 8-byte on mips64 n64 abi */ -#define SC_REGS_SAVED 12 /* ra,gp,sp,s0-s8 */ -#define SC_REGS (4*4) /* SC_REGS_SAVED*REGSZ bytes */ +#define SC_REGS_OFFSET (10*4) /* SC_REGS_BYTES */ +#define SC_REGS_SAVED 12 /*regs*/ /* ra,s0-s8,gp,sp */ +#define SC_REGS_BYTES (SC_REGS_SAVED*REGSZ) +#define SC_REGS SC_REGS_OFFSET -/* Floating pt registers are 8-bytes on all abis, +/* Double floating pt registers are 8-bytes on all abis, * but the number of saved fp regs varies for o32/n32 versus n64 abis: */ @@ -120,22 +155,20 @@ #define SC_FPREGS_SAVED 6 /* even fp regs f20,f22,f24,f26,f28,f30 */ #endif -#define SC_FPREGS (SC_REGS + SC_REGS_SAVED*REGSZ) /* SC_FPREGS_SAVED*REGSZ_FP bytes */ +#define SC_FPREGS_OFFSET (SC_REGS_OFFSET + SC_REGS_BYTES) /* SC_FPREGS_BYTES */ +#define SC_FPREGS_BYTES (SC_FPREGS_SAVED*REGSZ_FP) +#define SC_FPREGS SC_FPREGS_OFFSET -#define SC_BYTES (SC_FPREGS + SC_FPREGS_SAVED*REGSZ_FP) -#define SC_LONGS (SC_BYTES/REGSZ) +#define SC_TOTAL_BYTES (SC_FPREGS_OFFSET + SC_FPREGS_BYTES) +#define SC_TOTAL_LONGS (SC_TOTAL_BYTES/REGSZ) -#ifdef __LP64__ -/* SC_LONGS is 22, so _JBLEN should be 22 or larger */ -#else -/* SC_LONGS is 28, but must also allocate dynamic-roundup filler. - so _JBLEN should be 29 or larger */ +#if SC_TOTAL_LONGS > _JBLEN +#error _JBLEN is too small #endif /* - * _setjmp, _longjmp (restoring signal state) * - * GPOFF and FRAMESIZE must be the same for both _setjmp and _longjmp! + * GPOFF and FRAMESIZE must be the same for all setjmp/longjmp routines * */ @@ -145,30 +178,33 @@ A0OFF= FRAMESZ-3*REGSZ GPOFF= FRAMESZ-2*REGSZ RAOFF= FRAMESZ-1*REGSZ -NON_LEAF(setjmp, FRAMESZ, ra) +NON_LEAF(sigsetjmp, FRAMESZ, ra) .mask 0x80000000, RAOFF PTR_SUBU sp, FRAMESZ # allocate stack frame - SETUP_GP64(GPOFF, setjmp) + SETUP_GP64(GPOFF, sigsetjmp) SAVE_GP(GPOFF) .set reorder +setjmp_common: #ifndef __LP64__ - addiu a0, 7 # roundup jmpbuf addr to 8-byte boundary - li t0, ~7 - and a0, t0 + li t0, ~7 + and a0, t0 # round jmpbuf addr DOWN to 8-byte boundary #endif + sw a1, SC_FLAG_OFFSET(a0) # save savesigs flag + beqz a1, 1f # do saving of signal mask? - REG_S ra, RAOFF(sp) # save state + REG_S ra, RAOFF(sp) # spill state REG_S a0, A0OFF(sp) - move a0, zero # get current signal mask - jal sigblock + # call sigprocmask(int how ignored, sigset_t* null, sigset_t* SC_MASK(a0)): + LA a2, SC_MASK_OFFSET(a0) # gets current signal mask + li a0, 0 # how; ignored when new mask is null + li a1, 0 # null new mask + jal sigprocmask # get current signal mask REG_L a0, A0OFF(sp) REG_L ra, RAOFF(sp) - - REG_S v0, SC_MASK(a0) # save sc_mask = sigblock(0) - +1: li v0, 0xACEDBADE # sigcontext magic number - sw v0, SC_MAGIC(a0) + sw v0, SC_MAGIC_OFFSET(a0) # callee-saved long-sized regs: REG_S ra, SC_REGS+0*REGSZ(a0) REG_S s0, SC_REGS+1*REGSZ(a0) @@ -181,9 +217,9 @@ NON_LEAF(setjmp, FRAMESZ, ra) REG_S s7, SC_REGS+8*REGSZ(a0) REG_S s8, SC_REGS+9*REGSZ(a0) REG_L v0, GPOFF(sp) - REG_S v0, SC_REGS+10*REGSZ(a0) + REG_S v0, SC_REGS+10*REGSZ(a0) # save gp PTR_ADDU v0, sp, FRAMESZ - REG_S v0, SC_REGS+11*REGSZ(a0) + REG_S v0, SC_REGS+11*REGSZ(a0) # save orig sp cfc1 v0, $31 @@ -199,7 +235,7 @@ NON_LEAF(setjmp, FRAMESZ, ra) s.d $f31, SC_FPREGS+7*REGSZ_FP(a0) #else # callee-saved fp regs on mips o32 ABI are - # the even-numbered fp regs $f20,$f22,...$f30 + # the even-numbered double fp regs $f20,$f22,...$f30 s.d $f20, SC_FPREGS+0*REGSZ_FP(a0) s.d $f22, SC_FPREGS+1*REGSZ_FP(a0) s.d $f24, SC_FPREGS+2*REGSZ_FP(a0) @@ -207,37 +243,68 @@ NON_LEAF(setjmp, FRAMESZ, ra) s.d $f28, SC_FPREGS+4*REGSZ_FP(a0) s.d $f30, SC_FPREGS+5*REGSZ_FP(a0) #endif - sw v0, SC_FPSR(a0) + sw v0, SC_FPSR_OFFSET(a0) move v0, zero RESTORE_GP64 PTR_ADDU sp, FRAMESZ j ra -END(setjmp) +END(sigsetjmp) -NON_LEAF(longjmp, FRAMESZ, ra) + +# Alternate entry points: + +NON_LEAF(setjmp, FRAMESZ, ra) .mask 0x80000000, RAOFF PTR_SUBU sp, FRAMESZ - SETUP_GP64(GPOFF, longjmp) + SETUP_GP64(GPOFF, setjmp) # can't share sigsetjmp's gp code + SAVE_GP(GPOFF) + .set reorder + + li a1, 1 # save/restore signals state + b setjmp_common # tail call +END(setjmp) + + +NON_LEAF(_setjmp, FRAMESZ, ra) + .mask 0x80000000, RAOFF + PTR_SUBU sp, FRAMESZ + SETUP_GP64(GPOFF, _setjmp) # can't share sigsetjmp's gp code + SAVE_GP(GPOFF) + .set reorder + + li a1, 0 # don't save/restore signals + b setjmp_common # tail call +END(_setjmp) + + +NON_LEAF(siglongjmp, FRAMESZ, ra) + .mask 0x80000000, RAOFF + PTR_SUBU sp, FRAMESZ + SETUP_GP64(GPOFF, siglongjmp) SAVE_GP(GPOFF) .set reorder #ifndef __LP64__ - addiu a0, 7 # roundup jmpbuf addr to 8-byte boundary - li t0, ~7 - and a0, t0 + li t0, ~7 + and a0, t0 # round jmpbuf addr DOWN to 8-byte boundary #endif + lw v0, SC_MAGIC_OFFSET(a0) + li t0, 0xACEDBADE + bne v0, t0, longjmp_botch # jump if error - REG_S a1, A1OFF(sp) + lw t0, SC_FLAG_OFFSET(a0) # get savesigs flag + beqz t0, 1f # restore signal mask? + + REG_S a1, A1OFF(sp) # temp spill REG_S a0, A0OFF(sp) - lw a0, SC_MASK(a0) - jal sigsetmask + # call sigprocmask(int how SIG_SETMASK, sigset_t* SC_MASK(a0), sigset_t* null): + LA a1, SC_MASK_OFFSET(a0) # signals being restored + li a0, 3 # mips SIG_SETMASK + li a2, 0 # null + jal sigprocmask # restore signal mask REG_L a0, A0OFF(sp) REG_L a1, A1OFF(sp) - - lw v0, SC_MAGIC(a0) - li t0, 0xACEDBADE - bne v0, t0, longjmp_botch # jump if error - +1: # callee-saved long-sized regs: REG_L ra, SC_REGS+0*REGSZ(a0) REG_L s0, SC_REGS+1*REGSZ(a0) @@ -252,8 +319,8 @@ NON_LEAF(longjmp, FRAMESZ, ra) REG_L gp, SC_REGS+10*REGSZ(a0) REG_L sp, SC_REGS+11*REGSZ(a0) - lw v0, SC_FPSR(a0) - ctc1 v0, $31 + lw v0, SC_FPSR_OFFSET(a0) + ctc1 v0, $31 # restore old fr mode before fp values #ifdef __LP64__ # callee-saved fp regs on mips n64 ABI are $f24..$f31 l.d $f24, SC_FPREGS+0*REGSZ_FP(a0) @@ -266,7 +333,7 @@ NON_LEAF(longjmp, FRAMESZ, ra) l.d $f31, SC_FPREGS+7*REGSZ_FP(a0) #else # callee-saved fp regs on mips o32 ABI are - # the even-numbered fp regs $f20,$f22,...$f30 + # the even-numbered double fp regs $f20,$f22,...$f30 l.d $f20, SC_FPREGS+0*REGSZ_FP(a0) l.d $f22, SC_FPREGS+1*REGSZ_FP(a0) l.d $f24, SC_FPREGS+2*REGSZ_FP(a0) @@ -278,192 +345,19 @@ NON_LEAF(longjmp, FRAMESZ, ra) li a1, 1 # never return 0! 1: move v0, a1 - j ra + j ra # return to setjmp call site longjmp_botch: jal longjmperror jal abort - RESTORE_GP64 - PTR_ADDU sp, FRAMESZ -END(longjmp) - - -/* - * _setjmp, _longjmp (not restoring signal state) - * - * GPOFF and FRAMESIZE must be the same for both _setjmp and _longjmp! - * - */ - -FRAMESZ= MKFSIZ(0,4) -GPOFF= FRAMESZ-2*REGSZ - -LEAF(_setjmp, FRAMESZ) - PTR_SUBU sp, FRAMESZ - SETUP_GP64(GPOFF, _setjmp) - SAVE_GP(GPOFF) - .set reorder - -#ifndef __LP64__ - addiu a0, 7 # roundup jmpbuf addr to 8-byte boundary - li t0, ~7 - and a0, t0 -#endif - - # SC_MASK is unused here - - li v0, 0xACEDBADE # sigcontext magic number - sw v0, SC_MAGIC(a0) - # callee-saved long-sized regs: - REG_S ra, SC_REGS+0*REGSZ(a0) - REG_S s0, SC_REGS+1*REGSZ(a0) - REG_S s1, SC_REGS+2*REGSZ(a0) - REG_S s2, SC_REGS+3*REGSZ(a0) - REG_S s3, SC_REGS+4*REGSZ(a0) - REG_S s4, SC_REGS+5*REGSZ(a0) - REG_S s5, SC_REGS+6*REGSZ(a0) - REG_S s6, SC_REGS+7*REGSZ(a0) - REG_S s7, SC_REGS+8*REGSZ(a0) - REG_S s8, SC_REGS+9*REGSZ(a0) - REG_L v0, GPOFF(sp) - REG_S v0, SC_REGS+10*REGSZ(a0) - PTR_ADDU v0, sp, FRAMESZ - REG_S v0, SC_REGS+11*REGSZ(a0) - - cfc1 v0, $31 - -#ifdef __LP64__ - # callee-saved fp regs on mips n64 ABI are $f24..$f31 - s.d $f24, SC_FPREGS+0*REGSZ_FP(a0) - s.d $f25, SC_FPREGS+1*REGSZ_FP(a0) - s.d $f26, SC_FPREGS+2*REGSZ_FP(a0) - s.d $f27, SC_FPREGS+3*REGSZ_FP(a0) - s.d $f28, SC_FPREGS+4*REGSZ_FP(a0) - s.d $f29, SC_FPREGS+5*REGSZ_FP(a0) - s.d $f30, SC_FPREGS+6*REGSZ_FP(a0) - s.d $f31, SC_FPREGS+7*REGSZ_FP(a0) -#else - # callee-saved fp regs on mips o32 ABI are - # the even-numbered fp regs $f20,$f22,...$f30 - s.d $f20, SC_FPREGS+0*REGSZ_FP(a0) - s.d $f22, SC_FPREGS+1*REGSZ_FP(a0) - s.d $f24, SC_FPREGS+2*REGSZ_FP(a0) - s.d $f26, SC_FPREGS+3*REGSZ_FP(a0) - s.d $f28, SC_FPREGS+4*REGSZ_FP(a0) - s.d $f30, SC_FPREGS+5*REGSZ_FP(a0) -#endif - sw v0, SC_FPSR(a0) - move v0, zero - RESTORE_GP64 - PTR_ADDU sp, FRAMESZ - j ra -END(_setjmp) - - -LEAF(_longjmp, FRAMESZ) - PTR_SUBU sp, FRAMESZ - SETUP_GP64(GPOFF, _longjmp) - SAVE_GP(GPOFF) - .set reorder - -#ifndef __LP64__ - addiu a0, 7 # roundup jmpbuf addr to 8-byte boundary - li t0, ~7 - and a0, t0 -#endif - - # SC_MASK is unused here - - lw v0, SC_MAGIC(a0) - li t0, 0xACEDBADE - bne v0, t0, _longjmp_botch # jump if error - - # callee-saved long-sized regs: - REG_L ra, SC_REGS+0*REGSZ(a0) - REG_L s0, SC_REGS+1*REGSZ(a0) - REG_L s1, SC_REGS+2*REGSZ(a0) - REG_L s2, SC_REGS+3*REGSZ(a0) - REG_L s3, SC_REGS+4*REGSZ(a0) - REG_L s4, SC_REGS+5*REGSZ(a0) - REG_L s5, SC_REGS+6*REGSZ(a0) - REG_L s6, SC_REGS+7*REGSZ(a0) - REG_L s7, SC_REGS+8*REGSZ(a0) - REG_L s8, SC_REGS+9*REGSZ(a0) - REG_L gp, SC_REGS+10*REGSZ(a0) - REG_L sp, SC_REGS+11*REGSZ(a0) - - lw v0, SC_FPSR(a0) - ctc1 v0, $31 -#ifdef __LP64__ - # callee-saved fp regs on mips n64 ABI are $f24..$f31 - l.d $f24, SC_FPREGS+0*REGSZ_FP(a0) - l.d $f25, SC_FPREGS+1*REGSZ_FP(a0) - l.d $f26, SC_FPREGS+2*REGSZ_FP(a0) - l.d $f27, SC_FPREGS+3*REGSZ_FP(a0) - l.d $f28, SC_FPREGS+4*REGSZ_FP(a0) - l.d $f29, SC_FPREGS+5*REGSZ_FP(a0) - l.d $f30, SC_FPREGS+6*REGSZ_FP(a0) - l.d $f31, SC_FPREGS+7*REGSZ_FP(a0) -#else - # callee-saved fp regs on mips o32 ABI are - # the even-numbered fp regs $f20,$f22,...$f30 - l.d $f20, SC_FPREGS+0*REGSZ_FP(a0) - l.d $f22, SC_FPREGS+1*REGSZ_FP(a0) - l.d $f24, SC_FPREGS+2*REGSZ_FP(a0) - l.d $f26, SC_FPREGS+3*REGSZ_FP(a0) - l.d $f28, SC_FPREGS+4*REGSZ_FP(a0) - l.d $f30, SC_FPREGS+5*REGSZ_FP(a0) -#endif - bne a1, zero, 1f - li a1, 1 # never return 0! -1: - move v0, a1 - j ra - -_longjmp_botch: - jal longjmperror - jal abort - RESTORE_GP64 - PTR_ADDU sp, FRAMESZ -END(_longjmp) - -/* - * trampolines for sigsetjmp and siglongjmp save and restore mask. - * - */ -FRAMESZ= MKFSIZ(1,1) -GPOFF= FRAMESZ-2*REGSZ - -LEAF(sigsetjmp, FRAMESZ) - PTR_SUBU sp, FRAMESZ - SETUP_GP64(GPOFF, sigsetjmp) - .set reorder - sw a1, _JBLEN*REGSZ(a0) # save "savemask" - bne a1, 0x0, 1f # do saving of signal mask? - LA t9, _setjmp - RESTORE_GP64 - PTR_ADDU sp, FRAMESZ - jr t9 - -1: LA t9, setjmp - RESTORE_GP64 - PTR_ADDU sp, FRAMESZ - jr t9 -END(sigsetjmp) - -LEAF(siglongjmp, FRAMESZ) - PTR_SUBU sp, FRAMESZ - SETUP_GP64(GPOFF, siglongjmp) - .set reorder - lw t0, _JBLEN*REGSZ(a0) # get "savemask" - bne t0, 0x0, 1f # restore signal mask? - LA t9, _longjmp - RESTORE_GP64 - PTR_ADDU sp, FRAMESZ - jr t9 -1: - LA t9, longjmp - RESTORE_GP64 - PTR_ADDU sp, FRAMESZ - jr t9 END(siglongjmp) + + + .globl longjmp + .type longjmp, @function + .equ longjmp, siglongjmp # alias for siglongjmp + + + .globl _longjmp + .type _longjmp, @function + .equ _longjmp, siglongjmp # alias for siglongjmp diff --git a/libc/arch-mips/include/machine/setjmp.h b/libc/arch-mips/include/machine/setjmp.h index a9707dc2e..4067d510a 100644 --- a/libc/arch-mips/include/machine/setjmp.h +++ b/libc/arch-mips/include/machine/setjmp.h @@ -6,9 +6,10 @@ #define _MIPS_SETJMP_H_ #ifdef __LP64__ -#define _JBLEN 22 /* size, in 8-byte longs, of a mips64 jmp_buf */ +#define _JBLEN 25 /* size, in 8-byte longs, of a mips64 jmp_buf/sigjmp_buf */ #else -#define _JBLEN 29 /* size, in 4-byte longs, of a mips32 jmp_buf */ +#define _JBLEN 157 /* historical size, in 4-byte longs, of a mips32 jmp_buf */ + /* actual used size is 34 */ #endif #endif /* !_MIPS_SETJMP_H_ */