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