1/* Support functions for the unwinder. 2 Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc. 3 Contributed by Paul Brook 4 5 This file is free software; you can redistribute it and/or modify it 6 under the terms of the GNU General Public License as published by the 7 Free Software Foundation; either version 3, or (at your option) any 8 later version. 9 10 This file is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 General Public License for more details. 14 15 Under Section 7 of GPL version 3, you are granted additional 16 permissions described in the GCC Runtime Library Exception, version 17 3.1, as published by the Free Software Foundation. 18 19 You should have received a copy of the GNU General Public License and 20 a copy of the GCC Runtime Library Exception along with this program; 21 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 22 <http://www.gnu.org/licenses/>. */ 23 24/* An executable stack is *not* required for these functions. */ 25#if defined(__ELF__) && defined(__linux__) 26.section .note.GNU-stack,"",%progbits 27.previous 28#endif 29 30#ifndef __symbian__ 31 32#include "lib1funcs.asm" 33 34.macro UNPREFIX name 35 .global SYM (\name) 36 EQUIV SYM (\name), SYM (__\name) 37.endm 38 39#if (__ARM_ARCH__ == 4) 40/* Some coprocessors require armv5. We know this code will never be run on 41 other cpus. Tell gas to allow armv5, but only mark the objects as armv4. 42 */ 43.arch armv5t 44#ifdef __ARM_ARCH_4T__ 45.object_arch armv4t 46#else 47.object_arch armv4 48#endif 49#endif 50 51#ifdef __ARM_ARCH_6M__ 52 53/* r0 points to a 16-word block. Upload these values to the actual core 54 state. */ 55FUNC_START restore_core_regs 56 mov r1, r0 57 add r1, r1, #52 58 ldmia r1!, {r3, r4, r5} 59 sub r3, r3, #4 60 mov ip, r3 61 str r5, [r3] 62 mov lr, r4 63 /* Restore r8-r11. */ 64 mov r1, r0 65 add r1, r1, #32 66 ldmia r1!, {r2, r3, r4, r5} 67 mov r8, r2 68 mov r9, r3 69 mov sl, r4 70 mov fp, r5 71 mov r1, r0 72 add r1, r1, #8 73 ldmia r1!, {r2, r3, r4, r5, r6, r7} 74 ldr r1, [r0, #4] 75 ldr r0, [r0] 76 mov sp, ip 77 pop {pc} 78 FUNC_END restore_core_regs 79 UNPREFIX restore_core_regs 80 81/* ARMV6M does not have coprocessors, so these should never be used. */ 82FUNC_START gnu_Unwind_Restore_VFP 83 RET 84 85/* Store VFR regsters d0-d15 to the address in r0. */ 86FUNC_START gnu_Unwind_Save_VFP 87 RET 88 89/* Load VFP registers d0-d15 from the address in r0. 90 Use this to load from FSTMD format. */ 91FUNC_START gnu_Unwind_Restore_VFP_D 92 RET 93 94/* Store VFP registers d0-d15 to the address in r0. 95 Use this to store in FLDMD format. */ 96FUNC_START gnu_Unwind_Save_VFP_D 97 RET 98 99/* Load VFP registers d16-d31 from the address in r0. 100 Use this to load from FSTMD (=VSTM) format. Needs VFPv3. */ 101FUNC_START gnu_Unwind_Restore_VFP_D_16_to_31 102 RET 103 104/* Store VFP registers d16-d31 to the address in r0. 105 Use this to store in FLDMD (=VLDM) format. Needs VFPv3. */ 106FUNC_START gnu_Unwind_Save_VFP_D_16_to_31 107 RET 108 109FUNC_START gnu_Unwind_Restore_WMMXD 110 RET 111 112FUNC_START gnu_Unwind_Save_WMMXD 113 RET 114 115FUNC_START gnu_Unwind_Restore_WMMXC 116 RET 117 118FUNC_START gnu_Unwind_Save_WMMXC 119 RET 120 121.macro UNWIND_WRAPPER name nargs 122 FUNC_START \name 123 /* Create a phase2_vrs structure. */ 124 /* Save r0 in the PC slot so we can use it as a scratch register. */ 125 push {r0} 126 add r0, sp, #4 127 push {r0, lr} /* Push original SP and LR. */ 128 /* Make space for r8-r12. */ 129 sub sp, sp, #20 130 /* Save low registers. */ 131 push {r0, r1, r2, r3, r4, r5, r6, r7} 132 /* Save high registers. */ 133 add r0, sp, #32 134 mov r1, r8 135 mov r2, r9 136 mov r3, sl 137 mov r4, fp 138 mov r5, ip 139 stmia r0!, {r1, r2, r3, r4, r5} 140 /* Restore original low register values. */ 141 add r0, sp, #4 142 ldmia r0!, {r1, r2, r3, r4, r5} 143 /* Restore orginial r0. */ 144 ldr r0, [sp, #60] 145 str r0, [sp] 146 /* Demand-save flags, plus an extra word for alignment. */ 147 mov r3, #0 148 push {r2, r3} 149 /* Point r1 at the block. Pass r[0..nargs) unchanged. */ 150 add r\nargs, sp, #4 151 152 bl SYM (__gnu\name) 153 154 ldr r3, [sp, #64] 155 add sp, sp, #72 156 bx r3 157 158 FUNC_END \name 159 UNPREFIX \name 160.endm 161 162#else /* !__ARM_ARCH_6M__ */ 163 164/* r0 points to a 16-word block. Upload these values to the actual core 165 state. */ 166ARM_FUNC_START restore_core_regs 167 /* We must use sp as the base register when restoring sp. Push the 168 last 3 registers onto the top of the current stack to achieve 169 this. */ 170 add r1, r0, #52 171 ldmia r1, {r3, r4, r5} /* {sp, lr, pc}. */ 172#if defined(__thumb2__) 173 /* Thumb-2 doesn't allow sp in a load-multiple instruction, so push 174 the target address onto the target stack. This is safe as 175 we're always returning to somewhere further up the call stack. */ 176 mov ip, r3 177 mov lr, r4 178 str r5, [ip, #-4]! 179#elif defined(__INTERWORKING__) 180 /* Restore pc into ip. */ 181 mov r2, r5 182 stmfd sp!, {r2, r3, r4} 183#else 184 stmfd sp!, {r3, r4, r5} 185#endif 186 /* Don't bother restoring ip. */ 187 ldmia r0, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp} 188#if defined(__thumb2__) 189 /* Pop the return address off the target stack. */ 190 mov sp, ip 191 pop {pc} 192#elif defined(__INTERWORKING__) 193 /* Pop the three registers we pushed earlier. */ 194 ldmfd sp, {ip, sp, lr} 195 bx ip 196#else 197 ldmfd sp, {sp, lr, pc} 198#endif 199 FUNC_END restore_core_regs 200 UNPREFIX restore_core_regs 201 202/* Load VFP registers d0-d15 from the address in r0. 203 Use this to load from FSTMX format. */ 204ARM_FUNC_START gnu_Unwind_Restore_VFP 205 /* Use the generic coprocessor form so that gas doesn't complain 206 on soft-float targets. */ 207 ldc p11,cr0,[r0],{0x21} /* fldmiax r0, {d0-d15} */ 208 RET 209 210/* Store VFP registers d0-d15 to the address in r0. 211 Use this to store in FSTMX format. */ 212ARM_FUNC_START gnu_Unwind_Save_VFP 213 /* Use the generic coprocessor form so that gas doesn't complain 214 on soft-float targets. */ 215 stc p11,cr0,[r0],{0x21} /* fstmiax r0, {d0-d15} */ 216 RET 217 218/* Load VFP registers d0-d15 from the address in r0. 219 Use this to load from FSTMD format. */ 220ARM_FUNC_START gnu_Unwind_Restore_VFP_D 221 ldc p11,cr0,[r0],{0x20} /* fldmiad r0, {d0-d15} */ 222 RET 223 224/* Store VFP registers d0-d15 to the address in r0. 225 Use this to store in FLDMD format. */ 226ARM_FUNC_START gnu_Unwind_Save_VFP_D 227 stc p11,cr0,[r0],{0x20} /* fstmiad r0, {d0-d15} */ 228 RET 229 230/* Load VFP registers d16-d31 from the address in r0. 231 Use this to load from FSTMD (=VSTM) format. Needs VFPv3. */ 232ARM_FUNC_START gnu_Unwind_Restore_VFP_D_16_to_31 233 ldcl p11,cr0,[r0],{0x20} /* vldm r0, {d16-d31} */ 234 RET 235 236/* Store VFP registers d16-d31 to the address in r0. 237 Use this to store in FLDMD (=VLDM) format. Needs VFPv3. */ 238ARM_FUNC_START gnu_Unwind_Save_VFP_D_16_to_31 239 stcl p11,cr0,[r0],{0x20} /* vstm r0, {d16-d31} */ 240 RET 241 242ARM_FUNC_START gnu_Unwind_Restore_WMMXD 243 /* Use the generic coprocessor form so that gas doesn't complain 244 on non-iWMMXt targets. */ 245 ldcl p1, cr0, [r0], #8 /* wldrd wr0, [r0], #8 */ 246 ldcl p1, cr1, [r0], #8 /* wldrd wr1, [r0], #8 */ 247 ldcl p1, cr2, [r0], #8 /* wldrd wr2, [r0], #8 */ 248 ldcl p1, cr3, [r0], #8 /* wldrd wr3, [r0], #8 */ 249 ldcl p1, cr4, [r0], #8 /* wldrd wr4, [r0], #8 */ 250 ldcl p1, cr5, [r0], #8 /* wldrd wr5, [r0], #8 */ 251 ldcl p1, cr6, [r0], #8 /* wldrd wr6, [r0], #8 */ 252 ldcl p1, cr7, [r0], #8 /* wldrd wr7, [r0], #8 */ 253 ldcl p1, cr8, [r0], #8 /* wldrd wr8, [r0], #8 */ 254 ldcl p1, cr9, [r0], #8 /* wldrd wr9, [r0], #8 */ 255 ldcl p1, cr10, [r0], #8 /* wldrd wr10, [r0], #8 */ 256 ldcl p1, cr11, [r0], #8 /* wldrd wr11, [r0], #8 */ 257 ldcl p1, cr12, [r0], #8 /* wldrd wr12, [r0], #8 */ 258 ldcl p1, cr13, [r0], #8 /* wldrd wr13, [r0], #8 */ 259 ldcl p1, cr14, [r0], #8 /* wldrd wr14, [r0], #8 */ 260 ldcl p1, cr15, [r0], #8 /* wldrd wr15, [r0], #8 */ 261 RET 262 263ARM_FUNC_START gnu_Unwind_Save_WMMXD 264 /* Use the generic coprocessor form so that gas doesn't complain 265 on non-iWMMXt targets. */ 266 stcl p1, cr0, [r0], #8 /* wstrd wr0, [r0], #8 */ 267 stcl p1, cr1, [r0], #8 /* wstrd wr1, [r0], #8 */ 268 stcl p1, cr2, [r0], #8 /* wstrd wr2, [r0], #8 */ 269 stcl p1, cr3, [r0], #8 /* wstrd wr3, [r0], #8 */ 270 stcl p1, cr4, [r0], #8 /* wstrd wr4, [r0], #8 */ 271 stcl p1, cr5, [r0], #8 /* wstrd wr5, [r0], #8 */ 272 stcl p1, cr6, [r0], #8 /* wstrd wr6, [r0], #8 */ 273 stcl p1, cr7, [r0], #8 /* wstrd wr7, [r0], #8 */ 274 stcl p1, cr8, [r0], #8 /* wstrd wr8, [r0], #8 */ 275 stcl p1, cr9, [r0], #8 /* wstrd wr9, [r0], #8 */ 276 stcl p1, cr10, [r0], #8 /* wstrd wr10, [r0], #8 */ 277 stcl p1, cr11, [r0], #8 /* wstrd wr11, [r0], #8 */ 278 stcl p1, cr12, [r0], #8 /* wstrd wr12, [r0], #8 */ 279 stcl p1, cr13, [r0], #8 /* wstrd wr13, [r0], #8 */ 280 stcl p1, cr14, [r0], #8 /* wstrd wr14, [r0], #8 */ 281 stcl p1, cr15, [r0], #8 /* wstrd wr15, [r0], #8 */ 282 RET 283 284ARM_FUNC_START gnu_Unwind_Restore_WMMXC 285 /* Use the generic coprocessor form so that gas doesn't complain 286 on non-iWMMXt targets. */ 287 ldc2 p1, cr8, [r0], #4 /* wldrw wcgr0, [r0], #4 */ 288 ldc2 p1, cr9, [r0], #4 /* wldrw wcgr1, [r0], #4 */ 289 ldc2 p1, cr10, [r0], #4 /* wldrw wcgr2, [r0], #4 */ 290 ldc2 p1, cr11, [r0], #4 /* wldrw wcgr3, [r0], #4 */ 291 RET 292 293ARM_FUNC_START gnu_Unwind_Save_WMMXC 294 /* Use the generic coprocessor form so that gas doesn't complain 295 on non-iWMMXt targets. */ 296 stc2 p1, cr8, [r0], #4 /* wstrw wcgr0, [r0], #4 */ 297 stc2 p1, cr9, [r0], #4 /* wstrw wcgr1, [r0], #4 */ 298 stc2 p1, cr10, [r0], #4 /* wstrw wcgr2, [r0], #4 */ 299 stc2 p1, cr11, [r0], #4 /* wstrw wcgr3, [r0], #4 */ 300 RET 301 302/* Wrappers to save core registers, then call the real routine. */ 303 304.macro UNWIND_WRAPPER name nargs 305 ARM_FUNC_START \name 306 /* Create a phase2_vrs structure. */ 307 /* Split reg push in two to ensure the correct value for sp. */ 308#if defined(__thumb2__) 309 mov ip, sp 310 push {lr} /* PC is ignored. */ 311 push {ip, lr} /* Push original SP and LR. */ 312#else 313 stmfd sp!, {sp, lr, pc} 314#endif 315 stmfd sp!, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp, ip} 316 317 /* Demand-save flags, plus an extra word for alignment. */ 318 mov r3, #0 319 stmfd sp!, {r2, r3} 320 321 /* Point r1 at the block. Pass r[0..nargs) unchanged. */ 322 add r\nargs, sp, #4 323#if defined(__thumb__) && !defined(__thumb2__) 324 /* Switch back to thumb mode to avoid interworking hassle. */ 325 adr ip, .L1_\name 326 orr ip, ip, #1 327 bx ip 328 .thumb 329.L1_\name: 330 bl SYM (__gnu\name) __PLT__ 331 ldr r3, [sp, #64] 332 add sp, #72 333 bx r3 334#else 335 bl SYM (__gnu\name) __PLT__ 336 ldr lr, [sp, #64] 337 add sp, sp, #72 338 RET 339#endif 340 FUNC_END \name 341 UNPREFIX \name 342.endm 343 344#endif /* !__ARM_ARCH_6M__ */ 345 346UNWIND_WRAPPER _Unwind_RaiseException 1 347UNWIND_WRAPPER _Unwind_Resume 1 348UNWIND_WRAPPER _Unwind_Resume_or_Rethrow 1 349UNWIND_WRAPPER _Unwind_ForcedUnwind 3 350UNWIND_WRAPPER _Unwind_Backtrace 2 351 352#endif /* ndef __symbian__ */ 353