OSDN Git Service

Minor copyright header unification.
[android-x86/bionic.git] / libc / arch-arm / bionic / setjmp.S
index 8220c08..6ee162e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 1997 Mark Brinicombe
- * Copyright (c) 2010 Android Open Source Project.
+ * Copyright (C) 2010 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 // According to the ARM AAPCS document, we only need to save
 // the following registers:
 //
-//  Core   r4-r14
-//
-//  VFP    d8-d15  (see section 5.1.2.1)
+//  Core   r4-r11, sp, lr
+//    AAPCS 5.1.1:
+//      A subroutine must preserve the contents of the registers r4-r8, r10, r11
+//      and SP (and r9 in PCS variants that designate r9 as v6).
 //
+//  VFP    d8-d15
+//    AAPCS 5.1.2.1:
 //      Registers s16-s31 (d8-d15, q4-q7) must be preserved across subroutine
 //      calls; registers s0-s15 (d0-d7, q0-q3) do not need to be preserved
 //      (and can be used for passing arguments or returning results in standard
 //  FPSCR  saved because glibc does.
 
 // The internal structure of a jmp_buf is totally private.
-// Current layout (may change in the future):
+// Current layout (changes from release to release):
 //
-// word   name         description
-// 0      magic        magic number
-// 1      sigmask      signal mask (not used with _setjmp / _longjmp)
-// 2      float_base   base of float registers (d8 to d15)
-// 18     float_state  floating-point status and control register
-// 19     core_base    base of core registers (r4 to r14)
-// 30     reserved     reserved entries (room to grow)
+// word   name            description
+// 0      sigflag/cookie  setjmp cookie in top 31 bits, signal mask flag in low bit
+// 1      sigmask         signal mask (not used with _setjmp / _longjmp)
+// 2      float_base      base of float registers (d8 to d15)
+// 18     float_state     floating-point status and control register
+// 19     core_base       base of core registers (r4-r11, r13-r14)
+// 29     checksum        checksum of all of the core registers, to give better error messages.
+// 30     reserved        reserved entries (room to grow)
 // 64
 //
 // NOTE: float_base must be at an even word index, since the
@@ -69,6 +73,7 @@
 #define _JB_FLOAT_BASE  (_JB_SIGMASK+1)
 #define _JB_FLOAT_STATE (_JB_FLOAT_BASE + (15-8+1)*2)
 #define _JB_CORE_BASE   (_JB_FLOAT_STATE+1)
+#define _JB_CHECKSUM    (_JB_CORE_BASE+10)
 
 ENTRY(setjmp)
   mov r1, #1
@@ -80,33 +85,91 @@ ENTRY(_setjmp)
   b sigsetjmp
 END(_setjmp)
 
