1234353Sdim/* Support functions for the unwinder.
2218885Sdim   Copyright (C) 2003-2020 Free Software Foundation, Inc.
3218885Sdim   Contributed by Paul Brook
4218885Sdim
5218885Sdim   This file is free software; you can redistribute it and/or modify it
6218885Sdim   under the terms of the GNU General Public License as published by the
7218885Sdim   Free Software Foundation; either version 3, or (at your option) any
8218885Sdim   later version.
9218885Sdim
10218885Sdim   This file is distributed in the hope that it will be useful, but
11218885Sdim   WITHOUT ANY WARRANTY; without even the implied warranty of
12218885Sdim   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13218885Sdim   General Public License for more details.
14218885Sdim
15218885Sdim   Under Section 7 of GPL version 3, you are granted additional
16218885Sdim   permissions described in the GCC Runtime Library Exception, version
17218885Sdim   3.1, as published by the Free Software Foundation.
18221345Sdim
19249423Sdim   You should have received a copy of the GNU General Public License and
20249423Sdim   a copy of the GCC Runtime Library Exception along with this program;
21249423Sdim   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
22218885Sdim   <http://www.gnu.org/licenses/>.  */
23218885Sdim
24218885Sdim/* An executable stack is *not* required for these functions.  */
25218885Sdim#if defined(__ELF__) && defined(__linux__)
26218885Sdim.section .note.GNU-stack,"",%progbits
27218885Sdim.previous
28249423Sdim#endif
29218885Sdim
30218885Sdim#ifdef __ARM_EABI__
31218885Sdim/* Some attributes that are common to all routines in this file.  */
32218885Sdim	/* Tag_ABI_align_needed: This code does not require 8-byte
33218885Sdim	   alignment from the caller.  */
34218885Sdim	/* .eabi_attribute 24, 0  -- default setting.  */
35218885Sdim	/* Tag_ABI_align_preserved: This code preserves 8-byte
36218885Sdim	   alignment in any callee.  */
37218885Sdim	.eabi_attribute 25, 1
38218885Sdim#endif /* __ARM_EABI__ */
39218885Sdim
40218885Sdim#ifndef __symbian__
41218885Sdim
42218885Sdim#include "lib1funcs.S"
43218885Sdim
44218885Sdim.macro UNPREFIX name
45218885Sdim	.global SYM (\name)
46218885Sdim	EQUIV SYM (\name), SYM (__\name)
47218885Sdim.endm
48218885Sdim
49218885Sdim#if (__ARM_ARCH == 4)
50218885Sdim/* Some coprocessors require armv5t.  We know this code will never be run on
51218885Sdim   other cpus.  Tell gas to allow armv5t, but only mark the objects as armv4.
52218885Sdim */
53218885Sdim.arch armv5t
54243830Sdim#ifdef __ARM_ARCH_4T__
55243830Sdim.object_arch armv4t
56218885Sdim#else
57218885Sdim.object_arch armv4
58221345Sdim#endif
59218885Sdim#endif
60218885Sdim
61218885Sdim#if !__ARM_ARCH_ISA_ARM && __ARM_ARCH_ISA_THUMB == 1
62218885Sdim
63218885Sdim/* r0 points to a 16-word block.  Upload these values to the actual core
64243830Sdim   state.  */
65218885SdimFUNC_START restore_core_regs
66221345Sdim	movs	r1, r0
67218885Sdim	adds	r1, r1, #52
68218885Sdim	ldmia	r1!, {r3, r4, r5}
69218885Sdim	subs	r3, r3, #4
70218885Sdim	mov	ip, r3
71218885Sdim	str	r5, [r3]
72218885Sdim	mov	lr, r4
73218885Sdim	/* Restore r8-r11.  */
74218885Sdim	movs	r1, r0
75218885Sdim	adds	r1, r1, #32
76218885Sdim	ldmia	r1!, {r2, r3, r4, r5}
77218885Sdim	mov	r8, r2
78218885Sdim	mov	r9, r3
79218885Sdim	mov	sl, r4
80218885Sdim	mov	fp, r5
81218885Sdim	movs	r1, r0
82218885Sdim	adds	r1, r1, #8
83218885Sdim	ldmia	r1!, {r2, r3, r4, r5, r6, r7}
84218885Sdim	ldr	r1, [r0, #4]
85218885Sdim	ldr	r0, [r0]
86218885Sdim	mov	sp, ip
87218885Sdim	pop	{pc}
88218885Sdim	FUNC_END restore_core_regs
89218885Sdim	UNPREFIX restore_core_regs
90218885Sdim
91218885Sdim/* ARMV6M does not have coprocessors, so these should never be used.  */
92218885SdimFUNC_START gnu_Unwind_Restore_VFP
93218885Sdim	RET
94218885Sdim
95218885Sdim/* Store VFR regsters d0-d15 to the address in r0.  */
96218885SdimFUNC_START gnu_Unwind_Save_VFP
97218885Sdim	RET
98218885Sdim
99218885Sdim/* Load VFP registers d0-d15 from the address in r0.
100218885Sdim   Use this to load from FSTMD format.  */
101218885SdimFUNC_START gnu_Unwind_Restore_VFP_D
102218885Sdim	RET
103218885Sdim
104218885Sdim/* Store VFP registers d0-d15 to the address in r0.
105218885Sdim   Use this to store in FLDMD format.  */
106218885SdimFUNC_START gnu_Unwind_Save_VFP_D
107218885Sdim	RET
108218885Sdim
109218885Sdim/* Load VFP registers d16-d31 from the address in r0.
110218885Sdim   Use this to load from FSTMD (=VSTM) format.  Needs VFPv3.  */
111218885SdimFUNC_START gnu_Unwind_Restore_VFP_D_16_to_31
112218885Sdim	RET
113218885Sdim
114218885Sdim/* Store VFP registers d16-d31 to the address in r0.
115218885Sdim   Use this to store in FLDMD (=VLDM) format.  Needs VFPv3.  */
116218885SdimFUNC_START gnu_Unwind_Save_VFP_D_16_to_31
117218885Sdim	RET
118218885Sdim
119218885SdimFUNC_START gnu_Unwind_Restore_WMMXD
120218885Sdim	RET
121218885Sdim
122218885SdimFUNC_START gnu_Unwind_Save_WMMXD
123218885Sdim	RET
124218885Sdim
125218885SdimFUNC_START gnu_Unwind_Restore_WMMXC
126218885Sdim	RET
127218885Sdim
128218885SdimFUNC_START gnu_Unwind_Save_WMMXC
129218885Sdim	RET
130218885Sdim
131218885Sdim.macro  UNWIND_WRAPPER name nargs
132218885Sdim	FUNC_START \name
133218885Sdim	/* Create a phase2_vrs structure.  */
134218885Sdim	/* Save r0 in the PC slot so we can use it as a scratch register.  */
135218885Sdim	push	{r0}
136218885Sdim	add	r0, sp, #4
137218885Sdim	push	{r0, lr} /* Push original SP and LR.  */
138218885Sdim	/* Make space for r8-r12.  */
139218885Sdim	sub	sp, sp, #20
140243830Sdim	/* Save low registers.  */
141243830Sdim	push	{r0, r1, r2, r3, r4, r5, r6, r7}
142243830Sdim	/* Save high registers.  */
143243830Sdim	add	r0, sp, #32
144243830Sdim	mov	r1, r8
145243830Sdim	mov	r2, r9
146243830Sdim	mov	r3, sl
147243830Sdim	mov	r4, fp
148243830Sdim	mov	r5, ip
149243830Sdim	stmia	r0!, {r1, r2, r3, r4, r5}
150243830Sdim	/* Restore original low register values.  */
151243830Sdim	add	r0, sp, #4
152243830Sdim	ldmia	r0!, {r1, r2, r3, r4, r5}
153243830Sdim	/* Restore orginial r0.  */
154243830Sdim	ldr	r0, [sp, #60]
155243830Sdim	str	r0, [sp]
156243830Sdim	/* Demand-save flags, plus an extra word for alignment.  */
157243830Sdim	movs	r3, #0
158243830Sdim	push	{r2, r3}
159243830Sdim	/* Point r1 at the block.  Pass r[0..nargs) unchanged.  */
160243830Sdim	add	r\nargs, sp, #4
161243830Sdim
162243830Sdim	bl	SYM (__gnu\name)
163243830Sdim
164243830Sdim	ldr	r3, [sp, #64]
165243830Sdim	add	sp, sp, #72
166243830Sdim	bx	r3
167243830Sdim
168243830Sdim	FUNC_END \name
169243830Sdim	UNPREFIX \name
170243830Sdim.endm
171243830Sdim
172243830Sdim#else /* __ARM_ARCH_ISA_ARM || __ARM_ARCH_ISA_THUMB != 1 */
173243830Sdim
174243830Sdim/* r0 points to a 16-word block.  Upload these values to the actual core
175243830Sdim   state.  */
176243830SdimARM_FUNC_START restore_core_regs
177243830Sdim	/* We must use sp as the base register when restoring sp.  Push the
178243830Sdim	   last 3 registers onto the top of the current stack to achieve
179243830Sdim	   this.  */
180243830Sdim	add r1, r0, #52
181243830Sdim	ldmia r1, {r3, r4, r5}  /* {sp, lr, pc}.  */
182243830Sdim#if defined(__thumb2__)
183243830Sdim	/* Thumb-2 doesn't allow sp in a load-multiple instruction, so push
184218885Sdim	   the target address onto the target stack.  This is safe as
185219077Sdim	   we're always returning to somewhere further up the call stack.  */
186224145Sdim	mov ip, r3
187224145Sdim	mov lr, r4
188234353Sdim	str r5, [ip, #-4]!
189218885Sdim#elif defined(__INTERWORKING__)
190224145Sdim	/* Restore pc into ip.  */
191219077Sdim	mov r2, r5
192219077Sdim	stmfd sp!, {r2, r3, r4}
193219077Sdim#else
194219077Sdim	stmfd sp!, {r3, r4, r5}
195218885Sdim#endif
196218885Sdim	/* Don't bother restoring ip.  */
197218885Sdim	ldmia r0, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp}
198243830Sdim#if defined(__thumb2__)
199243830Sdim	/* Pop the return address off the target stack.  */
200243830Sdim	mov sp, ip
201243830Sdim	pop {pc}
202243830Sdim#elif defined(__INTERWORKING__)
203243830Sdim	/* Pop the three registers we pushed earlier.  */
204243830Sdim	ldmfd sp, {ip, sp, lr}
205243830Sdim	bx ip
206243830Sdim#else
207243830Sdim	ldmfd sp, {sp, lr, pc}
208243830Sdim#endif
209243830Sdim	FUNC_END restore_core_regs
210243830Sdim	UNPREFIX restore_core_regs
211218885Sdim
212221345Sdim/* Load VFP registers d0-d15 from the address in r0.
213218885Sdim   Use this to load from FSTMX format.  */
214218885SdimARM_FUNC_START gnu_Unwind_Restore_VFP
215218885Sdim	/* Use the generic coprocessor form so that gas doesn't complain
216218885Sdim	   on soft-float targets.  */
217218885Sdim	ldc   p11,cr0,[r0],{0x21} /* fldmiax r0, {d0-d15} */
218218885Sdim	RET
219218885Sdim
220221345Sdim/* Store VFP registers d0-d15 to the address in r0.
221218885Sdim   Use this to store in FSTMX format.  */
222218885SdimARM_FUNC_START gnu_Unwind_Save_VFP
223218885Sdim	/* Use the generic coprocessor form so that gas doesn't complain
224218885Sdim	   on soft-float targets.  */
225218885Sdim	stc   p11,cr0,[r0],{0x21} /* fstmiax r0, {d0-d15} */
226218885Sdim	RET
227218885Sdim
228218885Sdim/* Load VFP registers d0-d15 from the address in r0.
229221345Sdim   Use this to load from FSTMD format.  */
230218885SdimARM_FUNC_START gnu_Unwind_Restore_VFP_D
231221345Sdim	ldc   p11,cr0,[r0],{0x20} /* fldmiad r0, {d0-d15} */
232218885Sdim	RET
233243830Sdim
234243830Sdim/* Store VFP registers d0-d15 to the address in r0.
235243830Sdim   Use this to store in FLDMD format.  */
236243830SdimARM_FUNC_START gnu_Unwind_Save_VFP_D
237243830Sdim	stc   p11,cr0,[r0],{0x20} /* fstmiad r0, {d0-d15} */
238243830Sdim	RET
239221345Sdim
240221345Sdim/* Load VFP registers d16-d31 from the address in r0.
241221345Sdim   Use this to load from FSTMD (=VSTM) format.  Needs VFPv3.  */
242218885SdimARM_FUNC_START gnu_Unwind_Restore_VFP_D_16_to_31
243218885Sdim	ldcl  p11,cr0,[r0],{0x20} /* vldm r0, {d16-d31} */
244218885Sdim	RET
245218885Sdim
246218885Sdim/* Store VFP registers d16-d31 to the address in r0.
247243830Sdim   Use this to store in FLDMD (=VLDM) format.  Needs VFPv3.  */
248243830SdimARM_FUNC_START gnu_Unwind_Save_VFP_D_16_to_31
249218885Sdim	stcl  p11,cr0,[r0],{0x20} /* vstm r0, {d16-d31} */
250218885Sdim	RET
251218885Sdim
252218885SdimARM_FUNC_START gnu_Unwind_Restore_WMMXD
253218885Sdim	/* Use the generic coprocessor form so that gas doesn't complain
254218885Sdim	   on non-iWMMXt targets.  */
255221345Sdim	ldcl  p1, cr0, [r0], #8 /* wldrd wr0, [r0], #8 */
256221345Sdim	ldcl  p1, cr1, [r0], #8 /* wldrd wr1, [r0], #8 */
257221345Sdim	ldcl  p1, cr2, [r0], #8 /* wldrd wr2, [r0], #8 */
258221345Sdim	ldcl  p1, cr3, [r0], #8 /* wldrd wr3, [r0], #8 */
259218885Sdim	ldcl  p1, cr4, [r0], #8 /* wldrd wr4, [r0], #8 */
260218885Sdim	ldcl  p1, cr5, [r0], #8 /* wldrd wr5, [r0], #8 */
261221345Sdim	ldcl  p1, cr6, [r0], #8 /* wldrd wr6, [r0], #8 */
262218885Sdim	ldcl  p1, cr7, [r0], #8 /* wldrd wr7, [r0], #8 */
263218885Sdim	ldcl  p1, cr8, [r0], #8 /* wldrd wr8, [r0], #8 */
264218885Sdim	ldcl  p1, cr9, [r0], #8 /* wldrd wr9, [r0], #8 */
265218885Sdim	ldcl  p1, cr10, [r0], #8 /* wldrd wr10, [r0], #8 */
266218885Sdim	ldcl  p1, cr11, [r0], #8 /* wldrd wr11, [r0], #8 */
267218885Sdim	ldcl  p1, cr12, [r0], #8 /* wldrd wr12, [r0], #8 */
268218885Sdim	ldcl  p1, cr13, [r0], #8 /* wldrd wr13, [r0], #8 */
269218885Sdim	ldcl  p1, cr14, [r0], #8 /* wldrd wr14, [r0], #8 */
270218885Sdim	ldcl  p1, cr15, [r0], #8 /* wldrd wr15, [r0], #8 */
271218885Sdim	RET
272218885Sdim
273218885SdimARM_FUNC_START gnu_Unwind_Save_WMMXD
274218885Sdim	/* Use the generic coprocessor form so that gas doesn't complain
275218885Sdim	   on non-iWMMXt targets.  */
276218885Sdim	stcl  p1, cr0, [r0], #8 /* wstrd wr0, [r0], #8 */
277218885Sdim	stcl  p1, cr1, [r0], #8 /* wstrd wr1, [r0], #8 */
278218885Sdim	stcl  p1, cr2, [r0], #8 /* wstrd wr2, [r0], #8 */
279218885Sdim	stcl  p1, cr3, [r0], #8 /* wstrd wr3, [r0], #8 */
280218885Sdim	stcl  p1, cr4, [r0], #8 /* wstrd wr4, [r0], #8 */
281218885Sdim	stcl  p1, cr5, [r0], #8 /* wstrd wr5, [r0], #8 */
282218885Sdim	stcl  p1, cr6, [r0], #8 /* wstrd wr6, [r0], #8 */
283218885Sdim	stcl  p1, cr7, [r0], #8 /* wstrd wr7, [r0], #8 */
284218885Sdim	stcl  p1, cr8, [r0], #8 /* wstrd wr8, [r0], #8 */
285218885Sdim	stcl  p1, cr9, [r0], #8 /* wstrd wr9, [r0], #8 */
286224145Sdim	stcl  p1, cr10, [r0], #8 /* wstrd wr10, [r0], #8 */
287224145Sdim	stcl  p1, cr11, [r0], #8 /* wstrd wr11, [r0], #8 */
288239462Sdim	stcl  p1, cr12, [r0], #8 /* wstrd wr12, [r0], #8 */
289239462Sdim	stcl  p1, cr13, [r0], #8 /* wstrd wr13, [r0], #8 */
290239462Sdim	stcl  p1, cr14, [r0], #8 /* wstrd wr14, [r0], #8 */
291218885Sdim	stcl  p1, cr15, [r0], #8 /* wstrd wr15, [r0], #8 */
292234353Sdim	RET
293218885Sdim
294218885SdimARM_FUNC_START gnu_Unwind_Restore_WMMXC
295218885Sdim	/* Use the generic coprocessor form so that gas doesn't complain
296218885Sdim	   on non-iWMMXt targets.  */
297218885Sdim	ldc2  p1, cr8, [r0], #4 /* wldrw wcgr0, [r0], #4 */
298218885Sdim	ldc2  p1, cr9, [r0], #4 /* wldrw wcgr1, [r0], #4 */
299234353Sdim	ldc2  p1, cr10, [r0], #4 /* wldrw wcgr2, [r0], #4 */
300218885Sdim	ldc2  p1, cr11, [r0], #4 /* wldrw wcgr3, [r0], #4 */
301218885Sdim	RET
302218885Sdim
303218885SdimARM_FUNC_START gnu_Unwind_Save_WMMXC
304218885Sdim	/* Use the generic coprocessor form so that gas doesn't complain
305218885Sdim	   on non-iWMMXt targets.  */
306218885Sdim	stc2  p1, cr8, [r0], #4 /* wstrw wcgr0, [r0], #4 */
307218885Sdim	stc2  p1, cr9, [r0], #4 /* wstrw wcgr1, [r0], #4 */
308218885Sdim	stc2  p1, cr10, [r0], #4 /* wstrw wcgr2, [r0], #4 */
309218885Sdim	stc2  p1, cr11, [r0], #4 /* wstrw wcgr3, [r0], #4 */
310218885Sdim	RET
311218885Sdim
312218885Sdim/* Wrappers to save core registers, then call the real routine.   */
313218885Sdim
314218885Sdim.macro  UNWIND_WRAPPER name nargs
315218885Sdim	ARM_FUNC_START \name
316218885Sdim	/* Create a phase2_vrs structure.  */
317218885Sdim	/* Split reg push in two to ensure the correct value for sp.  */
318218885Sdim#if defined(__thumb2__)
319218885Sdim	mov ip, sp
320218885Sdim	push {lr} /* PC is ignored.  */
321218885Sdim	push {ip, lr} /* Push original SP and LR.  */
322218885Sdim#else
323218885Sdim	stmfd sp!, {sp, lr, pc}
324218885Sdim#endif
325218885Sdim	stmfd sp!, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp, ip}
326218885Sdim
327218885Sdim	/* Demand-save flags, plus an extra word for alignment.  */
328218885Sdim	mov r3, #0
329218885Sdim	stmfd sp!, {r2, r3}
330218885Sdim
331221345Sdim	/* Point r1 at the block.  Pass r[0..nargs) unchanged.  */
332218885Sdim	add r\nargs, sp, #4
333218885Sdim#if defined(__thumb__) && !defined(__thumb2__)
334218885Sdim	/* Switch back to thumb mode to avoid interworking hassle.  */
335218885Sdim	adr ip, .L1_\name
336218885Sdim	orr ip, ip, #1
337218885Sdim	bx ip
338218885Sdim	.thumb
339218885Sdim.L1_\name:
340218885Sdim	bl SYM (__gnu\name) __PLT__
341218885Sdim	ldr r3, [sp, #64]
342218885Sdim	add sp, #72
343224145Sdim	bx r3
344234353Sdim#else
345218885Sdim	bl SYM (__gnu\name) __PLT__
346218885Sdim	ldr lr, [sp, #64]
347218885Sdim	add sp, sp, #72
348218885Sdim	RET
349218885Sdim#endif
350218885Sdim	FUNC_END \name
351224145Sdim	UNPREFIX \name
352218885Sdim.endm
353218885Sdim
354218885Sdim#endif /* __ARM_ARCH_ISA_ARM || __ARM_ARCH_ISA_THUMB != 1 */
355218885Sdim
356218885SdimUNWIND_WRAPPER _Unwind_RaiseException 1
357218885SdimUNWIND_WRAPPER _Unwind_Resume 1
358218885SdimUNWIND_WRAPPER _Unwind_Resume_or_Rethrow 1
359218885SdimUNWIND_WRAPPER _Unwind_ForcedUnwind 3
360218885SdimUNWIND_WRAPPER _Unwind_Backtrace 2
361224145Sdim
362218885Sdim#endif  /* ndef __symbian__ */
363218885Sdim