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