1//===-------------------- UnwindRegistersRestore.S ------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is dual licensed under the MIT and the University of Illinois Open 6// Source Licenses. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9 10#include "assembly.h" 11 12 .text 13 14#if !defined(__USING_SJLJ_EXCEPTIONS__) 15 16#if defined(__i386__) 17DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_x866jumptoEv) 18# 19# void libunwind::Registers_x86::jumpto() 20# 21#if defined(_WIN32) 22# On windows, the 'this' pointer is passed in ecx instead of on the stack 23 movl %ecx, %eax 24#else 25# On entry: 26# + + 27# +-----------------------+ 28# + thread_state pointer + 29# +-----------------------+ 30# + return address + 31# +-----------------------+ <-- SP 32# + + 33 movl 4(%esp), %eax 34#endif 35 # set up eax and ret on new stack location 36 movl 28(%eax), %edx # edx holds new stack pointer 37 subl $8,%edx 38 movl %edx, 28(%eax) 39 movl 0(%eax), %ebx 40 movl %ebx, 0(%edx) 41 movl 40(%eax), %ebx 42 movl %ebx, 4(%edx) 43 # we now have ret and eax pushed onto where new stack will be 44 # restore all registers 45 movl 4(%eax), %ebx 46 movl 8(%eax), %ecx 47 movl 12(%eax), %edx 48 movl 16(%eax), %edi 49 movl 20(%eax), %esi 50 movl 24(%eax), %ebp 51 movl 28(%eax), %esp 52 # skip ss 53 # skip eflags 54 pop %eax # eax was already pushed on new stack 55 ret # eip was already pushed on new stack 56 # skip cs 57 # skip ds 58 # skip es 59 # skip fs 60 # skip gs 61 62#elif defined(__x86_64__) 63 64DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind16Registers_x86_646jumptoEv) 65# 66# void libunwind::Registers_x86_64::jumpto() 67# 68# On entry, thread_state pointer is in rdi 69 70 movq 56(%rdi), %rax # rax holds new stack pointer 71 subq $16, %rax 72 movq %rax, 56(%rdi) 73 movq 32(%rdi), %rbx # store new rdi on new stack 74 movq %rbx, 0(%rax) 75 movq 128(%rdi), %rbx # store new rip on new stack 76 movq %rbx, 8(%rax) 77 # restore all registers 78 movq 0(%rdi), %rax 79 movq 8(%rdi), %rbx 80 movq 16(%rdi), %rcx 81 movq 24(%rdi), %rdx 82 # restore rdi later 83 movq 40(%rdi), %rsi 84 movq 48(%rdi), %rbp 85 # restore rsp later 86 movq 64(%rdi), %r8 87 movq 72(%rdi), %r9 88 movq 80(%rdi), %r10 89 movq 88(%rdi), %r11 90 movq 96(%rdi), %r12 91 movq 104(%rdi), %r13 92 movq 112(%rdi), %r14 93 movq 120(%rdi), %r15 94 # skip rflags 95 # skip cs 96 # skip fs 97 # skip gs 98 movq 56(%rdi), %rsp # cut back rsp to new location 99 pop %rdi # rdi was saved here earlier 100 ret # rip was saved here 101 102 103#elif defined(__ppc__) 104 105DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_ppc6jumptoEv) 106; 107; void libunwind::Registers_ppc::jumpto() 108; 109; On entry: 110; thread_state pointer is in r3 111; 112 113 ; restore integral registerrs 114 ; skip r0 for now 115 ; skip r1 for now 116 lwz r2, 16(r3) 117 ; skip r3 for now 118 ; skip r4 for now 119 ; skip r5 for now 120 lwz r6, 32(r3) 121 lwz r7, 36(r3) 122 lwz r8, 40(r3) 123 lwz r9, 44(r3) 124 lwz r10, 48(r3) 125 lwz r11, 52(r3) 126 lwz r12, 56(r3) 127 lwz r13, 60(r3) 128 lwz r14, 64(r3) 129 lwz r15, 68(r3) 130 lwz r16, 72(r3) 131 lwz r17, 76(r3) 132 lwz r18, 80(r3) 133 lwz r19, 84(r3) 134 lwz r20, 88(r3) 135 lwz r21, 92(r3) 136 lwz r22, 96(r3) 137 lwz r23,100(r3) 138 lwz r24,104(r3) 139 lwz r25,108(r3) 140 lwz r26,112(r3) 141 lwz r27,116(r3) 142 lwz r28,120(r3) 143 lwz r29,124(r3) 144 lwz r30,128(r3) 145 lwz r31,132(r3) 146 147 ; restore float registers 148 lfd f0, 160(r3) 149 lfd f1, 168(r3) 150 lfd f2, 176(r3) 151 lfd f3, 184(r3) 152 lfd f4, 192(r3) 153 lfd f5, 200(r3) 154 lfd f6, 208(r3) 155 lfd f7, 216(r3) 156 lfd f8, 224(r3) 157 lfd f9, 232(r3) 158 lfd f10,240(r3) 159 lfd f11,248(r3) 160 lfd f12,256(r3) 161 lfd f13,264(r3) 162 lfd f14,272(r3) 163 lfd f15,280(r3) 164 lfd f16,288(r3) 165 lfd f17,296(r3) 166 lfd f18,304(r3) 167 lfd f19,312(r3) 168 lfd f20,320(r3) 169 lfd f21,328(r3) 170 lfd f22,336(r3) 171 lfd f23,344(r3) 172 lfd f24,352(r3) 173 lfd f25,360(r3) 174 lfd f26,368(r3) 175 lfd f27,376(r3) 176 lfd f28,384(r3) 177 lfd f29,392(r3) 178 lfd f30,400(r3) 179 lfd f31,408(r3) 180 181 ; restore vector registers if any are in use 182 lwz r5,156(r3) ; test VRsave 183 cmpwi r5,0 184 beq Lnovec 185 186 subi r4,r1,16 187 rlwinm r4,r4,0,0,27 ; mask low 4-bits 188 ; r4 is now a 16-byte aligned pointer into the red zone 189 ; the _vectorRegisters may not be 16-byte aligned so copy via red zone temp buffer 190 191 192#define LOAD_VECTOR_UNALIGNEDl(_index) \ 193 andis. r0,r5,(1<<(15-_index)) @\ 194 beq Ldone ## _index @\ 195 lwz r0, 424+_index*16(r3) @\ 196 stw r0, 0(r4) @\ 197 lwz r0, 424+_index*16+4(r3) @\ 198 stw r0, 4(r4) @\ 199 lwz r0, 424+_index*16+8(r3) @\ 200 stw r0, 8(r4) @\ 201 lwz r0, 424+_index*16+12(r3)@\ 202 stw r0, 12(r4) @\ 203 lvx v ## _index,0,r4 @\ 204Ldone ## _index: 205 206#define LOAD_VECTOR_UNALIGNEDh(_index) \ 207 andi. r0,r5,(1<<(31-_index)) @\ 208 beq Ldone ## _index @\ 209 lwz r0, 424+_index*16(r3) @\ 210 stw r0, 0(r4) @\ 211 lwz r0, 424+_index*16+4(r3) @\ 212 stw r0, 4(r4) @\ 213 lwz r0, 424+_index*16+8(r3) @\ 214 stw r0, 8(r4) @\ 215 lwz r0, 424+_index*16+12(r3)@\ 216 stw r0, 12(r4) @\ 217 lvx v ## _index,0,r4 @\ 218 Ldone ## _index: 219 220 221 LOAD_VECTOR_UNALIGNEDl(0) 222 LOAD_VECTOR_UNALIGNEDl(1) 223 LOAD_VECTOR_UNALIGNEDl(2) 224 LOAD_VECTOR_UNALIGNEDl(3) 225 LOAD_VECTOR_UNALIGNEDl(4) 226 LOAD_VECTOR_UNALIGNEDl(5) 227 LOAD_VECTOR_UNALIGNEDl(6) 228 LOAD_VECTOR_UNALIGNEDl(7) 229 LOAD_VECTOR_UNALIGNEDl(8) 230 LOAD_VECTOR_UNALIGNEDl(9) 231 LOAD_VECTOR_UNALIGNEDl(10) 232 LOAD_VECTOR_UNALIGNEDl(11) 233 LOAD_VECTOR_UNALIGNEDl(12) 234 LOAD_VECTOR_UNALIGNEDl(13) 235 LOAD_VECTOR_UNALIGNEDl(14) 236 LOAD_VECTOR_UNALIGNEDl(15) 237 LOAD_VECTOR_UNALIGNEDh(16) 238 LOAD_VECTOR_UNALIGNEDh(17) 239 LOAD_VECTOR_UNALIGNEDh(18) 240 LOAD_VECTOR_UNALIGNEDh(19) 241 LOAD_VECTOR_UNALIGNEDh(20) 242 LOAD_VECTOR_UNALIGNEDh(21) 243 LOAD_VECTOR_UNALIGNEDh(22) 244 LOAD_VECTOR_UNALIGNEDh(23) 245 LOAD_VECTOR_UNALIGNEDh(24) 246 LOAD_VECTOR_UNALIGNEDh(25) 247 LOAD_VECTOR_UNALIGNEDh(26) 248 LOAD_VECTOR_UNALIGNEDh(27) 249 LOAD_VECTOR_UNALIGNEDh(28) 250 LOAD_VECTOR_UNALIGNEDh(29) 251 LOAD_VECTOR_UNALIGNEDh(30) 252 LOAD_VECTOR_UNALIGNEDh(31) 253 254Lnovec: 255 lwz r0, 136(r3) ; __cr 256 mtocrf 255,r0 257 lwz r0, 148(r3) ; __ctr 258 mtctr r0 259 lwz r0, 0(r3) ; __ssr0 260 mtctr r0 261 lwz r0, 8(r3) ; do r0 now 262 lwz r5,28(r3) ; do r5 now 263 lwz r4,24(r3) ; do r4 now 264 lwz r1,12(r3) ; do sp now 265 lwz r3,20(r3) ; do r3 last 266 bctr 267 268#elif defined(__arm64__) || defined(__aarch64__) 269 270// 271// void libunwind::Registers_arm64::jumpto() 272// 273// On entry: 274// thread_state pointer is in x0 275// 276 .p2align 2 277DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind15Registers_arm646jumptoEv) 278 // skip restore of x0,x1 for now 279 ldp x2, x3, [x0, #0x010] 280 ldp x4, x5, [x0, #0x020] 281 ldp x6, x7, [x0, #0x030] 282 ldp x8, x9, [x0, #0x040] 283 ldp x10,x11, [x0, #0x050] 284 ldp x12,x13, [x0, #0x060] 285 ldp x14,x15, [x0, #0x070] 286 ldp x16,x17, [x0, #0x080] 287 ldp x18,x19, [x0, #0x090] 288 ldp x20,x21, [x0, #0x0A0] 289 ldp x22,x23, [x0, #0x0B0] 290 ldp x24,x25, [x0, #0x0C0] 291 ldp x26,x27, [x0, #0x0D0] 292 ldp x28,x29, [x0, #0x0E0] 293 ldr x30, [x0, #0x100] // restore pc into lr 294 ldr x1, [x0, #0x0F8] 295 mov sp,x1 // restore sp 296 297 ldp d0, d1, [x0, #0x110] 298 ldp d2, d3, [x0, #0x120] 299 ldp d4, d5, [x0, #0x130] 300 ldp d6, d7, [x0, #0x140] 301 ldp d8, d9, [x0, #0x150] 302 ldp d10,d11, [x0, #0x160] 303 ldp d12,d13, [x0, #0x170] 304 ldp d14,d15, [x0, #0x180] 305 ldp d16,d17, [x0, #0x190] 306 ldp d18,d19, [x0, #0x1A0] 307 ldp d20,d21, [x0, #0x1B0] 308 ldp d22,d23, [x0, #0x1C0] 309 ldp d24,d25, [x0, #0x1D0] 310 ldp d26,d27, [x0, #0x1E0] 311 ldp d28,d29, [x0, #0x1F0] 312 ldr d30, [x0, #0x200] 313 ldr d31, [x0, #0x208] 314 315 ldp x0, x1, [x0, #0x000] // restore x0,x1 316 ret x30 // jump to pc 317 318#elif defined(__arm__) && !defined(__APPLE__) 319 320#if !defined(__ARM_ARCH_ISA_ARM) 321 .thumb 322#endif 323 324@ 325@ void libunwind::Registers_arm::restoreCoreAndJumpTo() 326@ 327@ On entry: 328@ thread_state pointer is in r0 329@ 330 .p2align 2 331DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm20restoreCoreAndJumpToEv) 332#if !defined(__ARM_ARCH_ISA_ARM) && __ARM_ARCH_ISA_THUMB == 1 333 @ r8-r11: ldm into r1-r4, then mov to r8-r11 334 adds r0, #0x20 335 ldm r0!, {r1-r4} 336 subs r0, #0x30 337 mov r8, r1 338 mov r9, r2 339 mov r10, r3 340 mov r11, r4 341 @ r12 does not need loading, it it the intra-procedure-call scratch register 342 ldr r2, [r0, #0x34] 343 ldr r3, [r0, #0x3c] 344 mov sp, r2 345 mov lr, r3 @ restore pc into lr 346 ldm r0, {r0-r7} 347#else 348 @ Use lr as base so that r0 can be restored. 349 mov lr, r0 350 @ 32bit thumb-2 restrictions for ldm: 351 @ . the sp (r13) cannot be in the list 352 @ . the pc (r15) and lr (r14) cannot both be in the list in an LDM instruction 353 ldm lr, {r0-r12} 354 ldr sp, [lr, #52] 355 ldr lr, [lr, #60] @ restore pc into lr 356#endif 357 JMP(lr) 358 359@ 360@ static void libunwind::Registers_arm::restoreVFPWithFLDMD(unw_fpreg_t* values) 361@ 362@ On entry: 363@ values pointer is in r0 364@ 365 .p2align 2 366 .fpu vfpv3-d16 367DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFLDMDEPy) 368 @ VFP and iwMMX instructions are only available when compiling with the flags 369 @ that enable them. We do not want to do that in the library (because we do not 370 @ want the compiler to generate instructions that access those) but this is 371 @ only accessed if the personality routine needs these registers. Use of 372 @ these registers implies they are, actually, available on the target, so 373 @ it's ok to execute. 374 @ So, generate the instruction using the corresponding coprocessor mnemonic. 375 vldmia r0, {d0-d15} 376 JMP(lr) 377 378@ 379@ static void libunwind::Registers_arm::restoreVFPWithFLDMX(unw_fpreg_t* values) 380@ 381@ On entry: 382@ values pointer is in r0 383@ 384 .p2align 2 385 .fpu vfpv3-d16 386DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFLDMXEPy) 387 vldmia r0, {d0-d15} @ fldmiax is deprecated in ARMv7+ and now behaves like vldmia 388 JMP(lr) 389 390@ 391@ static void libunwind::Registers_arm::restoreVFPv3(unw_fpreg_t* values) 392@ 393@ On entry: 394@ values pointer is in r0 395@ 396 .p2align 2 397 .fpu vfpv3 398DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm12restoreVFPv3EPy) 399 vldmia r0, {d16-d31} 400 JMP(lr) 401 402#if defined(__ARM_WMMX) 403 404@ 405@ static void libunwind::Registers_arm::restoreiWMMX(unw_fpreg_t* values) 406@ 407@ On entry: 408@ values pointer is in r0 409@ 410 .p2align 2 411 .arch armv5te 412DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm12restoreiWMMXEPy) 413 ldcl p1, cr0, [r0], #8 @ wldrd wR0, [r0], #8 414 ldcl p1, cr1, [r0], #8 @ wldrd wR1, [r0], #8 415 ldcl p1, cr2, [r0], #8 @ wldrd wR2, [r0], #8 416 ldcl p1, cr3, [r0], #8 @ wldrd wR3, [r0], #8 417 ldcl p1, cr4, [r0], #8 @ wldrd wR4, [r0], #8 418 ldcl p1, cr5, [r0], #8 @ wldrd wR5, [r0], #8 419 ldcl p1, cr6, [r0], #8 @ wldrd wR6, [r0], #8 420 ldcl p1, cr7, [r0], #8 @ wldrd wR7, [r0], #8 421 ldcl p1, cr8, [r0], #8 @ wldrd wR8, [r0], #8 422 ldcl p1, cr9, [r0], #8 @ wldrd wR9, [r0], #8 423 ldcl p1, cr10, [r0], #8 @ wldrd wR10, [r0], #8 424 ldcl p1, cr11, [r0], #8 @ wldrd wR11, [r0], #8 425 ldcl p1, cr12, [r0], #8 @ wldrd wR12, [r0], #8 426 ldcl p1, cr13, [r0], #8 @ wldrd wR13, [r0], #8 427 ldcl p1, cr14, [r0], #8 @ wldrd wR14, [r0], #8 428 ldcl p1, cr15, [r0], #8 @ wldrd wR15, [r0], #8 429 JMP(lr) 430 431@ 432@ static void libunwind::Registers_arm::restoreiWMMXControl(unw_uint32_t* values) 433@ 434@ On entry: 435@ values pointer is in r0 436@ 437 .p2align 2 438 .arch armv5te 439DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreiWMMXControlEPj) 440 ldc2 p1, cr8, [r0], #4 @ wldrw wCGR0, [r0], #4 441 ldc2 p1, cr9, [r0], #4 @ wldrw wCGR1, [r0], #4 442 ldc2 p1, cr10, [r0], #4 @ wldrw wCGR2, [r0], #4 443 ldc2 p1, cr11, [r0], #4 @ wldrw wCGR3, [r0], #4 444 JMP(lr) 445 446#endif 447 448#elif defined(__or1k__) 449 450DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv) 451# 452# void libunwind::Registers_or1k::jumpto() 453# 454# On entry: 455# thread_state pointer is in r3 456# 457 458 # restore integral registerrs 459 l.lwz r0, 0(r3) 460 l.lwz r1, 4(r3) 461 l.lwz r2, 8(r3) 462 # skip r3 for now 463 l.lwz r4, 16(r3) 464 l.lwz r5, 20(r3) 465 l.lwz r6, 24(r3) 466 l.lwz r7, 28(r3) 467 l.lwz r8, 32(r3) 468 l.lwz r9, 36(r3) 469 l.lwz r10, 40(r3) 470 l.lwz r11, 44(r3) 471 l.lwz r12, 48(r3) 472 l.lwz r13, 52(r3) 473 l.lwz r14, 56(r3) 474 l.lwz r15, 60(r3) 475 l.lwz r16, 64(r3) 476 l.lwz r17, 68(r3) 477 l.lwz r18, 72(r3) 478 l.lwz r19, 76(r3) 479 l.lwz r20, 80(r3) 480 l.lwz r21, 84(r3) 481 l.lwz r22, 88(r3) 482 l.lwz r23, 92(r3) 483 l.lwz r24, 96(r3) 484 l.lwz r25,100(r3) 485 l.lwz r26,104(r3) 486 l.lwz r27,108(r3) 487 l.lwz r28,112(r3) 488 l.lwz r29,116(r3) 489 l.lwz r30,120(r3) 490 l.lwz r31,124(r3) 491 492 # at last, restore r3 493 l.lwz r3, 12(r3) 494 495 # jump to pc 496 l.jr r9 497 l.nop 498 499#endif 500 501#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */ 502 503NO_EXEC_STACK_DIRECTIVE 504 505