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 r0
951DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind17Registers_hexagon6jumptoEv)
952#
953# void libunwind::Registers_hexagon::jumpto()
954#
955# The context layout is hexagon_thread_state_t: unsigned int __r[35]
956# __r[0..31] = r0..r31, __r[32] = predicates, __r[33] = PC.
957# Offsets: __r[n] is at byte offset n*4. r0 is the context pointer, so
958# it is restored last; r31 is loaded with the saved PC as the jumpr target.
959 r2 = memw(r0+#8)
960 r3 = memw(r0+#12)
961 r4 = memw(r0+#16)
962 r5 = memw(r0+#20)
963 r6 = memw(r0+#24)
964 r7 = memw(r0+#28)
965
966 r8 = memw(r0+#32)
967 r9 = memw(r0+#36)
968 r10 = memw(r0+#40)
969 r11 = memw(r0+#44)
970
971 r12 = memw(r0+#48)
972 r13 = memw(r0+#52)
973 r14 = memw(r0+#56)
974 r15 = memw(r0+#60)
975
976 r16 = memw(r0+#64)
977 r17 = memw(r0+#68)
978 r18 = memw(r0+#72)
979 r19 = memw(r0+#76)
980
981 r20 = memw(r0+#80)
982 r21 = memw(r0+#84)
983 r22 = memw(r0+#88)
984 r23 = memw(r0+#92)
985
986 r24 = memw(r0+#96)
987 r25 = memw(r0+#100)
988 r26 = memw(r0+#104)
989 r27 = memw(r0+#108)
990
991 r28 = memw(r0+#112)
992 r29 = memw(r0+#116)
993 r30 = memw(r0+#120)
994 r31 = memw(r0+#132)
995
996 r1 = memw(r0+#128)
997 c4 = r1 // Predicate register
998 r1 = memw(r0+#4)
999 r0 = memw(r0)
1000 jumpr r31
1001#elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32
1002
1003//
1004// void libunwind::Registers_mips_o32::jumpto()
1005//
1006// On entry:
1007// thread state pointer is in a0 ($4)
1008//
1009DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind18Registers_mips_o326jumptoEv)
1010 .set push
1011 .set noat
1012 .set noreorder
1013 .set nomacro
1014#ifdef __mips_hard_float
1015#if __mips_fpr != 64
1016 ldc1 $f0, (4 * 36 + 8 * 0)($4)
1017 ldc1 $f2, (4 * 36 + 8 * 2)($4)
1018 ldc1 $f4, (4 * 36 + 8 * 4)($4)
1019 ldc1 $f6, (4 * 36 + 8 * 6)($4)
1020 ldc1 $f8, (4 * 36 + 8 * 8)($4)
1021 ldc1 $f10, (4 * 36 + 8 * 10)($4)
1022 ldc1 $f12, (4 * 36 + 8 * 12)($4)
1023 ldc1 $f14, (4 * 36 + 8 * 14)($4)
1024 ldc1 $f16, (4 * 36 + 8 * 16)($4)
1025 ldc1 $f18, (4 * 36 + 8 * 18)($4)
1026 ldc1 $f20, (4 * 36 + 8 * 20)($4)
1027 ldc1 $f22, (4 * 36 + 8 * 22)($4)
1028 ldc1 $f24, (4 * 36 + 8 * 24)($4)
1029 ldc1 $f26, (4 * 36 + 8 * 26)($4)
1030 ldc1 $f28, (4 * 36 + 8 * 28)($4)
1031 ldc1 $f30, (4 * 36 + 8 * 30)($4)
1032#else
1033 ldc1 $f0, (4 * 36 + 8 * 0)($4)
1034 ldc1 $f1, (4 * 36 + 8 * 1)($4)
1035 ldc1 $f2, (4 * 36 + 8 * 2)($4)
1036 ldc1 $f3, (4 * 36 + 8 * 3)($4)
1037 ldc1 $f4, (4 * 36 + 8 * 4)($4)
1038 ldc1 $f5, (4 * 36 + 8 * 5)($4)
1039 ldc1 $f6, (4 * 36 + 8 * 6)($4)
1040 ldc1 $f7, (4 * 36 + 8 * 7)($4)
1041 ldc1 $f8, (4 * 36 + 8 * 8)($4)
1042 ldc1 $f9, (4 * 36 + 8 * 9)($4)
1043 ldc1 $f10, (4 * 36 + 8 * 10)($4)
1044 ldc1 $f11, (4 * 36 + 8 * 11)($4)
1045 ldc1 $f12, (4 * 36 + 8 * 12)($4)
1046 ldc1 $f13, (4 * 36 + 8 * 13)($4)
1047 ldc1 $f14, (4 * 36 + 8 * 14)($4)
1048 ldc1 $f15, (4 * 36 + 8 * 15)($4)
1049 ldc1 $f16, (4 * 36 + 8 * 16)($4)
1050 ldc1 $f17, (4 * 36 + 8 * 17)($4)
1051 ldc1 $f18, (4 * 36 + 8 * 18)($4)
1052 ldc1 $f19, (4 * 36 + 8 * 19)($4)
1053 ldc1 $f20, (4 * 36 + 8 * 20)($4)
1054 ldc1 $f21, (4 * 36 + 8 * 21)($4)
1055 ldc1 $f22, (4 * 36 + 8 * 22)($4)
1056 ldc1 $f23, (4 * 36 + 8 * 23)($4)
1057 ldc1 $f24, (4 * 36 + 8 * 24)($4)
1058 ldc1 $f25, (4 * 36 + 8 * 25)($4)
1059 ldc1 $f26, (4 * 36 + 8 * 26)($4)
1060 ldc1 $f27, (4 * 36 + 8 * 27)($4)
1061 ldc1 $f28, (4 * 36 + 8 * 28)($4)
1062 ldc1 $f29, (4 * 36 + 8 * 29)($4)
1063 ldc1 $f30, (4 * 36 + 8 * 30)($4)
1064 ldc1 $f31, (4 * 36 + 8 * 31)($4)
1065#endif
1066#endif
1067#if __mips_isa_rev < 6
1068 // restore hi and lo
1069 lw $8, (4 * 33)($4)
1070 mthi $8
1071 lw $8, (4 * 34)($4)
1072 mtlo $8
1073#endif
1074 // r0 is zero
1075 lw $1, (4 * 1)($4)
1076 lw $2, (4 * 2)($4)
1077 lw $3, (4 * 3)($4)
1078 // skip a0 for now
1079 lw $5, (4 * 5)($4)
1080 lw $6, (4 * 6)($4)
1081 lw $7, (4 * 7)($4)
1082 lw $8, (4 * 8)($4)
1083 lw $9, (4 * 9)($4)
1084 lw $10, (4 * 10)($4)
1085 lw $11, (4 * 11)($4)
1086 lw $12, (4 * 12)($4)
1087 lw $13, (4 * 13)($4)
1088 lw $14, (4 * 14)($4)
1089 lw $15, (4 * 15)($4)
1090 lw $16, (4 * 16)($4)
1091 lw $17, (4 * 17)($4)
1092 lw $18, (4 * 18)($4)
1093 lw $19, (4 * 19)($4)
1094 lw $20, (4 * 20)($4)
1095 lw $21, (4 * 21)($4)
1096 lw $22, (4 * 22)($4)
1097 lw $23, (4 * 23)($4)
1098 lw $24, (4 * 24)($4)
1099 lw $25, (4 * 25)($4)
1100 lw $26, (4 * 26)($4)
1101 lw $27, (4 * 27)($4)
1102 lw $28, (4 * 28)($4)
1103 lw $29, (4 * 29)($4)
1104 // load new pc into ra
1105 lw $31, (4 * 32)($4)
1106 // MIPS 1 has load delay slot. Ensure lw $31 and jr are separated by an instruction.
1107 lw $30, (4 * 30)($4)
1108 // jump to ra, load a0 in the delay slot
1109 jr $31
1110 lw $4, (4 * 4)($4)
1111 .set pop
1112
1113#elif defined(__mips64)
1114
1115//
1116// void libunwind::Registers_mips_newabi::jumpto()
1117//
1118// On entry:
1119// thread state pointer is in a0 ($4)
1120//
1121DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind21Registers_mips_newabi6jumptoEv)
1122 .set push
1123 .set noat
1124 .set noreorder
1125 .set nomacro
1126#ifdef __mips_hard_float
1127 .irp i,FROM_0_TO_31
1128 ldc1 $f\i, (280+8*\i)($4)
1129 .endr
1130#endif
1131#if __mips_isa_rev < 6
1132 // restore hi and lo
1133 ld $8, (8 * 33)($4)
1134 mthi $8
1135 ld $8, (8 * 34)($4)
1136 mtlo $8
1137#endif
1138 // r0 is zero
1139 ld $1, (8 * 1)($4)
1140 ld $2, (8 * 2)($4)
1141 ld $3, (8 * 3)($4)
1142 // skip a0 for now
1143 .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
1144 ld $\i, (8 * \i)($4)
1145 .endr
1146 // load new pc into ra
1147 ld $31, (8 * 32)($4)
1148 // MIPS 1 has load delay slot. Ensure lw $31 and jr are separated by an instruction.
1149 ld $30, (8 * 30)($4)
1150 // jump to ra, load a0 in the delay slot
1151 jr $31
1152 ld $4, (8 * 4)($4)
1153 .set pop
1154
1155#elif defined(__sparc__) && defined(__arch64__)
1156
1157DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind17Registers_sparc646jumptoEv)
1158//
1159// void libunwind::Registers_sparc64::jumpto()
1160//
1161// On entry:
1162// thread_state pointer is in %o0
1163//
1164 .register %g2, #scratch
1165 .register %g3, #scratch
1166 .register %g6, #scratch
1167 .register %g7, #scratch
1168 flushw
1169 ldx [%o0 + 0x08], %g1
1170 ldx [%o0 + 0x10], %g2
1171 ldx [%o0 + 0x18], %g3
1172 ldx [%o0 + 0x20], %g4
1173 ldx [%o0 + 0x28], %g5
1174 ldx [%o0 + 0x30], %g6
1175 ldx [%o0 + 0x38], %g7
1176 ldx [%o0 + 0x48], %o1
1177 ldx [%o0 + 0x50], %o2
1178 ldx [%o0 + 0x58], %o3
1179 ldx [%o0 + 0x60], %o4
1180 ldx [%o0 + 0x68], %o5
1181 ldx [%o0 + 0x70], %o6
1182 ldx [%o0 + 0x78], %o7
1183 ldx [%o0 + 0x80], %l0
1184 ldx [%o0 + 0x88], %l1
1185 ldx [%o0 + 0x90], %l2
1186 ldx [%o0 + 0x98], %l3
1187 ldx [%o0 + 0xa0], %l4
1188 ldx [%o0 + 0xa8], %l5
1189 ldx [%o0 + 0xb0], %l6
1190 ldx [%o0 + 0xb8], %l7
1191 ldx [%o0 + 0xc0], %i0
1192 ldx [%o0 + 0xc8], %i1
1193 ldx [%o0 + 0xd0], %i2
1194 ldx [%o0 + 0xd8], %i3
1195 ldx [%o0 + 0xe0], %i4
1196 ldx [%o0 + 0xe8], %i5
1197 ldx [%o0 + 0xf0], %i6
1198 ldx [%o0 + 0xf8], %i7
1199 jmp %o7
1200 ldx [%o0 + 0x40], %o0
1201
1202#elif defined(__sparc__)
1203
1204//
1205// void libunwind::Registers_sparc_o32::jumpto()
1206//
1207// On entry:
1208// thread_state pointer is in o0
1209//
1210DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_sparc6jumptoEv)
1211 ta 3
1212 ldd [%o0 + 64], %l0
1213 ldd [%o0 + 72], %l2
1214 ldd [%o0 + 80], %l4
1215 ldd [%o0 + 88], %l6
1216 ldd [%o0 + 96], %i0
1217 ldd [%o0 + 104], %i2
1218 ldd [%o0 + 112], %i4
1219 ldd [%o0 + 120], %i6
1220 ld [%o0 + 60], %o7
1221 jmp %o7
1222 nop
1223
1224#elif defined(__riscv)
1225
1226//
1227// void libunwind::Registers_riscv::jumpto()
1228//
1229// On entry:
1230// thread_state pointer is in a0
1231//
1232 .p2align 2
1233DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_riscv6jumptoEv)
1234# if defined(__riscv_flen)
1235 .irp i,FROM_0_TO_31
1236 FLOAD f\i, (RISCV_FOFFSET + RISCV_FSIZE * \i)(a0)
1237 .endr
1238# endif
1239
1240 // x0 is zero
1241 ILOAD x1, (RISCV_ISIZE * 0)(a0) // restore pc into ra
1242 .irp i,2,3,4,5,6,7,8,9
1243 ILOAD x\i, (RISCV_ISIZE * \i)(a0)
1244 .endr
1245 // skip a0 for now
1246#if defined(__riscv_32e)
1247 .irp i,11,12,13,14,15
1248#else
1249 .irp i,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
1250#endif
1251 ILOAD x\i, (RISCV_ISIZE * \i)(a0)
1252 .endr
1253 ILOAD x10, (RISCV_ISIZE * 10)(a0) // restore a0
1254
1255 ret // jump to ra
1256
1257#elif defined(__s390x__)
1258
1259DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_s390x6jumptoEv)
1260//
1261// void libunwind::Registers_s390x::jumpto()
1262//
1263// On entry:
1264// thread_state pointer is in r2
1265//
1266
1267 // Skip PSWM, but load PSWA into r1
1268 lg %r1, 8(%r2)
1269
1270 // Restore FPRs
1271 .irp i,FROM_0_TO_15
1272 ld %f\i, (144+8*\i)(%r2)
1273 .endr
1274
1275 // Restore GPRs - skipping %r0 and %r1
1276 lmg %r2, %r15, 32(%r2)
1277
1278 // Return to PSWA (was loaded into %r1 above)
1279 br %r1
1280
1281#elif defined(__loongarch__) && __loongarch_grlen == 64
1282
1283//
1284// void libunwind::Registers_loongarch::jumpto()
1285//
1286// On entry:
1287// thread_state pointer is in $a0($r4)
1288//
1289 .p2align 2
1290DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind19Registers_loongarch6jumptoEv)
1291# if __loongarch_frlen == 64
1292 .irp i,FROM_0_TO_31
1293 fld.d $f\i, $a0, (8 * 33 + 8 * \i)
1294 .endr
1295# endif
1296
1297 // $r0 is zero
1298 .irp i,1,2,3
1299 ld.d $r\i, $a0, (8 * \i)
1300 .endr
1301 // skip $a0 for now
1302 .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
1303 ld.d $r\i, $a0, (8 * \i)
1304 .endr
1305
1306 ld.d $ra, $a0, (8 * 32) // load new pc into $ra
1307 ld.d $a0, $a0, (8 * 4) // restore $a0 last
1308
1309 jr $ra
1310
1311#endif
1312
1313#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */
1314
1315NO_EXEC_STACK_DIRECTIVE
1316
1317#endif /* !defined(__wasm__) */
1318