1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "assembly.h"
10
11#define FROM_0_TO_15 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
12#define FROM_16_TO_31 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
13
14#define FROM_0_TO_31 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
15#define FROM_32_TO_63 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63
16
17#if defined(_AIX)
18 .toc
19#else
20 .text
21#endif
22
23#if !defined(__USING_SJLJ_EXCEPTIONS__)
24
25#if defined(__i386__)
26DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_jumpto)
27#
28# extern "C" void __libunwind_Registers_x86_jumpto(Registers_x86 *);
29#
30# On entry:
31# + +
32# +-----------------------+
33# + thread_state pointer +
34# +-----------------------+
35# + return address +
36# +-----------------------+ <-- SP
37# + +
38
39 _LIBUNWIND_CET_ENDBR
40 movl 4(%esp), %eax
41 # set up eax and ret on new stack location
42 movl 28(%eax), %edx # edx holds new stack pointer
43 subl $8,%edx
44 movl %edx, 28(%eax)
45 movl 0(%eax), %ebx
46 movl %ebx, 0(%edx)
47 movl 40(%eax), %ebx
48 movl %ebx, 4(%edx)
49 # we now have ret and eax pushed onto where new stack will be
50 # restore all registers
51 movl 4(%eax), %ebx
52 movl 8(%eax), %ecx
53 movl 12(%eax), %edx
54 movl 16(%eax), %edi
55 movl 20(%eax), %esi
56 movl 24(%eax), %ebp
57 movl 28(%eax), %esp
58 # skip ss
59 # skip eflags
60 pop %eax # eax was already pushed on new stack
61 pop %ecx
62 jmp *%ecx
63 # skip cs
64 # skip ds
65 # skip es
66 # skip fs
67 # skip gs
68
69#elif defined(__x86_64__)
70
71DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_64_jumpto)
72#
73# extern "C" void __libunwind_Registers_x86_64_jumpto(Registers_x86_64 *);
74#
75#if defined(_WIN64)
76# On entry, thread_state pointer is in rcx; move it into rdi
77# to share restore code below. Since this routine restores and
78# overwrites all registers, we can use the same registers for
79# pointers and temporaries as on unix even though win64 normally
80# mustn't clobber some of them.
81 movq %rcx, %rdi
82#else
83# On entry, thread_state pointer is in rdi
84#endif
85
86 _LIBUNWIND_CET_ENDBR
87 movq 56(%rdi), %rax # rax holds new stack pointer
88 subq $16, %rax
89 movq %rax, 56(%rdi)
90 movq 32(%rdi), %rbx # store new rdi on new stack
91 movq %rbx, 0(%rax)
92 movq 128(%rdi), %rbx # store new rip on new stack
93 movq %rbx, 8(%rax)
94 # restore all registers
95 movq 0(%rdi), %rax
96 movq 8(%rdi), %rbx
97 movq 16(%rdi), %rcx
98 movq 24(%rdi), %rdx
99 # restore rdi later
100 movq 40(%rdi), %rsi
101 movq 48(%rdi), %rbp
102 # restore rsp later
103 movq 64(%rdi), %r8
104 movq 72(%rdi), %r9
105 movq 80(%rdi), %r10
106 movq 88(%rdi), %r11
107 movq 96(%rdi), %r12
108 movq 104(%rdi), %r13
109 movq 112(%rdi), %r14
110 movq 120(%rdi), %r15
111 # skip rflags
112 # skip cs
113 # skip fs
114 # skip gs
115
116#if defined(_WIN64)
117 movdqu 176(%rdi),%xmm0
118 movdqu 192(%rdi),%xmm1
119 movdqu 208(%rdi),%xmm2
120 movdqu 224(%rdi),%xmm3
121 movdqu 240(%rdi),%xmm4
122 movdqu 256(%rdi),%xmm5
123 movdqu 272(%rdi),%xmm6
124 movdqu 288(%rdi),%xmm7
125 movdqu 304(%rdi),%xmm8
126 movdqu 320(%rdi),%xmm9
127 movdqu 336(%rdi),%xmm10
128 movdqu 352(%rdi),%xmm11
129 movdqu 368(%rdi),%xmm12
130 movdqu 384(%rdi),%xmm13
131 movdqu 400(%rdi),%xmm14
132 movdqu 416(%rdi),%xmm15
133#endif
134 movq 56(%rdi), %rsp # cut back rsp to new location
135 pop %rdi # rdi was saved here earlier
136 pop %rcx
137 jmpq *%rcx
138
139
140#elif defined(__powerpc64__)
141
142DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_ppc646jumptoEv)
143//
144// void libunwind::Registers_ppc64::jumpto()
145//
146// On entry:
147// thread_state pointer is in r3
148//
149
150// load register (GPR)
151#define PPC64_LR(n) \
152 ld n, (8 * (n + 2))(3)
153
154 // restore integral registers
155 // skip r0 for now
156 // skip r1 for now
157 PPC64_LR(2)
158 // skip r3 for now
159 // skip r4 for now
160 // skip r5 for now
161 PPC64_LR(6)
162 PPC64_LR(7)
163 PPC64_LR(8)
164 PPC64_LR(9)
165 PPC64_LR(10)
166 PPC64_LR(11)
167 PPC64_LR(12)
168 PPC64_LR(13)
169 PPC64_LR(14)
170 PPC64_LR(15)
171 PPC64_LR(16)
172 PPC64_LR(17)
173 PPC64_LR(18)
174 PPC64_LR(19)
175 PPC64_LR(20)
176 PPC64_LR(21)
177 PPC64_LR(22)
178 PPC64_LR(23)
179 PPC64_LR(24)
180 PPC64_LR(25)
181 PPC64_LR(26)
182 PPC64_LR(27)
183 PPC64_LR(28)
184 PPC64_LR(29)
185 PPC64_LR(30)
186 PPC64_LR(31)
187
188#if defined(__VSX__)
189
190 // restore VS registers
191 // (note that this also restores floating point registers and V registers,
192 // because part of VS is mapped to these registers)
193
194 addi 4, 3, PPC64_OFFS_FP
195
196// load VS register
197#ifdef __LITTLE_ENDIAN__
198// For little-endian targets, we need a swap since lxvd2x will load the register
199// in the incorrect doubleword order.
200// FIXME: when supporting targets older than Power9 on LE is no longer required,
201// this can be changed to simply `lxv n, (16 * n)(4)`.
202#define PPC64_LVS(n) \
203 lxvd2x n, 0, 4 ;\
204 xxswapd n, n ;\
205 addi 4, 4, 16
206#else
207#define PPC64_LVS(n) \
208 lxvd2x n, 0, 4 ;\
209 addi 4, 4, 16
210#endif
211
212 // restore the first 32 VS regs (and also all floating point regs)
213 PPC64_LVS(0)
214 PPC64_LVS(1)
215 PPC64_LVS(2)
216 PPC64_LVS(3)
217 PPC64_LVS(4)
218 PPC64_LVS(5)
219 PPC64_LVS(6)
220 PPC64_LVS(7)
221 PPC64_LVS(8)
222 PPC64_LVS(9)
223 PPC64_LVS(10)
224 PPC64_LVS(11)
225 PPC64_LVS(12)
226 PPC64_LVS(13)
227 PPC64_LVS(14)
228 PPC64_LVS(15)
229 PPC64_LVS(16)
230 PPC64_LVS(17)
231 PPC64_LVS(18)
232 PPC64_LVS(19)
233 PPC64_LVS(20)
234 PPC64_LVS(21)
235 PPC64_LVS(22)
236 PPC64_LVS(23)
237 PPC64_LVS(24)
238 PPC64_LVS(25)
239 PPC64_LVS(26)
240 PPC64_LVS(27)
241 PPC64_LVS(28)
242 PPC64_LVS(29)
243 PPC64_LVS(30)
244 PPC64_LVS(31)
245
246#ifdef __LITTLE_ENDIAN__
247#define PPC64_CLVS_RESTORE(n) \
248 addi 4, 3, PPC64_OFFS_FP + n * 16 ;\
249 lxvd2x n, 0, 4 ;\
250 xxswapd n, n
251#else
252#define PPC64_CLVS_RESTORE(n) \
253 addi 4, 3, PPC64_OFFS_FP + n * 16 ;\
254 lxvd2x n, 0, 4
255#endif
256
257#if !defined(_AIX)
258 // use VRSAVE to conditionally restore the remaining VS regs, that are
259 // where the V regs are mapped. In the AIX ABI, VRSAVE is not used.
260 ld 5, PPC64_OFFS_VRSAVE(3) // test VRsave
261 cmpwi 5, 0
262 beq Lnovec
263
264// conditionally load VS
265#define PPC64_CLVSl(n) \
266 andis. 0, 5, (1 PPC_LEFT_SHIFT(47-n)) ;\
267 beq Ldone##n ;\
268 PPC64_CLVS_RESTORE(n) ;\
269Ldone##n:
270
271#define PPC64_CLVSh(n) \
272 andi. 0, 5, (1 PPC_LEFT_SHIFT(63-n)) ;\
273 beq Ldone##n ;\
274 PPC64_CLVS_RESTORE(n) ;\
275Ldone##n:
276
277#else
278
279#define PPC64_CLVSl(n) PPC64_CLVS_RESTORE(n)
280#define PPC64_CLVSh(n) PPC64_CLVS_RESTORE(n)
281
282#endif // !defined(_AIX)
283
284 PPC64_CLVSl(32)
285 PPC64_CLVSl(33)
286 PPC64_CLVSl(34)
287 PPC64_CLVSl(35)
288 PPC64_CLVSl(36)
289 PPC64_CLVSl(37)
290 PPC64_CLVSl(38)
291 PPC64_CLVSl(39)
292 PPC64_CLVSl(40)
293 PPC64_CLVSl(41)
294 PPC64_CLVSl(42)
295 PPC64_CLVSl(43)
296 PPC64_CLVSl(44)
297 PPC64_CLVSl(45)
298 PPC64_CLVSl(46)
299 PPC64_CLVSl(47)
300 PPC64_CLVSh(48)
301 PPC64_CLVSh(49)
302 PPC64_CLVSh(50)
303 PPC64_CLVSh(51)
304 PPC64_CLVSh(52)
305 PPC64_CLVSh(53)
306 PPC64_CLVSh(54)
307 PPC64_CLVSh(55)
308 PPC64_CLVSh(56)
309 PPC64_CLVSh(57)
310 PPC64_CLVSh(58)
311 PPC64_CLVSh(59)
312 PPC64_CLVSh(60)
313 PPC64_CLVSh(61)
314 PPC64_CLVSh(62)
315 PPC64_CLVSh(63)
316
317#else
318
319// load FP register
320#define PPC64_LF(n) \
321 lfd n, (PPC64_OFFS_FP + n * 16)(3)
322
323 // restore float registers
324 PPC64_LF(0)
325 PPC64_LF(1)
326 PPC64_LF(2)
327 PPC64_LF(3)
328 PPC64_LF(4)
329 PPC64_LF(5)
330 PPC64_LF(6)
331 PPC64_LF(7)
332 PPC64_LF(8)
333 PPC64_LF(9)
334 PPC64_LF(10)
335 PPC64_LF(11)
336 PPC64_LF(12)
337 PPC64_LF(13)
338 PPC64_LF(14)
339 PPC64_LF(15)
340 PPC64_LF(16)
341 PPC64_LF(17)
342 PPC64_LF(18)
343 PPC64_LF(19)
344 PPC64_LF(20)
345 PPC64_LF(21)
346 PPC64_LF(22)
347 PPC64_LF(23)
348 PPC64_LF(24)
349 PPC64_LF(25)
350 PPC64_LF(26)
351 PPC64_LF(27)
352 PPC64_LF(28)
353 PPC64_LF(29)
354 PPC64_LF(30)
355 PPC64_LF(31)
356
357#if defined(__ALTIVEC__)
358
359#define PPC64_CLV_UNALIGNED_RESTORE(n) \
360 ld 0, (PPC64_OFFS_V + n * 16)(3) ;\
361 std 0, 0(4) ;\
362 ld 0, (PPC64_OFFS_V + n * 16 + 8)(3) ;\
363 std 0, 8(4) ;\
364 lvx n, 0, 4
365
366#if !defined(_AIX)
367 // restore vector registers if any are in use. In the AIX ABI, VRSAVE is
368 // not used.
369 ld 5, PPC64_OFFS_VRSAVE(3) // test VRsave
370 cmpwi 5, 0
371 beq Lnovec
372
373#define PPC64_CLV_UNALIGNEDl(n) \
374 andis. 0, 5, (1 PPC_LEFT_SHIFT(15-n)) ;\
375 beq Ldone##n ;\
376 PPC64_CLV_UNALIGNED_RESTORE(n) ;\
377Ldone ## n:
378
379#define PPC64_CLV_UNALIGNEDh(n) \
380 andi. 0, 5, (1 PPC_LEFT_SHIFT(31-n)) ;\
381 beq Ldone##n ;\
382 PPC64_CLV_UNALIGNED_RESTORE(n) ;\
383Ldone ## n:
384
385#else
386
387#define PPC64_CLV_UNALIGNEDl(n) PPC64_CLV_UNALIGNED_RESTORE(n)
388#define PPC64_CLV_UNALIGNEDh(n) PPC64_CLV_UNALIGNED_RESTORE(n)
389
390#endif // !defined(_AIX)
391
392 subi 4, 1, 16
393 // r4 is now a 16-byte aligned pointer into the red zone
394 // the _vectorScalarRegisters may not be 16-byte aligned
395 // so copy via red zone temp buffer
396
397 PPC64_CLV_UNALIGNEDl(0)
398 PPC64_CLV_UNALIGNEDl(1)
399 PPC64_CLV_UNALIGNEDl(2)
400 PPC64_CLV_UNALIGNEDl(3)
401 PPC64_CLV_UNALIGNEDl(4)
402 PPC64_CLV_UNALIGNEDl(5)
403 PPC64_CLV_UNALIGNEDl(6)
404 PPC64_CLV_UNALIGNEDl(7)
405 PPC64_CLV_UNALIGNEDl(8)
406 PPC64_CLV_UNALIGNEDl(9)
407 PPC64_CLV_UNALIGNEDl(10)
408 PPC64_CLV_UNALIGNEDl(11)
409 PPC64_CLV_UNALIGNEDl(12)
410 PPC64_CLV_UNALIGNEDl(13)
411 PPC64_CLV_UNALIGNEDl(14)
412 PPC64_CLV_UNALIGNEDl(15)
413 PPC64_CLV_UNALIGNEDh(16)
414 PPC64_CLV_UNALIGNEDh(17)
415 PPC64_CLV_UNALIGNEDh(18)
416 PPC64_CLV_UNALIGNEDh(19)
417 PPC64_CLV_UNALIGNEDh(20)
418 PPC64_CLV_UNALIGNEDh(21)
419 PPC64_CLV_UNALIGNEDh(22)
420 PPC64_CLV_UNALIGNEDh(23)
421 PPC64_CLV_UNALIGNEDh(24)
422 PPC64_CLV_UNALIGNEDh(25)
423 PPC64_CLV_UNALIGNEDh(26)
424 PPC64_CLV_UNALIGNEDh(27)
425 PPC64_CLV_UNALIGNEDh(28)
426 PPC64_CLV_UNALIGNEDh(29)
427 PPC64_CLV_UNALIGNEDh(30)
428 PPC64_CLV_UNALIGNEDh(31)
429
430#endif
431#endif
432
433Lnovec:
434 ld 0, PPC64_OFFS_CR(3)
435 mtcr 0
436 ld 0, PPC64_OFFS_SRR0(3)
437 mtctr 0
438
439#if defined(_AIX)
440 // After setting GPR1 to a higher address, AIX wipes out the original
441 // stack space below that address invalidated by the new GPR1 value. Use
442 // GPR0 to save the value of GPR3 in the context before it is wiped out.
443 // This compromises the content of GPR0 which is a volatile register.
444 ld 0, (8 * (3 + 2))(3)
445#else
446 PPC64_LR(0)
447#endif
448 PPC64_LR(5)
449 PPC64_LR(4)
450 PPC64_LR(1)
451#if defined(_AIX)
452 mr 3, 0
453#else
454 PPC64_LR(3)
455#endif
456 bctr
457
458#elif defined(__powerpc__)
459
460DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_ppc6jumptoEv)
461//
462// void libunwind::Registers_ppc::jumpto()
463//
464// On entry:
465// thread_state pointer is in r3
466//
467
468 // restore integral registers
469 // skip r0 for now
470 // skip r1 for now
471 lwz 2, 16(3)
472 // skip r3 for now
473 // skip r4 for now
474 // skip r5 for now
475 lwz 6, 32(3)
476 lwz 7, 36(3)
477 lwz 8, 40(3)
478 lwz 9, 44(3)
479 lwz 10, 48(3)
480 lwz 11, 52(3)
481 lwz 12, 56(3)
482 lwz 13, 60(3)
483 lwz 14, 64(3)
484 lwz 15, 68(3)
485 lwz 16, 72(3)
486 lwz 17, 76(3)
487 lwz 18, 80(3)
488 lwz 19, 84(3)
489 lwz 20, 88(3)
490 lwz 21, 92(3)
491 lwz 22, 96(3)
492 lwz 23,100(3)
493 lwz 24,104(3)
494 lwz 25,108(3)
495 lwz 26,112(3)
496 lwz 27,116(3)
497 lwz 28,120(3)
498 lwz 29,124(3)
499 lwz 30,128(3)
500 lwz 31,132(3)
501
502#ifndef __NO_FPRS__
503 // restore float registers
504 lfd 0, 160(3)
505 lfd 1, 168(3)
506 lfd 2, 176(3)
507 lfd 3, 184(3)
508 lfd 4, 192(3)
509 lfd 5, 200(3)
510 lfd 6, 208(3)
511 lfd 7, 216(3)
512 lfd 8, 224(3)
513 lfd 9, 232(3)
514 lfd 10,240(3)
515 lfd 11,248(3)
516 lfd 12,256(3)
517 lfd 13,264(3)
518 lfd 14,272(3)
519 lfd 15,280(3)
520 lfd 16,288(3)
521 lfd 17,296(3)
522 lfd 18,304(3)
523 lfd 19,312(3)
524 lfd 20,320(3)
525 lfd 21,328(3)
526 lfd 22,336(3)
527 lfd 23,344(3)
528 lfd 24,352(3)
529 lfd 25,360(3)
530 lfd 26,368(3)
531 lfd 27,376(3)
532 lfd 28,384(3)
533 lfd 29,392(3)
534 lfd 30,400(3)
535 lfd 31,408(3)
536#endif
537
538#if defined(__ALTIVEC__)
539
540#define LOAD_VECTOR_RESTORE(_index) \
541 lwz 0, 424+_index*16(3) SEPARATOR \
542 stw 0, 0(4) SEPARATOR \
543 lwz 0, 424+_index*16+4(3) SEPARATOR \
544 stw 0, 4(4) SEPARATOR \
545 lwz 0, 424+_index*16+8(3) SEPARATOR \
546 stw 0, 8(4) SEPARATOR \
547 lwz 0, 424+_index*16+12(3) SEPARATOR \
548 stw 0, 12(4) SEPARATOR \
549 lvx _index, 0, 4
550
551#if !defined(_AIX)
552 // restore vector registers if any are in use. In the AIX ABI, VRSAVE
553 // is not used.
554 lwz 5, 156(3) // test VRsave
555 cmpwi 5, 0
556 beq Lnovec
557
558#define LOAD_VECTOR_UNALIGNEDl(_index) \
559 andis. 0, 5, (1 PPC_LEFT_SHIFT(15-_index)) SEPARATOR \
560 beq Ldone ## _index SEPARATOR \
561 LOAD_VECTOR_RESTORE(_index) SEPARATOR \
562 Ldone ## _index:
563
564#define LOAD_VECTOR_UNALIGNEDh(_index) \
565 andi. 0, 5, (1 PPC_LEFT_SHIFT(31-_index)) SEPARATOR \
566 beq Ldone ## _index SEPARATOR \
567 LOAD_VECTOR_RESTORE(_index) SEPARATOR \
568 Ldone ## _index:
569
570#else
571
572#define LOAD_VECTOR_UNALIGNEDl(_index) LOAD_VECTOR_RESTORE(_index)
573#define LOAD_VECTOR_UNALIGNEDh(_index) LOAD_VECTOR_RESTORE(_index)
574
575#endif // !defined(_AIX)
576
577 subi 4, 1, 16
578 rlwinm 4, 4, 0, 0, 27 // mask low 4-bits
579 // r4 is now a 16-byte aligned pointer into the red zone
580 // the _vectorRegisters may not be 16-byte aligned so copy via red zone temp buffer
581
582 LOAD_VECTOR_UNALIGNEDl(0)
583 LOAD_VECTOR_UNALIGNEDl(1)
584 LOAD_VECTOR_UNALIGNEDl(2)
585 LOAD_VECTOR_UNALIGNEDl(3)
586 LOAD_VECTOR_UNALIGNEDl(4)
587 LOAD_VECTOR_UNALIGNEDl(5)
588 LOAD_VECTOR_UNALIGNEDl(6)
589 LOAD_VECTOR_UNALIGNEDl(7)
590 LOAD_VECTOR_UNALIGNEDl(8)
591 LOAD_VECTOR_UNALIGNEDl(9)
592 LOAD_VECTOR_UNALIGNEDl(10)
593 LOAD_VECTOR_UNALIGNEDl(11)
594 LOAD_VECTOR_UNALIGNEDl(12)
595 LOAD_VECTOR_UNALIGNEDl(13)
596 LOAD_VECTOR_UNALIGNEDl(14)
597 LOAD_VECTOR_UNALIGNEDl(15)
598 LOAD_VECTOR_UNALIGNEDh(16)
599 LOAD_VECTOR_UNALIGNEDh(17)
600 LOAD_VECTOR_UNALIGNEDh(18)
601 LOAD_VECTOR_UNALIGNEDh(19)
602 LOAD_VECTOR_UNALIGNEDh(20)
603 LOAD_VECTOR_UNALIGNEDh(21)
604 LOAD_VECTOR_UNALIGNEDh(22)
605 LOAD_VECTOR_UNALIGNEDh(23)
606 LOAD_VECTOR_UNALIGNEDh(24)
607 LOAD_VECTOR_UNALIGNEDh(25)
608 LOAD_VECTOR_UNALIGNEDh(26)
609 LOAD_VECTOR_UNALIGNEDh(27)
610 LOAD_VECTOR_UNALIGNEDh(28)
611 LOAD_VECTOR_UNALIGNEDh(29)
612 LOAD_VECTOR_UNALIGNEDh(30)
613 LOAD_VECTOR_UNALIGNEDh(31)
614#endif
615
616Lnovec:
617 lwz 0, 136(3) // __cr
618 mtcr 0
619 lwz 0, 148(3) // __ctr
620 mtctr 0
621 lwz 0, 0(3) // __ssr0
622 mtctr 0
623 lwz 0, 8(3) // do r0 now
624 lwz 5, 28(3) // do r5 now
625 lwz 4, 24(3) // do r4 now
626 lwz 1, 12(3) // do sp now
627 lwz 3, 20(3) // do r3 last
628 bctr
629
630#elif defined(__aarch64__)
631
632//
633// extern "C" void __libunwind_Registers_arm64_jumpto(Registers_arm64 *);
634//
635// On entry:
636// thread_state pointer is in x0
637//
638 .p2align 2
639DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto)
640 // skip restore of x0,x1 for now
641 ldp x2, x3, [x0, #0x010]
642 ldp x4, x5, [x0, #0x020]
643 ldp x6, x7, [x0, #0x030]
644 ldp x8, x9, [x0, #0x040]
645 ldp x10,x11, [x0, #0x050]
646 ldp x12,x13, [x0, #0x060]
647 ldp x14,x15, [x0, #0x070]
648 // x16 and x17 were clobbered by the call into the unwinder, so no point in
649 // restoring them.
650 ldp x18,x19, [x0, #0x090]
651 ldp x20,x21, [x0, #0x0A0]
652 ldp x22,x23, [x0, #0x0B0]
653 ldp x24,x25, [x0, #0x0C0]
654 ldp x26,x27, [x0, #0x0D0]
655 ldp x28,x29, [x0, #0x0E0]
656 ldr x30, [x0, #0x100] // restore pc into lr
657
658 ldp d0, d1, [x0, #0x110]
659 ldp d2, d3, [x0, #0x120]
660 ldp d4, d5, [x0, #0x130]
661 ldp d6, d7, [x0, #0x140]
662 ldp d8, d9, [x0, #0x150]
663 ldp d10,d11, [x0, #0x160]
664 ldp d12,d13, [x0, #0x170]
665 ldp d14,d15, [x0, #0x180]
666 ldp d16,d17, [x0, #0x190]
667 ldp d18,d19, [x0, #0x1A0]
668 ldp d20,d21, [x0, #0x1B0]
669 ldp d22,d23, [x0, #0x1C0]
670 ldp d24,d25, [x0, #0x1D0]
671 ldp d26,d27, [x0, #0x1E0]
672 ldp d28,d29, [x0, #0x1F0]
673 ldr d30, [x0, #0x200]
674 ldr d31, [x0, #0x208]
675
676 // Finally, restore sp. This must be done after the last read from the
677 // context struct, because it is allocated on the stack, and an exception
678 // could clobber the de-allocated portion of the stack after sp has been
679 // restored.
680 ldr x16, [x0, #0x0F8]
681 ldp x0, x1, [x0, #0x000] // restore x0,x1
682 mov sp,x16 // restore sp
683 ret x30 // jump to pc
684
685#elif defined(__arm__) && !defined(__APPLE__)
686
687#if !defined(__ARM_ARCH_ISA_ARM)
688#if (__ARM_ARCH_ISA_THUMB == 2)
689 .syntax unified
690#endif
691 .thumb
692#endif
693
694@
695@ void libunwind::Registers_arm::restoreCoreAndJumpTo()
696@
697@ On entry:
698@ thread_state pointer is in r0
699@
700 .p2align 2
701DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm20restoreCoreAndJumpToEv)
702#if !defined(__ARM_ARCH_ISA_ARM) && __ARM_ARCH_ISA_THUMB == 1
703 @ r8-r11: ldm into r1-r4, then mov to r8-r11
704 adds r0, #0x20
705 ldm r0!, {r1-r4}
706 subs r0, #0x30
707 mov r8, r1
708 mov r9, r2
709 mov r10, r3
710 mov r11, r4
711 @ r12 does not need loading, it it the intra-procedure-call scratch register
712 ldr r2, [r0, #0x34]
713 ldr r3, [r0, #0x3c]
714 mov sp, r2
715 mov lr, r3 @ restore pc into lr
716 ldm r0, {r0-r7}
717#else
718 @ Use lr as base so that r0 can be restored.
719 mov lr, r0
720 @ 32bit thumb-2 restrictions for ldm:
721 @ . the sp (r13) cannot be in the list
722 @ . the pc (r15) and lr (r14) cannot both be in the list in an LDM instruction
723 ldm lr, {r0-r12}
724 ldr sp, [lr, #52]
725 ldr lr, [lr, #60] @ restore pc into lr
726#endif
727#if defined(__ARM_FEATURE_BTI_DEFAULT) && !defined(__ARM_ARCH_ISA_ARM)
728 // 'bx' is not BTI setting when used with lr, therefore r12 is used instead
729 mov r12, lr
730 JMP(r12)
731#else
732 JMP(lr)
733#endif
734
735@
736@ static void libunwind::Registers_arm::restoreVFPWithFLDMD(unw_fpreg_t* values)
737@
738@ On entry:
739@ values pointer is in r0
740@
741 .p2align 2
742#if defined(__ELF__)
743 .fpu vfpv3-d16
744#endif
745DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFLDMDEPv)
746 @ VFP and iwMMX instructions are only available when compiling with the flags
747 @ that enable them. We do not want to do that in the library (because we do not
748 @ want the compiler to generate instructions that access those) but this is
749 @ only accessed if the personality routine needs these registers. Use of
750 @ these registers implies they are, actually, available on the target, so
751 @ it's ok to execute.
752 @ So, generate the instruction using the corresponding coprocessor mnemonic.
753 vldmia r0, {d0-d15}
754 JMP(lr)
755
756@
757@ static void libunwind::Registers_arm::restoreVFPWithFLDMX(unw_fpreg_t* values)
758@
759@ On entry:
760@ values pointer is in r0
761@
762 .p2align 2
763#if defined(__ELF__)
764 .fpu vfpv3-d16
765#endif
766DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFLDMXEPv)
767 vldmia r0, {d0-d15} @ fldmiax is deprecated in ARMv7+ and now behaves like vldmia
768 JMP(lr)
769
770@
771@ static void libunwind::Registers_arm::restoreVFPv3(unw_fpreg_t* values)
772@
773@ On entry:
774@ values pointer is in r0
775@
776 .p2align 2
777#if defined(__ELF__)
778 .fpu vfpv3
779#endif
780DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm12restoreVFPv3EPv)
781 vldmia r0, {d16-d31}
782 JMP(lr)
783
784#if defined(__ARM_WMMX)
785
786@
787@ static void libunwind::Registers_arm::restoreiWMMX(unw_fpreg_t* values)
788@
789@ On entry:
790@ values pointer is in r0
791@
792 .p2align 2
793#if defined(__ELF__)
794 .arch armv5te
795#endif
796DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm12restoreiWMMXEPv)
797 ldcl p1, cr0, [r0], #8 @ wldrd wR0, [r0], #8
798 ldcl p1, cr1, [r0], #8 @ wldrd wR1, [r0], #8
799 ldcl p1, cr2, [r0], #8 @ wldrd wR2, [r0], #8
800 ldcl p1, cr3, [r0], #8 @ wldrd wR3, [r0], #8
801 ldcl p1, cr4, [r0], #8 @ wldrd wR4, [r0], #8
802 ldcl p1, cr5, [r0], #8 @ wldrd wR5, [r0], #8
803 ldcl p1, cr6, [r0], #8 @ wldrd wR6, [r0], #8
804 ldcl p1, cr7, [r0], #8 @ wldrd wR7, [r0], #8
805 ldcl p1, cr8, [r0], #8 @ wldrd wR8, [r0], #8
806 ldcl p1, cr9, [r0], #8 @ wldrd wR9, [r0], #8
807 ldcl p1, cr10, [r0], #8 @ wldrd wR10, [r0], #8
808 ldcl p1, cr11, [r0], #8 @ wldrd wR11, [r0], #8
809 ldcl p1, cr12, [r0], #8 @ wldrd wR12, [r0], #8
810 ldcl p1, cr13, [r0], #8 @ wldrd wR13, [r0], #8
811 ldcl p1, cr14, [r0], #8 @ wldrd wR14, [r0], #8
812 ldcl p1, cr15, [r0], #8 @ wldrd wR15, [r0], #8
813 JMP(lr)
814
815@
816@ static void libunwind::Registers_arm::restoreiWMMXControl(unw_uint32_t* values)
817@
818@ On entry:
819@ values pointer is in r0
820@
821 .p2align 2
822#if defined(__ELF__)
823 .arch armv5te
824#endif
825DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm19restoreiWMMXControlEPj)
826 ldc2 p1, cr8, [r0], #4 @ wldrw wCGR0, [r0], #4
827 ldc2 p1, cr9, [r0], #4 @ wldrw wCGR1, [r0], #4
828 ldc2 p1, cr10, [r0], #4 @ wldrw wCGR2, [r0], #4
829 ldc2 p1, cr11, [r0], #4 @ wldrw wCGR3, [r0], #4
830 JMP(lr)
831
832#endif
833
834#elif defined(__or1k__)
835
836DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv)
837#
838# void libunwind::Registers_or1k::jumpto()
839#
840# On entry:
841# thread_state pointer is in r3
842#
843
844 # restore integral registers
845 l.lwz r0, 0(r3)
846 l.lwz r1, 4(r3)
847 l.lwz r2, 8(r3)
848 # skip r3 for now
849 l.lwz r4, 16(r3)
850 l.lwz r5, 20(r3)
851 l.lwz r6, 24(r3)
852 l.lwz r7, 28(r3)
853 l.lwz r8, 32(r3)
854 # skip r9
855 l.lwz r10, 40(r3)
856 l.lwz r11, 44(r3)
857 l.lwz r12, 48(r3)
858 l.lwz r13, 52(r3)
859 l.lwz r14, 56(r3)
860 l.lwz r15, 60(r3)
861 l.lwz r16, 64(r3)
862 l.lwz r17, 68(r3)
863 l.lwz r18, 72(r3)
864 l.lwz r19, 76(r3)
865 l.lwz r20, 80(r3)
866 l.lwz r21, 84(r3)
867 l.lwz r22, 88(r3)
868 l.lwz r23, 92(r3)
869 l.lwz r24, 96(r3)
870 l.lwz r25,100(r3)
871 l.lwz r26,104(r3)
872 l.lwz r27,108(r3)
873 l.lwz r28,112(r3)
874 l.lwz r29,116(r3)
875 l.lwz r30,120(r3)
876 l.lwz r31,124(r3)
877
878 # load new pc into ra
879 l.lwz r9, 128(r3)
880
881 # at last, restore r3
882 l.lwz r3, 12(r3)
883
884 # jump to pc
885 l.jr r9
886 l.nop
887
888#elif defined(__hexagon__)
889# On entry:
890# thread_state pointer is in r2
891DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind17Registers_hexagon6jumptoEv)
892#
893# void libunwind::Registers_hexagon::jumpto()
894#
895 r8 = memw(r0+#32)
896 r9 = memw(r0+#36)
897 r10 = memw(r0+#40)
898 r11 = memw(r0+#44)
899
900 r12 = memw(r0+#48)
901 r13 = memw(r0+#52)
902 r14 = memw(r0+#56)
903 r15 = memw(r0+#60)
904
905 r16 = memw(r0+#64)
906 r17 = memw(r0+#68)
907 r18 = memw(r0+#72)
908 r19 = memw(r0+#76)
909
910 r20 = memw(r0+#80)
911 r21 = memw(r0+#84)
912 r22 = memw(r0+#88)
913 r23 = memw(r0+#92)
914
915 r24 = memw(r0+#96)
916 r25 = memw(r0+#100)
917 r26 = memw(r0+#104)
918 r27 = memw(r0+#108)
919
920 r28 = memw(r0+#112)
921 r29 = memw(r0+#116)
922 r30 = memw(r0+#120)
923 r31 = memw(r0+#132)
924
925 r1 = memw(r0+#128)
926 c4 = r1 // Predicate register
927 r1 = memw(r0+#4)
928 r0 = memw(r0)
929 jumpr r31
930#elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32
931
932//
933// void libunwind::Registers_mips_o32::jumpto()
934//
935// On entry:
936// thread state pointer is in a0 ($4)
937//
938DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind18Registers_mips_o326jumptoEv)
939 .set push
940 .set noat
941 .set noreorder
942 .set nomacro
943#ifdef __mips_hard_float
944#if __mips_fpr != 64
945 ldc1 $f0, (4 * 36 + 8 * 0)($4)
946 ldc1 $f2, (4 * 36 + 8 * 2)($4)
947 ldc1 $f4, (4 * 36 + 8 * 4)($4)
948 ldc1 $f6, (4 * 36 + 8 * 6)($4)
949 ldc1 $f8, (4 * 36 + 8 * 8)($4)
950 ldc1 $f10, (4 * 36 + 8 * 10)($4)
951 ldc1 $f12, (4 * 36 + 8 * 12)($4)
952 ldc1 $f14, (4 * 36 + 8 * 14)($4)
953 ldc1 $f16, (4 * 36 + 8 * 16)($4)
954 ldc1 $f18, (4 * 36 + 8 * 18)($4)
955 ldc1 $f20, (4 * 36 + 8 * 20)($4)
956 ldc1 $f22, (4 * 36 + 8 * 22)($4)
957 ldc1 $f24, (4 * 36 + 8 * 24)($4)
958 ldc1 $f26, (4 * 36 + 8 * 26)($4)
959 ldc1 $f28, (4 * 36 + 8 * 28)($4)
960 ldc1 $f30, (4 * 36 + 8 * 30)($4)
961#else
962 ldc1 $f0, (4 * 36 + 8 * 0)($4)
963 ldc1 $f1, (4 * 36 + 8 * 1)($4)
964 ldc1 $f2, (4 * 36 + 8 * 2)($4)
965 ldc1 $f3, (4 * 36 + 8 * 3)($4)
966 ldc1 $f4, (4 * 36 + 8 * 4)($4)
967 ldc1 $f5, (4 * 36 + 8 * 5)($4)
968 ldc1 $f6, (4 * 36 + 8 * 6)($4)
969 ldc1 $f7, (4 * 36 + 8 * 7)($4)
970 ldc1 $f8, (4 * 36 + 8 * 8)($4)
971 ldc1 $f9, (4 * 36 + 8 * 9)($4)
972 ldc1 $f10, (4 * 36 + 8 * 10)($4)
973 ldc1 $f11, (4 * 36 + 8 * 11)($4)
974 ldc1 $f12, (4 * 36 + 8 * 12)($4)
975 ldc1 $f13, (4 * 36 + 8 * 13)($4)
976 ldc1 $f14, (4 * 36 + 8 * 14)($4)
977 ldc1 $f15, (4 * 36 + 8 * 15)($4)
978 ldc1 $f16, (4 * 36 + 8 * 16)($4)
979 ldc1 $f17, (4 * 36 + 8 * 17)($4)
980 ldc1 $f18, (4 * 36 + 8 * 18)($4)
981 ldc1 $f19, (4 * 36 + 8 * 19)($4)
982 ldc1 $f20, (4 * 36 + 8 * 20)($4)
983 ldc1 $f21, (4 * 36 + 8 * 21)($4)
984 ldc1 $f22, (4 * 36 + 8 * 22)($4)
985 ldc1 $f23, (4 * 36 + 8 * 23)($4)
986 ldc1 $f24, (4 * 36 + 8 * 24)($4)
987 ldc1 $f25, (4 * 36 + 8 * 25)($4)
988 ldc1 $f26, (4 * 36 + 8 * 26)($4)
989 ldc1 $f27, (4 * 36 + 8 * 27)($4)
990 ldc1 $f28, (4 * 36 + 8 * 28)($4)
991 ldc1 $f29, (4 * 36 + 8 * 29)($4)
992 ldc1 $f30, (4 * 36 + 8 * 30)($4)
993 ldc1 $f31, (4 * 36 + 8 * 31)($4)
994#endif
995#endif
996#if __mips_isa_rev < 6
997 // restore hi and lo
998 lw $8, (4 * 33)($4)
999 mthi $8
1000 lw $8, (4 * 34)($4)
1001 mtlo $8
1002#endif
1003 // r0 is zero
1004 lw $1, (4 * 1)($4)
1005 lw $2, (4 * 2)($4)
1006 lw $3, (4 * 3)($4)
1007 // skip a0 for now
1008 lw $5, (4 * 5)($4)
1009 lw $6, (4 * 6)($4)
1010 lw $7, (4 * 7)($4)
1011 lw $8, (4 * 8)($4)
1012 lw $9, (4 * 9)($4)
1013 lw $10, (4 * 10)($4)
1014 lw $11, (4 * 11)($4)
1015 lw $12, (4 * 12)($4)
1016 lw $13, (4 * 13)($4)
1017 lw $14, (4 * 14)($4)
1018 lw $15, (4 * 15)($4)
1019 lw $16, (4 * 16)($4)
1020 lw $17, (4 * 17)($4)
1021 lw $18, (4 * 18)($4)
1022 lw $19, (4 * 19)($4)
1023 lw $20, (4 * 20)($4)
1024 lw $21, (4 * 21)($4)
1025 lw $22, (4 * 22)($4)
1026 lw $23, (4 * 23)($4)
1027 lw $24, (4 * 24)($4)
1028 lw $25, (4 * 25)($4)
1029 lw $26, (4 * 26)($4)
1030 lw $27, (4 * 27)($4)
1031 lw $28, (4 * 28)($4)
1032 lw $29, (4 * 29)($4)
1033 lw $30, (4 * 30)($4)
1034 // load new pc into ra
1035 lw $31, (4 * 32)($4)
1036 // jump to ra, load a0 in the delay slot
1037 jr $31
1038 lw $4, (4 * 4)($4)
1039 .set pop
1040
1041#elif defined(__mips64)
1042
1043//
1044// void libunwind::Registers_mips_newabi::jumpto()
1045//
1046// On entry:
1047// thread state pointer is in a0 ($4)
1048//
1049DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind21Registers_mips_newabi6jumptoEv)
1050 .set push
1051 .set noat
1052 .set noreorder
1053 .set nomacro
1054#ifdef __mips_hard_float
1055 .irp i,FROM_0_TO_31
1056 ldc1 $f\i, (280+8*\i)($4)
1057 .endr
1058#endif
1059#if __mips_isa_rev < 6
1060 // restore hi and lo
1061 ld $8, (8 * 33)($4)
1062 mthi $8
1063 ld $8, (8 * 34)($4)
1064 mtlo $8
1065#endif
1066 // r0 is zero
1067 ld $1, (8 * 1)($4)
1068 ld $2, (8 * 2)($4)
1069 ld $3, (8 * 3)($4)
1070 // skip a0 for now
1071 .irp i,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30
1072 ld $\i, (8 * \i)($4)
1073 .endr
1074 // load new pc into ra
1075 ld $31, (8 * 32)($4)
1076 // jump to ra, load a0 in the delay slot
1077 jr $31
1078 ld $4, (8 * 4)($4)
1079 .set pop
1080
1081#elif defined(__sparc__) && defined(__arch64__)
1082
1083DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind17Registers_sparc646jumptoEv)
1084//
1085// void libunwind::Registers_sparc64::jumpto()
1086//
1087// On entry:
1088// thread_state pointer is in %o0
1089//
1090 .register %g2, #scratch
1091 .register %g3, #scratch
1092 .register %g6, #scratch
1093 .register %g7, #scratch
1094 flushw
1095 ldx [%o0 + 0x08], %g1
1096 ldx [%o0 + 0x10], %g2
1097 ldx [%o0 + 0x18], %g3
1098 ldx [%o0 + 0x20], %g4
1099 ldx [%o0 + 0x28], %g5
1100 ldx [%o0 + 0x30], %g6
1101 ldx [%o0 + 0x38], %g7
1102 ldx [%o0 + 0x48], %o1
1103 ldx [%o0 + 0x50], %o2
1104 ldx [%o0 + 0x58], %o3
1105 ldx [%o0 + 0x60], %o4
1106 ldx [%o0 + 0x68], %o5
1107 ldx [%o0 + 0x70], %o6
1108 ldx [%o0 + 0x78], %o7
1109 ldx [%o0 + 0x80], %l0
1110 ldx [%o0 + 0x88], %l1
1111 ldx [%o0 + 0x90], %l2
1112 ldx [%o0 + 0x98], %l3
1113 ldx [%o0 + 0xa0], %l4
1114 ldx [%o0 + 0xa8], %l5
1115 ldx [%o0 + 0xb0], %l6
1116 ldx [%o0 + 0xb8], %l7
1117 ldx [%o0 + 0xc0], %i0
1118 ldx [%o0 + 0xc8], %i1
1119 ldx [%o0 + 0xd0], %i2
1120 ldx [%o0 + 0xd8], %i3
1121 ldx [%o0 + 0xe0], %i4
1122 ldx [%o0 + 0xe8], %i5
1123 ldx [%o0 + 0xf0], %i6
1124 ldx [%o0 + 0xf8], %i7
1125 jmp %o7
1126 ldx [%o0 + 0x40], %o0
1127
1128#elif defined(__sparc__)
1129
1130//
1131// void libunwind::Registers_sparc_o32::jumpto()
1132//
1133// On entry:
1134// thread_state pointer is in o0
1135//
1136DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_sparc6jumptoEv)
1137 ta 3
1138 ldd [%o0 + 64], %l0
1139 ldd [%o0 + 72], %l2
1140 ldd [%o0 + 80], %l4
1141 ldd [%o0 + 88], %l6
1142 ldd [%o0 + 96], %i0
1143 ldd [%o0 + 104], %i2
1144 ldd [%o0 + 112], %i4
1145 ldd [%o0 + 120], %i6
1146 ld [%o0 + 60], %o7
1147 jmp %o7
1148 nop
1149
1150#elif defined(__riscv)
1151
1152//
1153// void libunwind::Registers_riscv::jumpto()
1154//
1155// On entry:
1156// thread_state pointer is in a0
1157//
1158 .p2align 2
1159DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_riscv6jumptoEv)
1160# if defined(__riscv_flen)
1161 .irp i,FROM_0_TO_31
1162 FLOAD f\i, (RISCV_FOFFSET + RISCV_FSIZE * \i)(a0)
1163 .endr
1164# endif
1165
1166 // x0 is zero
1167 ILOAD x1, (RISCV_ISIZE * 0)(a0) // restore pc into ra
1168 .irp i,2,3,4,5,6,7,8,9
1169 ILOAD x\i, (RISCV_ISIZE * \i)(a0)
1170 .endr
1171 // skip a0 for now
1172 .irp i,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
1173 ILOAD x\i, (RISCV_ISIZE * \i)(a0)
1174 .endr
1175 ILOAD x10, (RISCV_ISIZE * 10)(a0) // restore a0
1176
1177 ret // jump to ra
1178
1179#elif defined(__s390x__)
1180
1181DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_s390x6jumptoEv)
1182//
1183// void libunwind::Registers_s390x::jumpto()
1184//
1185// On entry:
1186// thread_state pointer is in r2
1187//
1188
1189 // Skip PSWM, but load PSWA into r1
1190 lg %r1, 8(%r2)
1191
1192 // Restore FPRs
1193 .irp i,FROM_0_TO_15
1194 ld %f\i, (144+8*\i)(%r2)
1195 .endr
1196
1197 // Restore GPRs - skipping %r0 and %r1
1198 lmg %r2, %r15, 32(%r2)
1199
1200 // Return to PSWA (was loaded into %r1 above)
1201 br %r1
1202
1203#elif defined(__loongarch__) && __loongarch_grlen == 64
1204
1205//
1206// void libunwind::Registers_loongarch::jumpto()
1207//
1208// On entry:
1209// thread_state pointer is in $a0($r4)
1210//
1211 .p2align 2
1212DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind19Registers_loongarch6jumptoEv)
1213# if __loongarch_frlen == 64
1214 .irp i,FROM_0_TO_31
1215 fld.d $f\i, $a0, (8 * 33 + 8 * \i)
1216 .endr
1217# endif
1218
1219 // $r0 is zero
1220 .irp i,1,2,3
1221 ld.d $r\i, $a0, (8 * \i)
1222 .endr
1223 // skip $a0 for now
1224 .irp i,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
1225 ld.d $r\i, $a0, (8 * \i)
1226 .endr
1227
1228 ld.d $ra, $a0, (8 * 32) // load new pc into $ra
1229 ld.d $a0, $a0, (8 * 4) // restore $a0 last
1230
1231 jr $ra
1232
1233#endif
1234
1235#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */
1236
1237NO_EXEC_STACK_DIRECTIVE
1238
1239

source code of libunwind/src/UnwindRegistersRestore.S