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