diff options
Diffstat (limited to 'libc/arch-arm64/bionic/setjmp.S')
-rw-r--r-- | libc/arch-arm64/bionic/setjmp.S | 205 |
1 files changed, 116 insertions, 89 deletions
diff --git a/libc/arch-arm64/bionic/setjmp.S b/libc/arch-arm64/bionic/setjmp.S index f9d2266..ba0a226 100644 --- a/libc/arch-arm64/bionic/setjmp.S +++ b/libc/arch-arm64/bionic/setjmp.S @@ -27,97 +27,124 @@ */ #include <private/bionic_asm.h> -#include <machine/setjmp.h> -/* - * C library - _setjmp, _longjmp - * - * _longjmp(jmp_buf state, int value) - * will generate a "return(v)" from the last call to _setjmp(state) by restoring - * registers from the stack. The previous signal state is NOT restored. - * - * NOTE: x0 return value - * x9-x15 temporary registers - */ +// According to AARCH64 PCS document we need to save the following +// registers: +// +// Core x19 - x30, sp (see section 5.1.1) +// VFP d8 - d15 (see section 5.1.2) +// +// NOTE: All the registers saved here will have 64 bit vales. +// AAPCS mandates that the higher part of q registers do not need to +// be saved by the callee. + +#define _JB_SIGFLAG 0 +#define _JB_SIGMASK (_JB_SIGFLAG + 1) +#define _JB_X30_SP (_JB_SIGMASK + 1) +#define _JB_X28_X29 (_JB_X30_SP + 2) +#define _JB_X26_X27 (_JB_X28_X29 + 2) +#define _JB_X24_X25 (_JB_X26_X27 + 2) +#define _JB_X22_X23 (_JB_X24_X25 + 2) +#define _JB_X20_X21 (_JB_X22_X23 + 2) +#define _JB_X19 (_JB_X20_X21 + 2) +#define _JB_D14_D15 (_JB_X19 + 1) +#define _JB_D12_D13 (_JB_D14_D15 + 2) +#define _JB_D10_D11 (_JB_D12_D13 + 2) +#define _JB_D8_D9 (_JB_D10_D11 + 2) ENTRY(setjmp) - /* block all signals an retrieve signal mask */ - stp x0, x30, [sp, #-16]! - - mov x0, xzr - bl PIC_SYM(sigblock, PLT) - mov w1, w0 - - ldp x0, x30, [sp], #16 - - /* store signal mask */ - str w1, [x0, #(_JB_SIGMASK *4)] - - /* store magic number */ - ldr w9, .L_setjmp_magic - str w9, [x0, #(_JB_MAGIC * 4)] - - /* store core registers */ - mov x10, sp - stp x30, x10, [x0, #(_JB_CORE_BASE * 4 + 16 * 0)] - stp x28, x29, [x0, #(_JB_CORE_BASE * 4 + 16 * 1)] - stp x26, x27, [x0, #(_JB_CORE_BASE * 4 + 16 * 2)] - stp x24, x25, [x0, #(_JB_CORE_BASE * 4 + 16 * 3)] - stp x22, x23, [x0, #(_JB_CORE_BASE * 4 + 16 * 4)] - stp x20, x21, [x0, #(_JB_CORE_BASE * 4 + 16 * 5)] - str x19, [x0, #(_JB_CORE_BASE * 4 + 16 * 6)] - - /* store floating point registers */ - stp d14, d15, [x0, #(_JB_FLOAT_BASE * 4 + 16 * 0)] - stp d12, d13, [x0, #(_JB_FLOAT_BASE * 4 + 16 * 1)] - stp d10, d11, [x0, #(_JB_FLOAT_BASE * 4 + 16 * 2)] - stp d8, d9, [x0, #(_JB_FLOAT_BASE * 4 + 16 * 3)] - - mov w0, wzr - ret + mov w1, #1 + b sigsetjmp END(setjmp) -.L_setjmp_magic: - .word _JB_MAGIC__SETJMP - -ENTRY(longjmp) - /* check magic */ - ldr w9, .L_setjmp_magic - ldr w10, [x0, #(_JB_MAGIC * 4)] - cmp w9, w10 - b.ne .L_fail - - /* restore core registers */ - ldp x30, x10, [x0, #(_JB_CORE_BASE * 4 + 16 * 0)] - mov sp, x10 - ldp x28, x29, [x0, #(_JB_CORE_BASE * 4 + 16 * 1)] - ldp x26, x27, [x0, #(_JB_CORE_BASE * 4 + 16 * 2)] - ldp x24, x25, [x0, #(_JB_CORE_BASE * 4 + 16 * 3)] - ldp x22, x23, [x0, #(_JB_CORE_BASE * 4 + 16 * 4)] - ldp x20, x21, [x0, #(_JB_CORE_BASE * 4 + 16 * 5)] - ldr x19, [x0, #(_JB_CORE_BASE * 4 + 16 * 6)] - - /* restore floating point registers */ - ldp d14, d15, [x0, #(_JB_FLOAT_BASE * 4 + 16 * 0)] - ldp d12, d13, [x0, #(_JB_FLOAT_BASE * 4 + 16 * 1)] - ldp d10, d11, [x0, #(_JB_FLOAT_BASE * 4 + 16 * 2)] - ldp d8, d9, [x0, #(_JB_FLOAT_BASE * 4 + 16 * 3)] - - /* validate sp (sp mod 16 = 0) and lr (lr mod 4 = 0) */ - tst x30, #3 - b.ne .L_fail - mov x10, sp - tst x10, #15 - b.ne .L_fail - - /* set return value */ - cmp w1, wzr - csinc w0, w1, wzr, ne - ret - - /* validation failed, die die die */ -.L_fail: - bl PIC_SYM(longjmperror, PLT) - bl PIC_SYM(abort, PLT) - b . - 8 /* Cannot get here */ -END(longjmp) +ENTRY(_setjmp) + mov w1, #0 + b sigsetjmp +END(_setjmp) + +// int sigsetjmp(sigjmp_buf env, int save_signal_mask); +ENTRY(sigsetjmp) + // Record whether or not we're saving the signal mask. + str w1, [x0, #(_JB_SIGFLAG * 8)] + + // Do we need to save the signal mask? + cbz w1, 1f + + // Save current signal mask. + stp x0, x30, [sp, #-16]! + // The 'how' argument is ignored if new_mask is NULL. + mov x1, #0 // NULL. + add x2, x0, #(_JB_SIGMASK * 8) // old_mask. + bl sigprocmask + ldp x0, x30, [sp], #16 + +1: + // Save core registers. + mov x10, sp + stp x30, x10, [x0, #(_JB_X30_SP * 8)] + stp x28, x29, [x0, #(_JB_X28_X29 * 8)] + stp x26, x27, [x0, #(_JB_X26_X27 * 8)] + stp x24, x25, [x0, #(_JB_X24_X25 * 8)] + stp x22, x23, [x0, #(_JB_X22_X23 * 8)] + stp x20, x21, [x0, #(_JB_X20_X21 * 8)] + str x19, [x0, #(_JB_X19 * 8)] + + // Save floating point registers. + stp d14, d15, [x0, #(_JB_D14_D15 * 8)] + stp d12, d13, [x0, #(_JB_D12_D13 * 8)] + stp d10, d11, [x0, #(_JB_D10_D11 * 8)] + stp d8, d9, [x0, #(_JB_D8_D9 * 8)] + + mov w0, #0 + ret +END(sigsetjmp) + +// void siglongjmp(sigjmp_buf env, int value); +ENTRY(siglongjmp) + // Do we need to restore the signal mask? + ldr w9, [x0, #(_JB_SIGFLAG * 8)] + cbz w9, 1f + + // Restore signal mask. + stp x0, x30, [sp, #-16]! + mov x19, x1 // Save 'value'. + mov x2, x0 + mov x0, #2 // SIG_SETMASK + add x1, x2, #(_JB_SIGMASK * 8) // new_mask. + mov x2, #0 // NULL. + bl sigprocmask + mov x1, x19 // Restore 'value'. + ldp x0, x30, [sp], #16 + +1: + // Restore core registers. + ldp x30, x10, [x0, #(_JB_X30_SP * 8)] + mov sp, x10 + ldp x28, x29, [x0, #(_JB_X28_X29 * 8)] + ldp x26, x27, [x0, #(_JB_X26_X27 * 8)] + ldp x24, x25, [x0, #(_JB_X24_X25 * 8)] + ldp x22, x23, [x0, #(_JB_X22_X23 * 8)] + ldp x20, x21, [x0, #(_JB_X20_X21 * 8)] + ldr x19, [x0, #(_JB_X19 * 8)] + + // Restore floating point registers. + ldp d14, d15, [x0, #(_JB_D14_D15 * 8)] + ldp d12, d13, [x0, #(_JB_D12_D13 * 8)] + ldp d10, d11, [x0, #(_JB_D10_D11 * 8)] + ldp d8, d9, [x0, #(_JB_D8_D9 * 8)] + + // Validate sp (sp mod 16 = 0) and lr (lr mod 4 = 0). + tst x30, #3 + b.ne longjmperror + mov x10, sp + tst x10, #15 + b.ne longjmperror + + // Set return value. + cmp w1, wzr + csinc w0, w1, wzr, ne + ret +END(siglongjmp) + +ALIAS_SYMBOL(longjmp, siglongjmp) +ALIAS_SYMBOL(_longjmp, siglongjmp) |