+#define MANGLE_REGISTERS 1
+#define USE_CHECKSUM 1
+
+.macro m_mangle_registers reg
+#if MANGLE_REGISTERS
+  eor r4, r4, \reg
+  eor r5, r5, \reg
+  eor r6, r6, \reg
+  eor r7, r7, \reg
+  eor r8, r8, \reg
+  eor r9, r9, \reg
+  eor r10, r10, \reg
+  eor r11, r11, \reg
+  eor r13, r13, \reg
+  eor r14, r14, \reg
+#endif
+.endm
+
+.macro m_unmangle_registers reg
+  m_mangle_registers \reg
+.endm
+
+.macro m_calculate_checksum dst, src, scratch
+  mov \dst, #0
+  .irp i,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28
+    ldr \scratch, [\src, #(\i * 4)]
+    eor \dst, \dst, \scratch
+  .endr
+.endm
+
 // int sigsetjmp(sigjmp_buf env, int save_signal_mask);
 ENTRY(sigsetjmp)
-  // Record whether or not we're saving the signal mask.
+  stmfd sp!, {r0, lr}
+  .cfi_def_cfa_offset 8
+  .cfi_rel_offset r0, 0
+  .cfi_rel_offset lr, 4
+
+  mov r0, r1
+  bl __bionic_setjmp_cookie_get
+  mov r1, r0
+
+  ldmfd sp, {r0}
+
+  // Save the setjmp cookie for later.
+  bic r2, r1, #1
+  stmfd sp!, {r2}
+  .cfi_adjust_cfa_offset 4
+
+  // Record the setjmp cookie and whether or not we're saving the signal mask.
   str r1, [r0, #(_JB_SIGFLAG * 4)]
 
   // Do we need to save the signal mask?
-  teq r1, #0
+  tst r1, #1
   beq 1f
 
-  // Get current signal mask.
-  stmfd sp!, {r0, r14}
-  .cfi_def_cfa_offset 8
-  .cfi_rel_offset r0, 0
-  .cfi_rel_offset r14, 4
-  mov r0, #0
-  bl sigblock
-  mov r1, r0
-  ldmfd sp!, {r0, r14}
-  .cfi_def_cfa_offset 0
+  // Align the stack.
+  sub sp, #4
+  .cfi_adjust_cfa_offset 4
 
-  // Save the signal mask.
-  str r1, [r0, #(_JB_SIGMASK * 4)]
+  // Save the current signal mask.
+  add r2, r0, #(_JB_SIGMASK * 4)
+  mov r0, #2 // SIG_SETMASK
+  mov r1, #0
+  bl sigprocmask
+
+  // Unalign the stack.
+  add sp, #4
+  .cfi_adjust_cfa_offset -4
 
 1:
+  ldmfd sp!, {r2}
+  .cfi_adjust_cfa_offset -4
+  ldmfd sp!, {r0, lr}
+  .cfi_adjust_cfa_offset -8
+  .cfi_restore r0
+  .cfi_restore lr
+
   // Save core registers.
   add r1, r0, #(_JB_CORE_BASE * 4)
-  stmia r1, {r4-r14}
+  m_mangle_registers r2
+
+  // ARM deprecates using sp in the register list for stmia.
+  stmia r1, {r4-r11, lr}
+  str sp, [r1, #(9 * 4)]
+  m_unmangle_registers r2
 
   // Save floating-point registers.
   add r1, r0, #(_JB_FLOAT_BASE * 4)
@@ -116,35 +179,51 @@ ENTRY(sigsetjmp)
   fmrx r1, fpscr
   str r1, [r0, #(_JB_FLOAT_STATE * 4)]
 
+#if USE_CHECKSUM
+  // Calculate the checksum.
+  m_calculate_checksum r12, r0, r2
+  str r12, [r0, #(_JB_CHECKSUM * 4)]
+#endif
+
   mov r0, #0
   bx lr
 END(sigsetjmp)
 
 // void siglongjmp(sigjmp_buf env, int value);
 ENTRY(siglongjmp)
-  // Do we need to restore the signal mask?
-  ldr r2, [r0, #(_JB_SIGFLAG * 4)]
-  teq r2, #0
-  beq 1f
-
-  // Restore the signal mask.
-  stmfd sp!, {r0, r1, r14}
+  stmfd sp!, {r0, r1, lr}
   .cfi_def_cfa_offset 12
   .cfi_rel_offset r0, 0
   .cfi_rel_offset r1, 4
-  .cfi_rel_offset r14, 8
-  sub sp, sp, #4 // Align the stack.
-  .cfi_adjust_cfa_offset 4
+  .cfi_rel_offset lr, 8
+
+#if USE_CHECKSUM
+  // Check the checksum before doing anything.
+  m_calculate_checksum r12, r0, r3
+  ldr r2, [r0, #(_JB_CHECKSUM * 4)]
+
+  teq r2, r12
+  bne __bionic_setjmp_checksum_mismatch
+#endif
+
+  // Fetch the signal flag.
+  ldr r1, [r0, #(_JB_SIGFLAG * 4)]
 
+  // Do we need to restore the signal mask?
+  ands r1, r1, #1
+  beq 1f
+
+  // Restore the signal mask.
   ldr r0, [r0, #(_JB_SIGMASK * 4)]
   bl sigsetmask
 
-  add sp, sp, #4 // Unalign the stack.
-  .cfi_adjust_cfa_offset -4
-  ldmfd sp!, {r0, r1, r14}
-  .cfi_def_cfa_offset 0
-
 1:
+  ldmfd sp!, {r0, r1, lr}
+  .cfi_adjust_cfa_offset -12
+  .cfi_restore r0
+  .cfi_restore r1
+  .cfi_restore lr
+
   // Restore floating-point registers.
   add r2, r0, #(_JB_FLOAT_BASE * 4)
   vldmia r2, {d8-d15}
@@ -153,17 +232,30 @@ ENTRY(siglongjmp)
   ldr r2, [r0, #(_JB_FLOAT_STATE * 4)]
   fmxr fpscr, r2
 
+  // Load the cookie.
+  ldr r3, [r0, #(_JB_SIGFLAG * 4)]
+  bic r3, r3, #1
+
   // Restore core registers.
   add r2, r0, #(_JB_CORE_BASE * 4)
-  ldmia r2, {r4-r14}
 
-  // Validate sp and r14.
-  teq sp, #0
-  teqne r14, #0
-  bleq longjmperror
+  // ARM deprecates using sp in the register list for ldmia.
+  ldmia r2, {r4-r11, lr}
+  ldr sp, [r2, #(9 * 4)]
+  m_unmangle_registers r3
+
+  // Save the return value/address and check the setjmp cookie.
+  stmfd sp!, {r1, lr}
+  .cfi_adjust_cfa_offset 8
+  .cfi_rel_offset lr, 4
+  mov r0, r3
+  bl __bionic_setjmp_cookie_check
+
+  // Restore return value/address.
+  ldmfd sp!, {r0, lr}
+  .cfi_adjust_cfa_offset -8
+  .cfi_restore lr
 
-  // Set return value.
-  mov r0, r1
   teq r0, #0
   moveq r0, #1
   bx lr