summaryrefslogtreecommitdiff
path: root/lib/libutils/isoc/arch/arm/setjmp_a32.S
blob: bf7ef8bf7460e5f3276dbee88becde40d0d9e2df (plain)
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
/*
 * Copyright (c) 1994-2009  Red Hat, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. Neither the name of the copyright holder nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * 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 HOLDER 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.
 */
/* This is a simple version of setjmp and longjmp.

   Nick Clifton, Cygnus Solutions, 13 June 1997.  */

/* ANSI concatenation macros.  */
#define CONCAT(a, b)  CONCAT2(a, b)
#define CONCAT2(a, b) a##b

#ifndef __USER_LABEL_PREFIX__
#error  __USER_LABEL_PREFIX__ not defined
#endif

#define SYM(x) CONCAT (__USER_LABEL_PREFIX__, x)

#ifdef __ELF__
#define TYPE(x) .type SYM(x),function
#define SIZE(x) .size SYM(x), . - SYM(x)
#else
#define TYPE(x)
#define SIZE(x)
#endif

/* Arm/Thumb interworking support:

   The interworking scheme expects functions to use a BX instruction
   to return control to their parent.  Since we need this code to work
   in both interworked and non-interworked environments as well as with
   older processors which do not have the BX instruction we do the 
   following:
	Test the return address.
	If the bottom bit is clear perform an "old style" function exit.
	(We know that we are in ARM mode and returning to an ARM mode caller).
	Otherwise use the BX instruction to perform the function exit.

   We know that we will never attempt to perform the BX instruction on 
   an older processor, because that kind of processor will never be 
   interworked, and a return address with the bottom bit set will never 
   be generated.

   In addition, we do not actually assemble the BX instruction as this would
   require us to tell the assembler that the processor is an ARM7TDMI and
   it would store this information in the binary.  We want this binary to be
   able to be linked with binaries compiled for older processors however, so
   we do not want such information stored there.  

   If we are running using the APCS-26 convention however, then we never
   test the bottom bit, because this is part of the processor status.  
   Instead we just do a normal return, since we know that we cannot be 
   returning to a Thumb caller - the Thumb does not support APCS-26.
	
   Function entry is much simpler.  If we are compiling for the Thumb we 
   just switch into ARM mode and then drop through into the rest of the
   function.  The function exit code will take care of the restore to
   Thumb mode.
   
   For Thumb-2 do everything in Thumb mode.  */

#if defined(__ARM_ARCH_6M__)
/* ARMv6-M has to be implemented in Thumb mode.  */

.thumb
.thumb_func
	.globl SYM (setjmp)
	TYPE (setjmp)
SYM (setjmp):
	/* Save registers in jump buffer.  */
	stmia	r0!, {r4, r5, r6, r7}
	mov	r1, r8
	mov	r2, r9
	mov	r3, r10
	mov	r4, fp
	mov	r5, sp
	mov	r6, lr
	stmia	r0!, {r1, r2, r3, r4, r5, r6}
	sub	r0, r0, #40
	/* Restore callee-saved low regs.  */
	ldmia	r0!, {r4, r5, r6, r7}
	/* Return zero.  */
	mov	r0, #0
	bx lr

.thumb_func
	.globl SYM (longjmp)
	TYPE (longjmp)
SYM (longjmp):
	/* Restore High regs.  */
	add	r0, r0, #16
	ldmia	r0!, {r2, r3, r4, r5, r6}
	mov	r8, r2
	mov	r9, r3
	mov	r10, r4
	mov	fp, r5
	mov	sp, r6
	ldmia	r0!, {r3} /* lr */
	/* Restore low regs.  */
	sub	r0, r0, #40
	ldmia	r0!, {r4, r5, r6, r7}
	/* Return the result argument, or 1 if it is zero.  */
	mov	r0, r1
	bne	1f
	mov	r0, #1
1:
	bx	r3

#else

#ifdef __APCS_26__
#define RET	movs		pc, lr
#elif defined(__thumb2__)
#define RET	bx lr
#else
#define RET	tst		lr, #1; \
	        moveq		pc, lr ; \
.word           0xe12fff1e	/* bx lr */
#endif

#ifdef __thumb2__
.macro COND where when 
	i\where	\when
.endm
#else
.macro COND where when 
.endm
#endif

#if defined(__thumb2__)
.syntax unified
.macro MODE
	.thumb
	.thumb_func
.endm
.macro PROLOGUE name
.endm

#elif defined(__thumb__)
#define	MODE		.thumb_func
.macro PROLOGUE name
	.code 16
	bx	pc
	nop	
	.code 32
SYM (.arm_start_of.\name):
.endm
#else /* Arm */
#define	MODE		.code 32
.macro PROLOGUE name
.endm
#endif
	
.macro FUNC_START name
	.text
	.align 2
	MODE
	.globl SYM (\name)
	TYPE (\name)
SYM (\name):
	PROLOGUE \name
.endm

.macro FUNC_END name
	RET
	SIZE (\name)
.endm
	
/* --------------------------------------------------------------------
                 int setjmp (jmp_buf); 
   -------------------------------------------------------------------- */
	
	FUNC_START setjmp

	/* Save all the callee-preserved registers into the jump buffer.  */
#ifdef __thumb2__
	mov		ip, sp
	stmea		a1!, { v1-v7, fp, ip, lr }
#else
	stmea		a1!, { v1-v7, fp, ip, sp, lr }
#endif
	
#if 0	/* Simulator does not cope with FP instructions yet.  */
#ifndef __SOFTFP__
	/* Save the floating point registers.  */
	sfmea		f4, 4, [a1]
#endif
#endif		
	/* When setting up the jump buffer return 0.  */
	mov		a1, #0

	FUNC_END setjmp
	
/* --------------------------------------------------------------------
		volatile void longjmp (jmp_buf, int);
   -------------------------------------------------------------------- */
	
	FUNC_START longjmp

	/* If we have stack extension code it ought to be handled here.  */
	
	/* Restore the registers, retrieving the state when setjmp() was called.  */
#ifdef __thumb2__
	ldmfd		a1!, { v1-v7, fp, ip, lr }
	mov		sp, ip
#else
	ldmfd		a1!, { v1-v7, fp, ip, sp, lr }
#endif
	
#if 0	/* Simulator does not cope with FP instructions yet.  */
#ifndef __SOFTFP__
	/* Restore floating point registers as well.  */
	lfmfd		f4, 4, [a1]
#endif
#endif	
	/* Put the return value into the integer result register.
	   But if it is zero then return 1 instead.  */	
	movs		a1, a2
#ifdef __thumb2__
	it		eq
#endif
	moveq		a1, #1

	FUNC_END longjmp
#endif