1//===------------------------ UnwindRegistersSave.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__) 17 18# 19# extern int unw_getcontext(unw_context_t* thread_state) 20# 21# On entry: 22# + + 23# +-----------------------+ 24# + thread_state pointer + 25# +-----------------------+ 26# + return address + 27# +-----------------------+ <-- SP 28# + + 29# 30DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) 31 push %eax 32 movl 8(%esp), %eax 33 movl %ebx, 4(%eax) 34 movl %ecx, 8(%eax) 35 movl %edx, 12(%eax) 36 movl %edi, 16(%eax) 37 movl %esi, 20(%eax) 38 movl %ebp, 24(%eax) 39 movl %esp, %edx 40 addl $8, %edx 41 movl %edx, 28(%eax) # store what sp was at call site as esp 42 # skip ss 43 # skip eflags 44 movl 4(%esp), %edx 45 movl %edx, 40(%eax) # store return address as eip 46 # skip cs 47 # skip ds 48 # skip es 49 # skip fs 50 # skip gs 51 movl (%esp), %edx 52 movl %edx, (%eax) # store original eax 53 popl %eax 54 xorl %eax, %eax # return UNW_ESUCCESS 55 ret 56 57#elif defined(__x86_64__) 58 59# 60# extern int unw_getcontext(unw_context_t* thread_state) 61# 62# On entry: 63# thread_state pointer is in rdi 64# 65DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) 66#if defined(_WIN64) 67#define PTR %rcx 68#define TMP %rdx 69#else 70#define PTR %rdi 71#define TMP %rsi 72#endif 73 74 movq %rax, (PTR) 75 movq %rbx, 8(PTR) 76 movq %rcx, 16(PTR) 77 movq %rdx, 24(PTR) 78 movq %rdi, 32(PTR) 79 movq %rsi, 40(PTR) 80 movq %rbp, 48(PTR) 81 movq %rsp, 56(PTR) 82 addq $8, 56(PTR) 83 movq %r8, 64(PTR) 84 movq %r9, 72(PTR) 85 movq %r10, 80(PTR) 86 movq %r11, 88(PTR) 87 movq %r12, 96(PTR) 88 movq %r13,104(PTR) 89 movq %r14,112(PTR) 90 movq %r15,120(PTR) 91 movq (%rsp),TMP 92 movq TMP,128(PTR) # store return address as rip 93 # skip rflags 94 # skip cs 95 # skip fs 96 # skip gs 97 98#if defined(_WIN64) 99 movdqu %xmm0,176(PTR) 100 movdqu %xmm1,192(PTR) 101 movdqu %xmm2,208(PTR) 102 movdqu %xmm3,224(PTR) 103 movdqu %xmm4,240(PTR) 104 movdqu %xmm5,256(PTR) 105 movdqu %xmm6,272(PTR) 106 movdqu %xmm7,288(PTR) 107 movdqu %xmm8,304(PTR) 108 movdqu %xmm9,320(PTR) 109 movdqu %xmm10,336(PTR) 110 movdqu %xmm11,352(PTR) 111 movdqu %xmm12,368(PTR) 112 movdqu %xmm13,384(PTR) 113 movdqu %xmm14,400(PTR) 114 movdqu %xmm15,416(PTR) 115#endif 116 xorl %eax, %eax # return UNW_ESUCCESS 117 ret 118 119# elif defined(__mips__) 120 121# 122# extern int unw_getcontext(unw_context_t* thread_state) 123# 124# Just trap for the time being. 125DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) 126 teq $0, $0 127 128#elif defined(__ppc__) 129 130; 131; extern int unw_getcontext(unw_context_t* thread_state) 132; 133; On entry: 134; thread_state pointer is in r3 135; 136DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) 137 stw r0, 8(r3) 138 mflr r0 139 stw r0, 0(r3) ; store lr as ssr0 140 stw r1, 12(r3) 141 stw r2, 16(r3) 142 stw r3, 20(r3) 143 stw r4, 24(r3) 144 stw r5, 28(r3) 145 stw r6, 32(r3) 146 stw r7, 36(r3) 147 stw r8, 40(r3) 148 stw r9, 44(r3) 149 stw r10, 48(r3) 150 stw r11, 52(r3) 151 stw r12, 56(r3) 152 stw r13, 60(r3) 153 stw r14, 64(r3) 154 stw r15, 68(r3) 155 stw r16, 72(r3) 156 stw r17, 76(r3) 157 stw r18, 80(r3) 158 stw r19, 84(r3) 159 stw r20, 88(r3) 160 stw r21, 92(r3) 161 stw r22, 96(r3) 162 stw r23,100(r3) 163 stw r24,104(r3) 164 stw r25,108(r3) 165 stw r26,112(r3) 166 stw r27,116(r3) 167 stw r28,120(r3) 168 stw r29,124(r3) 169 stw r30,128(r3) 170 stw r31,132(r3) 171 172 ; save VRSave register 173 mfspr r0,256 174 stw r0,156(r3) 175 ; save CR registers 176 mfcr r0 177 stw r0,136(r3) 178 ; save CTR register 179 mfctr r0 180 stw r0,148(r3) 181 182 ; save float registers 183 stfd f0, 160(r3) 184 stfd f1, 168(r3) 185 stfd f2, 176(r3) 186 stfd f3, 184(r3) 187 stfd f4, 192(r3) 188 stfd f5, 200(r3) 189 stfd f6, 208(r3) 190 stfd f7, 216(r3) 191 stfd f8, 224(r3) 192 stfd f9, 232(r3) 193 stfd f10,240(r3) 194 stfd f11,248(r3) 195 stfd f12,256(r3) 196 stfd f13,264(r3) 197 stfd f14,272(r3) 198 stfd f15,280(r3) 199 stfd f16,288(r3) 200 stfd f17,296(r3) 201 stfd f18,304(r3) 202 stfd f19,312(r3) 203 stfd f20,320(r3) 204 stfd f21,328(r3) 205 stfd f22,336(r3) 206 stfd f23,344(r3) 207 stfd f24,352(r3) 208 stfd f25,360(r3) 209 stfd f26,368(r3) 210 stfd f27,376(r3) 211 stfd f28,384(r3) 212 stfd f29,392(r3) 213 stfd f30,400(r3) 214 stfd f31,408(r3) 215 216 217 ; save vector registers 218 219 subi r4,r1,16 220 rlwinm r4,r4,0,0,27 ; mask low 4-bits 221 ; r4 is now a 16-byte aligned pointer into the red zone 222 223#define SAVE_VECTOR_UNALIGNED(_vec, _offset) \ 224 stvx _vec,0,r4 @\ 225 lwz r5, 0(r4) @\ 226 stw r5, _offset(r3) @\ 227 lwz r5, 4(r4) @\ 228 stw r5, _offset+4(r3) @\ 229 lwz r5, 8(r4) @\ 230 stw r5, _offset+8(r3) @\ 231 lwz r5, 12(r4) @\ 232 stw r5, _offset+12(r3) 233 234 SAVE_VECTOR_UNALIGNED( v0, 424+0x000) 235 SAVE_VECTOR_UNALIGNED( v1, 424+0x010) 236 SAVE_VECTOR_UNALIGNED( v2, 424+0x020) 237 SAVE_VECTOR_UNALIGNED( v3, 424+0x030) 238 SAVE_VECTOR_UNALIGNED( v4, 424+0x040) 239 SAVE_VECTOR_UNALIGNED( v5, 424+0x050) 240 SAVE_VECTOR_UNALIGNED( v6, 424+0x060) 241 SAVE_VECTOR_UNALIGNED( v7, 424+0x070) 242 SAVE_VECTOR_UNALIGNED( v8, 424+0x080) 243 SAVE_VECTOR_UNALIGNED( v9, 424+0x090) 244 SAVE_VECTOR_UNALIGNED(v10, 424+0x0A0) 245 SAVE_VECTOR_UNALIGNED(v11, 424+0x0B0) 246 SAVE_VECTOR_UNALIGNED(v12, 424+0x0C0) 247 SAVE_VECTOR_UNALIGNED(v13, 424+0x0D0) 248 SAVE_VECTOR_UNALIGNED(v14, 424+0x0E0) 249 SAVE_VECTOR_UNALIGNED(v15, 424+0x0F0) 250 SAVE_VECTOR_UNALIGNED(v16, 424+0x100) 251 SAVE_VECTOR_UNALIGNED(v17, 424+0x110) 252 SAVE_VECTOR_UNALIGNED(v18, 424+0x120) 253 SAVE_VECTOR_UNALIGNED(v19, 424+0x130) 254 SAVE_VECTOR_UNALIGNED(v20, 424+0x140) 255 SAVE_VECTOR_UNALIGNED(v21, 424+0x150) 256 SAVE_VECTOR_UNALIGNED(v22, 424+0x160) 257 SAVE_VECTOR_UNALIGNED(v23, 424+0x170) 258 SAVE_VECTOR_UNALIGNED(v24, 424+0x180) 259 SAVE_VECTOR_UNALIGNED(v25, 424+0x190) 260 SAVE_VECTOR_UNALIGNED(v26, 424+0x1A0) 261 SAVE_VECTOR_UNALIGNED(v27, 424+0x1B0) 262 SAVE_VECTOR_UNALIGNED(v28, 424+0x1C0) 263 SAVE_VECTOR_UNALIGNED(v29, 424+0x1D0) 264 SAVE_VECTOR_UNALIGNED(v30, 424+0x1E0) 265 SAVE_VECTOR_UNALIGNED(v31, 424+0x1F0) 266 267 li r3, 0 ; return UNW_ESUCCESS 268 blr 269 270 271#elif defined(__arm64__) || defined(__aarch64__) 272 273// 274// extern int unw_getcontext(unw_context_t* thread_state) 275// 276// On entry: 277// thread_state pointer is in x0 278// 279 .p2align 2 280DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) 281 stp x0, x1, [x0, #0x000] 282 stp x2, x3, [x0, #0x010] 283 stp x4, x5, [x0, #0x020] 284 stp x6, x7, [x0, #0x030] 285 stp x8, x9, [x0, #0x040] 286 stp x10,x11, [x0, #0x050] 287 stp x12,x13, [x0, #0x060] 288 stp x14,x15, [x0, #0x070] 289 stp x16,x17, [x0, #0x080] 290 stp x18,x19, [x0, #0x090] 291 stp x20,x21, [x0, #0x0A0] 292 stp x22,x23, [x0, #0x0B0] 293 stp x24,x25, [x0, #0x0C0] 294 stp x26,x27, [x0, #0x0D0] 295 stp x28,x29, [x0, #0x0E0] 296 str x30, [x0, #0x0F0] 297 mov x1,sp 298 str x1, [x0, #0x0F8] 299 str x30, [x0, #0x100] // store return address as pc 300 // skip cpsr 301 stp d0, d1, [x0, #0x110] 302 stp d2, d3, [x0, #0x120] 303 stp d4, d5, [x0, #0x130] 304 stp d6, d7, [x0, #0x140] 305 stp d8, d9, [x0, #0x150] 306 stp d10,d11, [x0, #0x160] 307 stp d12,d13, [x0, #0x170] 308 stp d14,d15, [x0, #0x180] 309 stp d16,d17, [x0, #0x190] 310 stp d18,d19, [x0, #0x1A0] 311 stp d20,d21, [x0, #0x1B0] 312 stp d22,d23, [x0, #0x1C0] 313 stp d24,d25, [x0, #0x1D0] 314 stp d26,d27, [x0, #0x1E0] 315 stp d28,d29, [x0, #0x1F0] 316 str d30, [x0, #0x200] 317 str d31, [x0, #0x208] 318 mov x0, #0 // return UNW_ESUCCESS 319 ret 320 321#elif defined(__arm__) && !defined(__APPLE__) 322 323#if !defined(__ARM_ARCH_ISA_ARM) 324 .thumb 325#endif 326 327@ 328@ extern int unw_getcontext(unw_context_t* thread_state) 329@ 330@ On entry: 331@ thread_state pointer is in r0 332@ 333@ Per EHABI #4.7 this only saves the core integer registers. 334@ EHABI #7.4.5 notes that in general all VRS registers should be restored 335@ however this is very hard to do for VFP registers because it is unknown 336@ to the library how many registers are implemented by the architecture. 337@ Instead, VFP registers are demand saved by logic external to unw_getcontext. 338@ 339 .p2align 2 340DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) 341#if !defined(__ARM_ARCH_ISA_ARM) && __ARM_ARCH_ISA_THUMB == 1 342 stm r0!, {r0-r7} 343 mov r1, r8 344 mov r2, r9 345 mov r3, r10 346 stm r0!, {r1-r3} 347 mov r1, r11 348 mov r2, sp 349 mov r3, lr 350 str r1, [r0, #0] @ r11 351 @ r12 does not need storing, it it the intra-procedure-call scratch register 352 str r2, [r0, #8] @ sp 353 str r3, [r0, #12] @ lr 354 str r3, [r0, #16] @ store return address as pc 355 @ T1 does not have a non-cpsr-clobbering register-zeroing instruction. 356 @ It is safe to use here though because we are about to return, and cpsr is 357 @ not expected to be preserved. 358 movs r0, #0 @ return UNW_ESUCCESS 359#else 360 @ 32bit thumb-2 restrictions for stm: 361 @ . the sp (r13) cannot be in the list 362 @ . the pc (r15) cannot be in the list in an STM instruction 363 stm r0, {r0-r12} 364 str sp, [r0, #52] 365 str lr, [r0, #56] 366 str lr, [r0, #60] @ store return address as pc 367 mov r0, #0 @ return UNW_ESUCCESS 368#endif 369 JMP(lr) 370 371@ 372@ static void libunwind::Registers_arm::saveVFPWithFSTMD(unw_fpreg_t* values) 373@ 374@ On entry: 375@ values pointer is in r0 376@ 377 .p2align 2 378#if defined(__ELF__) 379 .fpu vfpv3-d16 380#endif 381DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMDEPy) 382 vstmia r0, {d0-d15} 383 JMP(lr) 384 385@ 386@ static void libunwind::Registers_arm::saveVFPWithFSTMX(unw_fpreg_t* values) 387@ 388@ On entry: 389@ values pointer is in r0 390@ 391 .p2align 2 392#if defined(__ELF__) 393 .fpu vfpv3-d16 394#endif 395DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMXEPy) 396 vstmia r0, {d0-d15} @ fstmiax is deprecated in ARMv7+ and now behaves like vstmia 397 JMP(lr) 398 399@ 400@ static void libunwind::Registers_arm::saveVFPv3(unw_fpreg_t* values) 401@ 402@ On entry: 403@ values pointer is in r0 404@ 405 .p2align 2 406#if defined(__ELF__) 407 .fpu vfpv3 408#endif 409DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveVFPv3EPy) 410 @ VFP and iwMMX instructions are only available when compiling with the flags 411 @ that enable them. We do not want to do that in the library (because we do not 412 @ want the compiler to generate instructions that access those) but this is 413 @ only accessed if the personality routine needs these registers. Use of 414 @ these registers implies they are, actually, available on the target, so 415 @ it's ok to execute. 416 @ So, generate the instructions using the corresponding coprocessor mnemonic. 417 vstmia r0, {d16-d31} 418 JMP(lr) 419 420#if defined(_LIBUNWIND_ARM_WMMX) 421 422@ 423@ static void libunwind::Registers_arm::saveiWMMX(unw_fpreg_t* values) 424@ 425@ On entry: 426@ values pointer is in r0 427@ 428 .p2align 2 429#if defined(__ELF__) 430 .arch armv5te 431#endif 432DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveiWMMXEPy) 433 stcl p1, cr0, [r0], #8 @ wstrd wR0, [r0], #8 434 stcl p1, cr1, [r0], #8 @ wstrd wR1, [r0], #8 435 stcl p1, cr2, [r0], #8 @ wstrd wR2, [r0], #8 436 stcl p1, cr3, [r0], #8 @ wstrd wR3, [r0], #8 437 stcl p1, cr4, [r0], #8 @ wstrd wR4, [r0], #8 438 stcl p1, cr5, [r0], #8 @ wstrd wR5, [r0], #8 439 stcl p1, cr6, [r0], #8 @ wstrd wR6, [r0], #8 440 stcl p1, cr7, [r0], #8 @ wstrd wR7, [r0], #8 441 stcl p1, cr8, [r0], #8 @ wstrd wR8, [r0], #8 442 stcl p1, cr9, [r0], #8 @ wstrd wR9, [r0], #8 443 stcl p1, cr10, [r0], #8 @ wstrd wR10, [r0], #8 444 stcl p1, cr11, [r0], #8 @ wstrd wR11, [r0], #8 445 stcl p1, cr12, [r0], #8 @ wstrd wR12, [r0], #8 446 stcl p1, cr13, [r0], #8 @ wstrd wR13, [r0], #8 447 stcl p1, cr14, [r0], #8 @ wstrd wR14, [r0], #8 448 stcl p1, cr15, [r0], #8 @ wstrd wR15, [r0], #8 449 JMP(lr) 450 451@ 452@ static void libunwind::Registers_arm::saveiWMMXControl(unw_uint32_t* values) 453@ 454@ On entry: 455@ values pointer is in r0 456@ 457 .p2align 2 458#if defined(__ELF__) 459 .arch armv5te 460#endif 461DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveiWMMXControlEPj) 462 stc2 p1, cr8, [r0], #4 @ wstrw wCGR0, [r0], #4 463 stc2 p1, cr9, [r0], #4 @ wstrw wCGR1, [r0], #4 464 stc2 p1, cr10, [r0], #4 @ wstrw wCGR2, [r0], #4 465 stc2 p1, cr11, [r0], #4 @ wstrw wCGR3, [r0], #4 466 JMP(lr) 467 468#endif 469 470#elif defined(__or1k__) 471 472# 473# extern int unw_getcontext(unw_context_t* thread_state) 474# 475# On entry: 476# thread_state pointer is in r3 477# 478DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) 479 l.sw 0(r3), r0 480 l.sw 4(r3), r1 481 l.sw 8(r3), r2 482 l.sw 12(r3), r3 483 l.sw 16(r3), r4 484 l.sw 20(r3), r5 485 l.sw 24(r3), r6 486 l.sw 28(r3), r7 487 l.sw 32(r3), r8 488 l.sw 36(r3), r9 489 l.sw 40(r3), r10 490 l.sw 44(r3), r11 491 l.sw 48(r3), r12 492 l.sw 52(r3), r13 493 l.sw 56(r3), r14 494 l.sw 60(r3), r15 495 l.sw 64(r3), r16 496 l.sw 68(r3), r17 497 l.sw 72(r3), r18 498 l.sw 76(r3), r19 499 l.sw 80(r3), r20 500 l.sw 84(r3), r21 501 l.sw 88(r3), r22 502 l.sw 92(r3), r23 503 l.sw 96(r3), r24 504 l.sw 100(r3), r25 505 l.sw 104(r3), r26 506 l.sw 108(r3), r27 507 l.sw 112(r3), r28 508 l.sw 116(r3), r29 509 l.sw 120(r3), r30 510 l.sw 124(r3), r31 511#endif 512 513#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */ 514 515NO_EXEC_STACK_DIRECTIVE 516 517