1 /* This is a simple version of setjmp and longjmp. 2 3 Nick Clifton, Cygnus Solutions, 13 June 1997. */ 4 5 /* ANSI concatenation macros. */ 6 #define CONCAT(a, b) CONCAT2(a, b) 7 #define CONCAT2(a, b) a##b 8 9 #ifndef __USER_LABEL_PREFIX__ 10 #error __USER_LABEL_PREFIX__ not defined 11 #endif 12 13 #define SYM(x) CONCAT (__USER_LABEL_PREFIX__, x) 14 15 #ifdef __ELF__ 16 #define TYPE(x) .type SYM(x),function 17 #define SIZE(x) .size SYM(x), . - SYM(x) 18 #else 19 #define TYPE(x) 20 #define SIZE(x) 21 #endif 22 23 /* Arm/Thumb interworking support: 24 25 The interworking scheme expects functions to use a BX instruction 26 to return control to their parent. Since we need this code to work 27 in both interworked and non-interworked environments as well as with 28 older processors which do not have the BX instruction we do the 29 following: 30 Test the return address. 31 If the bottom bit is clear perform an "old style" function exit. 32 (We know that we are in ARM mode and returning to an ARM mode caller). 33 Otherwise use the BX instruction to perform the function exit. 34 35 We know that we will never attempt to perform the BX instruction on 36 an older processor, because that kind of processor will never be 37 interworked, and a return address with the bottom bit set will never 38 be generated. 39 40 In addition, we do not actually assemble the BX instruction as this would 41 require us to tell the assembler that the processor is an ARM7TDMI and 42 it would store this information in the binary. We want this binary to be 43 able to be linked with binaries compiled for older processors however, so 44 we do not want such information stored there. 45 46 If we are running using the APCS-26 convention however, then we never 47 test the bottom bit, because this is part of the processor status. 48 Instead we just do a normal return, since we know that we cannot be 49 returning to a Thumb caller - the Thumb does not support APCS-26. 50 51 Function entry is much simpler. If we are compiling for the Thumb we 52 just switch into ARM mode and then drop through into the rest of the 53 function. The function exit code will take care of the restore to 54 Thumb mode. 55 56 For Thumb-2 do everything in Thumb mode. */ 57 58 #if defined(__ARM_ARCH_6M__) 59 /* ARMv6-M has to be implemented in Thumb mode. */ 60 61 .thumb 62 .thumb_func 63 .globl SYM (setjmp) 64 TYPE (setjmp) 65 SYM (setjmp): 66 /* Save registers in jump buffer. */ 67 stmia r0!, {r4, r5, r6, r7} 68 mov r1, r8 69 mov r2, r9 70 mov r3, r10 71 mov r4, fp 72 mov r5, sp 73 mov r6, lr 74 stmia r0!, {r1, r2, r3, r4, r5, r6} 75 sub r0, r0, #40 76 /* Restore callee-saved low regs. */ 77 ldmia r0!, {r4, r5, r6, r7} 78 /* Return zero. */ 79 mov r0, #0 80 bx lr 81 82 .thumb_func 83 .globl SYM (longjmp) 84 TYPE (longjmp) 85 SYM (longjmp): 86 /* Restore High regs. */ 87 add r0, r0, #16 88 ldmia r0!, {r2, r3, r4, r5, r6} 89 mov r8, r2 90 mov r9, r3 91 mov r10, r4 92 mov fp, r5 93 mov sp, r6 94 ldmia r0!, {r3} /* lr */ 95 /* Restore low regs. */ 96 sub r0, r0, #40 97 ldmia r0!, {r4, r5, r6, r7} 98 /* Return the result argument, or 1 if it is zero. */ 99 mov r0, r1 100 bne 1f 101 mov r0, #1 102 1: 103 bx r3 104 105 #else 106 107 #ifdef __APCS_26__ 108 #define RET movs pc, lr 109 #elif defined(__thumb2__) 110 #define RET bx lr 111 #else 112 #define RET tst lr, #1; \ 113 moveq pc, lr ; \ 114 .word 0xe12fff1e /* bx lr */ 115 #endif 116 117 #ifdef __thumb2__ 118 .macro COND where when 119 i\where \when 120 .endm 121 #else 122 .macro COND where when 123 .endm 124 #endif 125 126 #if defined(__thumb2__) 127 .syntax unified 128 .macro MODE 129 .thumb 130 .thumb_func 131 .endm 132 .macro PROLOGUE name 133 .endm 134 135 #elif defined(__thumb__) 136 #define MODE .thumb_func 137 .macro PROLOGUE name 138 .code 16 139 bx pc 140 nop 141 .code 32 142 SYM (.arm_start_of.\name): 143 .endm 144 #else /* Arm */ 145 #define MODE .code 32 146 .macro PROLOGUE name 147 .endm 148 #endif 149 150 .macro FUNC_START name 151 .text 152 .align 2 153 MODE 154 .globl SYM (\name) 155 TYPE (\name) 156 SYM (\name): 157 PROLOGUE \name 158 .endm 159 160 .macro FUNC_END name 161 RET 162 SIZE (\name) 163 .endm 164 165 /* -------------------------------------------------------------------- 166 int setjmp (jmp_buf); 167 -------------------------------------------------------------------- */ 168 169 FUNC_START setjmp 170 171 /* Save all the callee-preserved registers into the jump buffer. */ 172 #ifdef __thumb2__ 173 mov ip, sp 174 stmea a1!, { v1-v7, fp, ip, lr } 175 #else 176 stmea a1!, { v1-v7, fp, ip, sp, lr } 177 #endif 178 179 #if 0 /* Simulator does not cope with FP instructions yet. */ 180 #ifndef __SOFTFP__ 181 /* Save the floating point registers. */ 182 sfmea f4, 4, [a1] 183 #endif 184 #endif 185 /* When setting up the jump buffer return 0. */ 186 mov a1, #0 187 188 FUNC_END setjmp 189 190 /* -------------------------------------------------------------------- 191 volatile void longjmp (jmp_buf, int); 192 -------------------------------------------------------------------- */ 193 194 FUNC_START longjmp 195 196 /* If we have stack extension code it ought to be handled here. */ 197 198 /* Restore the registers, retrieving the state when setjmp() was called. */ 199 #ifdef __thumb2__ 200 ldmfd a1!, { v1-v7, fp, ip, lr } 201 mov sp, ip 202 #else 203 ldmfd a1!, { v1-v7, fp, ip, sp, lr } 204 #endif 205 206 #if 0 /* Simulator does not cope with FP instructions yet. */ 207 #ifndef __SOFTFP__ 208 /* Restore floating point registers as well. */ 209 lfmfd f4, 4, [a1] 210 #endif 211 #endif 212 /* Put the return value into the integer result register. 213 But if it is zero then return 1 instead. */ 214 movs a1, a2 215 #ifdef __thumb2__ 216 it eq 217 #endif 218 moveq a1, #1 219 220 FUNC_END longjmp 221 #endif