xref: /freebsd-src/contrib/llvm-project/libunwind/src/UnwindRegistersRestore.S (revision 62987288060ff68c817b7056815aa9fb8ba8ecd7)
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__) && !defined(__wasm__)
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#if defined(__ARM_FEATURE_GCS_DEFAULT)
633.arch_extension gcs
634#endif
635
636//
637// extern "C" void __libunwind_Registers_arm64_jumpto(Registers_arm64 *);
638//
639// On entry:
640//  thread_state pointer is in x0
641//
642  .p2align 2
643DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto)
644  // skip restore of x0,x1 for now
645  ldp    x2, x3,  [x0, #0x010]
646  ldp    x4, x5,  [x0, #0x020]
647  ldp    x6, x7,  [x0, #0x030]
648  ldp    x8, x9,  [x0, #0x040]
649  ldp    x10,x11, [x0, #0x050]
650  ldp    x12,x13, [x0, #0x060]
651  ldp    x14,x15, [x0, #0x070]
652  // x16 and x17 were clobbered by the call into the unwinder, so no point in
653  // restoring them.
654  ldp    x18,x19, [x0, #0x090]
655  ldp    x20,x21, [x0, #0x0A0]
656  ldp    x22,x23, [x0, #0x0B0]
657  ldp    x24,x25, [x0, #0x0C0]
658  ldp    x26,x27, [x0, #0x0D0]
659  ldp    x28,x29, [x0, #0x0E0]
660  ldr    x30,     [x0, #0x100]  // restore pc into lr
661
662  ldp    d0, d1,  [x0, #0x110]
663  ldp    d2, d3,  [x0, #0x120]
664  ldp    d4, d5,  [x0, #0x130]
665  ldp    d6, d7,  [x0, #0x140]
666  ldp    d8, d9,  [x0, #0x150]
667  ldp    d10,d11, [x0, #0x160]
668  ldp    d12,d13, [x0, #0x170]
669  ldp    d14,d15, [x0, #0x180]
670  ldp    d16,d17, [x0, #0x190]
671  ldp    d18,d19, [x0, #0x1A0]
672  ldp    d20,d21, [x0, #0x1B0]
673  ldp    d22,d23, [x0, #0x1C0]
674  ldp    d24,d25, [x0, #0x1D0]
675  ldp    d26,d27, [x0, #0x1E0]
676  ldp    d28,d29, [x0, #0x1F0]
677  ldr    d30,     [x0, #0x200]
678  ldr    d31,     [x0, #0x208]
679
680  // Finally, restore sp. This must be done after the last read from the
681  // context struct, because it is allocated on the stack, and an exception
682  // could clobber the de-allocated portion of the stack after sp has been
683  // restored.
684  ldr    x16,     [x0, #0x0F8]
685  ldp    x0, x1,  [x0, #0x000]  // restore x0,x1
686  mov    sp,x16                 // restore sp
687#if defined(__ARM_FEATURE_GCS_DEFAULT)
688  // If GCS is enabled we need to push the address we're returning to onto the
689  // GCS stack. We can't just return using br, as there won't be a BTI landing
690  // pad instruction at the destination.
691  mov      x16, #1
692  chkfeat  x16
693  cbnz     x16, Lnogcs
694  gcspushm x30
695Lnogcs:
696#endif
697  ret    x30                    // jump to pc
698
699#elif defined(__arm__) && !defined(__APPLE__)
700
701#if !defined(__ARM_ARCH_ISA_ARM)
702#if (__ARM_ARCH_ISA_THUMB == 2)
703  .syntax unified
704#endif
705  .thumb
706#endif
707
708@
709@ void libunwind::Registers_arm::restoreCoreAndJumpTo()
710@
711@ On entry:
712@  thread_state pointer is in r0
713@
714  .p2align 2
715DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm20restoreCoreAndJumpToEv)
716#if !defined(__ARM_ARCH_ISA_ARM) && __ARM_ARCH_ISA_THUMB == 1
717  @ r8-r11: ldm into r1-r4, then mov to r8-r11
718  adds r0, #0x20
719  ldm r0!, {r1-r4}
720  subs r0, #0x30
721  mov r8, r1
722  mov r9, r2
723  mov r10, r3
724  mov r11, r4
725  @ r12 does not need loading, it it the intra-procedure-call scratch register
726  ldr r2, [r0, #0x34]
727  ldr r3, [r0, #0x3c]
728  mov sp, r2
729  mov lr, r3         @ restore pc into lr
730  ldm r0, {r0-r7}
731#else
732  @ Use lr as base so that r0 can be restored.
733  mov lr, r0
734  @ 32bit thumb-2 restrictions for ldm:
735  @ . the sp (r13) cannot be in the list
736  @ . the pc (r15) and lr (r14) cannot both be in the list in an LDM instruction
737  ldm lr, {r0-r12}
738  ldr sp, [lr, #52]
739  ldr lr, [lr, #60]  @ restore pc into lr
740#endif
741#if defined(__ARM_FEATURE_BTI_DEFAULT) && !defined(__ARM_ARCH_ISA_ARM)
742  // 'bx' is not BTI setting when used with lr, therefore r12 is used instead
743  mov r12, lr
744  JMP(r12)
745#else
746  JMP(lr)
747#endif
748
749@
750@ static void libunwind::Registers_arm::restoreVFPWithFLDMD(unw_fpreg_t* values)
751@
752@ On entry:
753@  values pointer is in r0
754@
755  .p2align 2
756#if defined(__ELF__)
757  .fpu vfpv3-d16
758#endif
759DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFLDMDEPv)
760  @ VFP and iwMMX instructions are only available when compiling with the flags
761  @ that enable them. We do not want to do that in the library (because we do not
762  @ want the compiler to generate instructions that access those) but this is
763  @ only accessed if the personality routine needs these registers. Use of
764  @ these registers implies they are, actually, available on the target, so
765  @ it's ok to execute.
766  @ So, generate the instruction using the corresponding coprocessor mnemonic.
767  vldmia r0, {d0-d15}
768  JMP(lr)
769
770@
771@ static void libunwind::Registers_arm::restoreVFPWithFLDMX(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-d16
779#endif
780DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFLDMXEPv)
781  vldmia r0, {d0-d15} @ fldmiax is deprecated in ARMv7+ and now behaves like vldmia
782  JMP(lr)
783
784@
785@ static void libunwind::Registers_arm::restoreVFPv3(unw_fpreg_t* values)
786@
787@ On entry:
788@  values pointer is in r0
789@
790  .p2align 2
791#if defined(__ELF__)
792  .fpu vfpv3
793#endif
794DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm12restoreVFPv3EPv)
795  vldmia r0, {d16-d31}
796  JMP(lr)
797
798#if defined(__ARM_WMMX)
799
800@
801@ static void libunwind::Registers_arm::restoreiWMMX(unw_fpreg_t* values)
802@
803@ On entry:
804@  values pointer is in r0
805@
806  .p2align 2
807#if defined(__ELF__)
808  .arch armv5te
809#endif
810DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm12restoreiWMMXEPv)
811  ldcl p1, cr0, [r0], #8  @ wldrd wR0, [r0], #8
812  ldcl p1, cr1, [r0], #8  @ wldrd wR1, [r0], #8
813  ldcl p1, cr2, [r0], #8  @ wldrd wR2, [r0], #8
814  ldcl p1, cr3, [r0], #8  @ wldrd wR3, [r0], #8
815  ldcl p1, cr4, [r0], #8  @ wldrd wR4, [r0], #8
816  ldcl p1, cr5, [r0], #8  @ wldrd wR5, [r0], #8
817  ldcl p1, cr6, [r0], #8  @ wldrd wR6, [r0], #8
818  ldcl p1, cr7, [r0], #8  @ wldrd wR7, [r0], #8
819  ldcl p1, cr8, [r0], #8  @ wldrd wR8, [r0], #8
820  ldcl p1, cr9, [r0], #8  @ wldrd wR9, [r0], #8
821  ldcl p1, cr10, [r0], #8  @ wldrd wR10, [r0], #8
822  ldcl p1, cr11, [r0], #8  @ wldrd wR11, [r0], #8
823  ldcl p1, cr12, [r0], #8  @ wldrd wR12, [r0], #8
824  ldcl p1, cr13, [r0], #8  @ wldrd wR13, [r0], #8
825  ldcl p1, cr14, [r0], #8  @ wldrd wR14, [r0], #8
826  ldcl p1, cr15, [r0], #8  @ wldrd wR15, [r0], #8
827  JMP(lr)
828
829@
830@ static void libunwind::Registers_arm::restoreiWMMXControl(unw_uint32_t* values)
831@
832@ On entry:
833@  values pointer is in r0
834@
835  .p2align 2
836#if defined(__ELF__)
837  .arch armv5te
838#endif
839DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm19restoreiWMMXControlEPj)
840  ldc2 p1, cr8, [r0], #4  @ wldrw wCGR0, [r0], #4
841  ldc2 p1, cr9, [r0], #4  @ wldrw wCGR1, [r0], #4
842  ldc2 p1, cr10, [r0], #4  @ wldrw wCGR2, [r0], #4
843  ldc2 p1, cr11, [r0], #4  @ wldrw wCGR3, [r0], #4
844  JMP(lr)
845
846#endif
847
848#elif defined(__or1k__)
849
850DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv)
851#
852# void libunwind::Registers_or1k::jumpto()
853#
854# On entry:
855#  thread_state pointer is in r3
856#
857
858  # restore integral registers
859  l.lwz     r0,  0(r3)
860  l.lwz     r1,  4(r3)
861  l.lwz     r2,  8(r3)
862  # skip r3 for now
863  l.lwz     r4, 16(r3)
864  l.lwz     r5, 20(r3)
865  l.lwz     r6, 24(r3)
866  l.lwz     r7, 28(r3)
867  l.lwz     r8, 32(r3)
868  # skip r9
869  l.lwz    r10, 40(r3)
870  l.lwz    r11, 44(r3)
871  l.lwz    r12, 48(r3)
872  l.lwz    r13, 52(r3)
873  l.lwz    r14, 56(r3)
874  l.lwz    r15, 60(r3)
875  l.lwz    r16, 64(r3)
876  l.lwz    r17, 68(r3)
877  l.lwz    r18, 72(r3)
878  l.lwz    r19, 76(r3)
879  l.lwz    r20, 80(r3)
880  l.lwz    r21, 84(r3)
881  l.lwz    r22, 88(r3)
882  l.lwz    r23, 92(r3)
883  l.lwz    r24, 96(r3)
884  l.lwz    r25,100(r3)
885  l.lwz    r26,104(r3)
886  l.lwz    r27,108(r3)
887  l.lwz    r28,112(r3)
888  l.lwz    r29,116(r3)
889  l.lwz    r30,120(r3)
890  l.lwz    r31,124(r3)
891
892  # load new pc into ra
893  l.lwz    r9, 128(r3)
894
895  # at last, restore r3
896  l.lwz    r3,  12(r3)
897
898  # jump to pc
899  l.jr     r9
900   l.nop
901
902#elif defined(__hexagon__)
903# On entry:
904#  thread_state pointer is in r2
905DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind17Registers_hexagon6jumptoEv)
906#
907# void libunwind::Registers_hexagon::jumpto()
908#
909  r8 = memw(r0+#32)
910  r9 = memw(r0+#36)
911  r10 = memw(r0+#40)
912  r11 = memw(r0+#44)
913
914  r12 = memw(r0+#48)
915  r13 = memw(r0+#52)
916  r14 = memw(r0+#56)
917  r15 = memw(r0+#60)
918
919  r16 = memw(r0+#64)
920  r17 = memw(r0+#68)
921  r18 = memw(r0+#72)
922  r19 = memw(r0+#76)
923
924  r20 = memw(r0+#80)
925  r21 = memw(r0+#84)
926  r22 = memw(r0+#88)
927  r23 = memw(r0+#92)
928
929  r24 = memw(r0+#96)
930  r25 = memw(r0+#100)
931  r26 = memw(r0+#104)
932  r27 = memw(r0+#108)
933
934  r28 = memw(r0+#112)
935  r29 = memw(r0+#116)
936  r30 = memw(r0+#120)
937  r31 = memw(r0+#132)
938
939  r1 = memw(r0+#128)
940  c4 = r1   // Predicate register
941  r1 = memw(r0+#4)
942  r0 = memw(r0)
943  jumpr r31
944#elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32
945
946//
947// void libunwind::Registers_mips_o32::jumpto()
948//
949// On entry:
950//  thread state pointer is in a0 ($4)
951//
952DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind18Registers_mips_o326jumptoEv)
953  .set push
954  .set noat
955  .set noreorder
956  .set nomacro
957#ifdef __mips_hard_float
958#if __mips_fpr != 64
959  ldc1  $f0, (4 * 36 + 8 * 0)($4)
960  ldc1  $f2, (4 * 36 + 8 * 2)($4)
961  ldc1  $f4, (4 * 36 + 8 * 4)($4)
962  ldc1  $f6, (4 * 36 + 8 * 6)($4)
963  ldc1  $f8, (4 * 36 + 8 * 8)($4)
964  ldc1  $f10, (4 * 36 + 8 * 10)($4)
965  ldc1  $f12, (4 * 36 + 8 * 12)($4)
966  ldc1  $f14, (4 * 36 + 8 * 14)($4)
967  ldc1  $f16, (4 * 36 + 8 * 16)($4)
968  ldc1  $f18, (4 * 36 + 8 * 18)($4)
969  ldc1  $f20, (4 * 36 + 8 * 20)($4)
970  ldc1  $f22, (4 * 36 + 8 * 22)($4)
971  ldc1  $f24, (4 * 36 + 8 * 24)($4)
972  ldc1  $f26, (4 * 36 + 8 * 26)($4)
973  ldc1  $f28, (4 * 36 + 8 * 28)($4)
974  ldc1  $f30, (4 * 36 + 8 * 30)($4)
975#else
976  ldc1  $f0, (4 * 36 + 8 * 0)($4)
977  ldc1  $f1, (4 * 36 + 8 * 1)($4)
978  ldc1  $f2, (4 * 36 + 8 * 2)($4)
979  ldc1  $f3, (4 * 36 + 8 * 3)($4)
980  ldc1  $f4, (4 * 36 + 8 * 4)($4)
981  ldc1  $f5, (4 * 36 + 8 * 5)($4)
982  ldc1  $f6, (4 * 36 + 8 * 6)($4)
983  ldc1  $f7, (4 * 36 + 8 * 7)($4)
984  ldc1  $f8, (4 * 36 + 8 * 8)($4)
985  ldc1  $f9, (4 * 36 + 8 * 9)($4)
986  ldc1  $f10, (4 * 36 + 8 * 10)($4)
987  ldc1  $f11, (4 * 36 + 8 * 11)($4)
988  ldc1  $f12, (4 * 36 + 8 * 12)($4)
989  ldc1  $f13, (4 * 36 + 8 * 13)($4)
990  ldc1  $f14, (4 * 36 + 8 * 14)($4)
991  ldc1  $f15, (4 * 36 + 8 * 15)($4)
992  ldc1  $f16, (4 * 36 + 8 * 16)($4)
993  ldc1  $f17, (4 * 36 + 8 * 17)($4)
994  ldc1  $f18, (4 * 36 + 8 * 18)($4)
995  ldc1  $f19, (4 * 36 + 8 * 19)($4)
996  ldc1  $f20, (4 * 36 + 8 * 20)($4)
997  ldc1  $f21, (4 * 36 + 8 * 21)($4)
998  ldc1  $f22, (4 * 36 + 8 * 22)($4)
999  ldc1  $f23, (4 * 36 + 8 * 23)($4)
1000  ldc1  $f24, (4 * 36 + 8 * 24)($4)
1001  ldc1  $f25, (4 * 36 + 8 * 25)($4)
1002  ldc1  $f26, (4 * 36 + 8 * 26)($4)
1003  ldc1  $f27, (4 * 36 + 8 * 27)($4)
1004  ldc1  $f28, (4 * 36 + 8 * 28)($4)
1005  ldc1  $f29, (4 * 36 + 8 * 29)($4)
1006  ldc1  $f30, (4 * 36 + 8 * 30)($4)
1007  ldc1  $f31, (4 * 36 + 8 * 31)($4)
1008#endif
1009#endif
1010#if __mips_isa_rev < 6
1011  // restore hi and lo
1012  lw    $8, (4 * 33)($4)
1013  mthi  $8
1014  lw    $8, (4 * 34)($4)
1015  mtlo  $8
1016#endif
1017  // r0 is zero
1018  lw    $1, (4 * 1)($4)
1019  lw    $2, (4 * 2)($4)
1020  lw    $3, (4 * 3)($4)
1021  // skip a0 for now
1022  lw    $5, (4 * 5)($4)
1023  lw    $6, (4 * 6)($4)
1024  lw    $7, (4 * 7)($4)
1025  lw    $8, (4 * 8)($4)
1026  lw    $9, (4 * 9)($4)
1027  lw    $10, (4 * 10)($4)
1028  lw    $11, (4 * 11)($4)
1029  lw    $12, (4 * 12)($4)
1030  lw    $13, (4 * 13)($4)
1031  lw    $14, (4 * 14)($4)
1032  lw    $15, (4 * 15)($4)
1033  lw    $16, (4 * 16)($4)
1034  lw    $17, (4 * 17)($4)
1035  lw    $18, (4 * 18)($4)
1036  lw    $19, (4 * 19)($4)
1037  lw    $20, (4 * 20)($4)
1038  lw    $21, (4 * 21)($4)
1039  lw    $22, (4 * 22)($4)
1040  lw    $23, (4 * 23)($4)
1041  lw    $24, (4 * 24)($4)
1042  lw    $25, (4 * 25)($4)
1043  lw    $26, (4 * 26)($4)
1044  lw    $27, (4 * 27)($4)
1045  lw    $28, (4 * 28)($4)
1046  lw    $29, (4 * 29)($4)
1047  lw    $30, (4 * 30)($4)
1048  // load new pc into ra
1049  lw    $31, (4 * 32)($4)
1050  // jump to ra, load a0 in the delay slot
1051  jr    $31
1052  lw    $4, (4 * 4)($4)
1053  .set pop
1054
1055#elif defined(__mips64)
1056
1057//
1058// void libunwind::Registers_mips_newabi::jumpto()
1059//
1060// On entry:
1061//  thread state pointer is in a0 ($4)
1062//
1063DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind21Registers_mips_newabi6jumptoEv)
1064  .set push
1065  .set noat
1066  .set noreorder
1067  .set nomacro
1068#ifdef __mips_hard_float
1069  .irp i,FROM_0_TO_31
1070    ldc1 $f\i, (280+8*\i)($4)
1071  .endr
1072#endif
1073#if __mips_isa_rev < 6
1074  // restore hi and lo
1075  ld    $8, (8 * 33)($4)
1076  mthi  $8
1077  ld    $8, (8 * 34)($4)
1078  mtlo  $8
1079#endif
1080  // r0 is zero
1081  ld    $1, (8 * 1)($4)
1082  ld    $2, (8 * 2)($4)
1083  ld    $3, (8 * 3)($4)
1084  // skip a0 for now
1085  .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
1086    ld $\i, (8 * \i)($4)
1087  .endr
1088  // load new pc into ra
1089  ld    $31, (8 * 32)($4)
1090  // jump to ra, load a0 in the delay slot
1091  jr    $31
1092  ld    $4, (8 * 4)($4)
1093  .set pop
1094
1095#elif defined(__sparc__) && defined(__arch64__)
1096
1097DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind17Registers_sparc646jumptoEv)
1098//
1099// void libunwind::Registers_sparc64::jumpto()
1100//
1101// On entry:
1102//  thread_state pointer is in %o0
1103//
1104  .register %g2, #scratch
1105  .register %g3, #scratch
1106  .register %g6, #scratch
1107  .register %g7, #scratch
1108  flushw
1109  ldx  [%o0 + 0x08], %g1
1110  ldx  [%o0 + 0x10], %g2
1111  ldx  [%o0 + 0x18], %g3
1112  ldx  [%o0 + 0x20], %g4
1113  ldx  [%o0 + 0x28], %g5
1114  ldx  [%o0 + 0x30], %g6
1115  ldx  [%o0 + 0x38], %g7
1116  ldx  [%o0 + 0x48], %o1
1117  ldx  [%o0 + 0x50], %o2
1118  ldx  [%o0 + 0x58], %o3
1119  ldx  [%o0 + 0x60], %o4
1120  ldx  [%o0 + 0x68], %o5
1121  ldx  [%o0 + 0x70], %o6
1122  ldx  [%o0 + 0x78], %o7
1123  ldx  [%o0 + 0x80], %l0
1124  ldx  [%o0 + 0x88], %l1
1125  ldx  [%o0 + 0x90], %l2
1126  ldx  [%o0 + 0x98], %l3
1127  ldx  [%o0 + 0xa0], %l4
1128  ldx  [%o0 + 0xa8], %l5
1129  ldx  [%o0 + 0xb0], %l6
1130  ldx  [%o0 + 0xb8], %l7
1131  ldx  [%o0 + 0xc0], %i0
1132  ldx  [%o0 + 0xc8], %i1
1133  ldx  [%o0 + 0xd0], %i2
1134  ldx  [%o0 + 0xd8], %i3
1135  ldx  [%o0 + 0xe0], %i4
1136  ldx  [%o0 + 0xe8], %i5
1137  ldx  [%o0 + 0xf0], %i6
1138  ldx  [%o0 + 0xf8], %i7
1139  jmp  %o7
1140   ldx [%o0 + 0x40], %o0
1141
1142#elif defined(__sparc__)
1143
1144//
1145// void libunwind::Registers_sparc_o32::jumpto()
1146//
1147// On entry:
1148//  thread_state pointer is in o0
1149//
1150DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_sparc6jumptoEv)
1151  ta 3
1152  ldd [%o0 + 64],  %l0
1153  ldd [%o0 + 72],  %l2
1154  ldd [%o0 + 80],  %l4
1155  ldd [%o0 + 88],  %l6
1156  ldd [%o0 + 96],  %i0
1157  ldd [%o0 + 104], %i2
1158  ldd [%o0 + 112], %i4
1159  ldd [%o0 + 120], %i6
1160  ld  [%o0 + 60],  %o7
1161  jmp %o7
1162   nop
1163
1164#elif defined(__riscv)
1165
1166//
1167// void libunwind::Registers_riscv::jumpto()
1168//
1169// On entry:
1170//  thread_state pointer is in a0
1171//
1172  .p2align 2
1173DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_riscv6jumptoEv)
1174# if defined(__riscv_flen)
1175  .irp i,FROM_0_TO_31
1176    FLOAD f\i, (RISCV_FOFFSET + RISCV_FSIZE * \i)(a0)
1177  .endr
1178# endif
1179
1180  // x0 is zero
1181  ILOAD    x1, (RISCV_ISIZE * 0)(a0) // restore pc into ra
1182  .irp i,2,3,4,5,6,7,8,9
1183    ILOAD x\i, (RISCV_ISIZE * \i)(a0)
1184  .endr
1185  // skip a0 for now
1186  .irp i,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
1187    ILOAD x\i, (RISCV_ISIZE * \i)(a0)
1188  .endr
1189  ILOAD    x10, (RISCV_ISIZE * 10)(a0)   // restore a0
1190
1191  ret                       // jump to ra
1192
1193#elif defined(__s390x__)
1194
1195DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_s390x6jumptoEv)
1196//
1197// void libunwind::Registers_s390x::jumpto()
1198//
1199// On entry:
1200//  thread_state pointer is in r2
1201//
1202
1203  // Skip PSWM, but load PSWA into r1
1204  lg %r1, 8(%r2)
1205
1206  // Restore FPRs
1207  .irp i,FROM_0_TO_15
1208    ld %f\i, (144+8*\i)(%r2)
1209  .endr
1210
1211  // Restore GPRs - skipping %r0 and %r1
1212  lmg  %r2, %r15, 32(%r2)
1213
1214  // Return to PSWA (was loaded into %r1 above)
1215  br %r1
1216
1217#elif defined(__loongarch__) && __loongarch_grlen == 64
1218
1219//
1220// void libunwind::Registers_loongarch::jumpto()
1221//
1222// On entry:
1223//  thread_state pointer is in $a0($r4)
1224//
1225  .p2align 2
1226DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind19Registers_loongarch6jumptoEv)
1227# if __loongarch_frlen == 64
1228  .irp i,FROM_0_TO_31
1229    fld.d $f\i, $a0, (8 * 33 + 8 * \i)
1230  .endr
1231# endif
1232
1233  // $r0 is zero
1234  .irp i,1,2,3
1235    ld.d $r\i, $a0, (8 * \i)
1236  .endr
1237  // skip $a0 for now
1238  .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
1239    ld.d $r\i, $a0, (8 * \i)
1240  .endr
1241
1242  ld.d    $ra,  $a0, (8 * 32)  // load new pc into $ra
1243  ld.d    $a0,  $a0, (8 * 4)   // restore $a0 last
1244
1245  jr      $ra
1246
1247#endif
1248
1249#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__wasm__) */
1250
1251NO_EXEC_STACK_DIRECTIVE
1252
1253