1//===-------------------- UnwindRegistersRestore.S ------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "assembly.h"
11
12  .text
13
14#if !defined(__USING_SJLJ_EXCEPTIONS__)
15
16#if defined(__i386__)
17DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_x866jumptoEv)
18#
19# void libunwind::Registers_x86::jumpto()
20#
21#if defined(_WIN32)
22# On windows, the 'this' pointer is passed in ecx instead of on the stack
23  movl   %ecx, %eax
24#else
25# On entry:
26#  +                       +
27#  +-----------------------+
28#  + thread_state pointer  +
29#  +-----------------------+
30#  + return address        +
31#  +-----------------------+   <-- SP
32#  +                       +
33  movl   4(%esp), %eax
34#endif
35  # set up eax and ret on new stack location
36  movl  28(%eax), %edx # edx holds new stack pointer
37  subl  $8,%edx
38  movl  %edx, 28(%eax)
39  movl  0(%eax), %ebx
40  movl  %ebx, 0(%edx)
41  movl  40(%eax), %ebx
42  movl  %ebx, 4(%edx)
43  # we now have ret and eax pushed onto where new stack will be
44  # restore all registers
45  movl   4(%eax), %ebx
46  movl   8(%eax), %ecx
47  movl  12(%eax), %edx
48  movl  16(%eax), %edi
49  movl  20(%eax), %esi
50  movl  24(%eax), %ebp
51  movl  28(%eax), %esp
52  # skip ss
53  # skip eflags
54  pop    %eax  # eax was already pushed on new stack
55  ret        # eip was already pushed on new stack
56  # skip cs
57  # skip ds
58  # skip es
59  # skip fs
60  # skip gs
61
62#elif defined(__x86_64__)
63
64DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind16Registers_x86_646jumptoEv)
65#
66# void libunwind::Registers_x86_64::jumpto()
67#
68# On entry, thread_state pointer is in rdi
69
70  movq  56(%rdi), %rax # rax holds new stack pointer
71  subq  $16, %rax
72  movq  %rax, 56(%rdi)
73  movq  32(%rdi), %rbx  # store new rdi on new stack
74  movq  %rbx, 0(%rax)
75  movq  128(%rdi), %rbx # store new rip on new stack
76  movq  %rbx, 8(%rax)
77  # restore all registers
78  movq    0(%rdi), %rax
79  movq    8(%rdi), %rbx
80  movq   16(%rdi), %rcx
81  movq   24(%rdi), %rdx
82  # restore rdi later
83  movq   40(%rdi), %rsi
84  movq   48(%rdi), %rbp
85  # restore rsp later
86  movq   64(%rdi), %r8
87  movq   72(%rdi), %r9
88  movq   80(%rdi), %r10
89  movq   88(%rdi), %r11
90  movq   96(%rdi), %r12
91  movq  104(%rdi), %r13
92  movq  112(%rdi), %r14
93  movq  120(%rdi), %r15
94  # skip rflags
95  # skip cs
96  # skip fs
97  # skip gs
98  movq  56(%rdi), %rsp  # cut back rsp to new location
99  pop    %rdi      # rdi was saved here earlier
100  ret            # rip was saved here
101
102
103#elif defined(__ppc__)
104
105DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_ppc6jumptoEv)
106;
107; void libunwind::Registers_ppc::jumpto()
108;
109; On entry:
110;  thread_state pointer is in r3
111;
112
113  ; restore integral registerrs
114  ; skip r0 for now
115  ; skip r1 for now
116  lwz     r2, 16(r3)
117  ; skip r3 for now
118  ; skip r4 for now
119  ; skip r5 for now
120  lwz     r6, 32(r3)
121  lwz     r7, 36(r3)
122  lwz     r8, 40(r3)
123  lwz     r9, 44(r3)
124  lwz    r10, 48(r3)
125  lwz    r11, 52(r3)
126  lwz    r12, 56(r3)
127  lwz    r13, 60(r3)
128  lwz    r14, 64(r3)
129  lwz    r15, 68(r3)
130  lwz    r16, 72(r3)
131  lwz    r17, 76(r3)
132  lwz    r18, 80(r3)
133  lwz    r19, 84(r3)
134  lwz    r20, 88(r3)
135  lwz    r21, 92(r3)
136  lwz    r22, 96(r3)
137  lwz    r23,100(r3)
138  lwz    r24,104(r3)
139  lwz    r25,108(r3)
140  lwz    r26,112(r3)
141  lwz    r27,116(r3)
142  lwz    r28,120(r3)
143  lwz    r29,124(r3)
144  lwz    r30,128(r3)
145  lwz    r31,132(r3)
146
147  ; restore float registers
148  lfd    f0, 160(r3)
149  lfd    f1, 168(r3)
150  lfd    f2, 176(r3)
151  lfd    f3, 184(r3)
152  lfd    f4, 192(r3)
153  lfd    f5, 200(r3)
154  lfd    f6, 208(r3)
155  lfd    f7, 216(r3)
156  lfd    f8, 224(r3)
157  lfd    f9, 232(r3)
158  lfd    f10,240(r3)
159  lfd    f11,248(r3)
160  lfd    f12,256(r3)
161  lfd    f13,264(r3)
162  lfd    f14,272(r3)
163  lfd    f15,280(r3)
164  lfd    f16,288(r3)
165  lfd    f17,296(r3)
166  lfd    f18,304(r3)
167  lfd    f19,312(r3)
168  lfd    f20,320(r3)
169  lfd    f21,328(r3)
170  lfd    f22,336(r3)
171  lfd    f23,344(r3)
172  lfd    f24,352(r3)
173  lfd    f25,360(r3)
174  lfd    f26,368(r3)
175  lfd    f27,376(r3)
176  lfd    f28,384(r3)
177  lfd    f29,392(r3)
178  lfd    f30,400(r3)
179  lfd    f31,408(r3)
180
181  ; restore vector registers if any are in use
182  lwz    r5,156(r3)  ; test VRsave
183  cmpwi  r5,0
184  beq    Lnovec
185
186  subi  r4,r1,16
187  rlwinm  r4,r4,0,0,27  ; mask low 4-bits
188  ; r4 is now a 16-byte aligned pointer into the red zone
189  ; the _vectorRegisters may not be 16-byte aligned so copy via red zone temp buffer
190
191
192#define LOAD_VECTOR_UNALIGNEDl(_index) \
193  andis.  r0,r5,(1<<(15-_index))  @\
194  beq    Ldone  ## _index     @\
195  lwz    r0, 424+_index*16(r3)  @\
196  stw    r0, 0(r4)        @\
197  lwz    r0, 424+_index*16+4(r3)  @\
198  stw    r0, 4(r4)        @\
199  lwz    r0, 424+_index*16+8(r3)  @\
200  stw    r0, 8(r4)        @\
201  lwz    r0, 424+_index*16+12(r3)@\
202  stw    r0, 12(r4)        @\
203  lvx    v ## _index,0,r4    @\
204Ldone  ## _index:
205
206#define LOAD_VECTOR_UNALIGNEDh(_index) \
207  andi.  r0,r5,(1<<(31-_index))  @\
208  beq    Ldone  ## _index    @\
209  lwz    r0, 424+_index*16(r3)  @\
210  stw    r0, 0(r4)        @\
211  lwz    r0, 424+_index*16+4(r3)  @\
212  stw    r0, 4(r4)        @\
213  lwz    r0, 424+_index*16+8(r3)  @\
214  stw    r0, 8(r4)        @\
215  lwz    r0, 424+_index*16+12(r3)@\
216  stw    r0, 12(r4)        @\
217  lvx    v ## _index,0,r4    @\
218  Ldone  ## _index:
219
220
221  LOAD_VECTOR_UNALIGNEDl(0)
222  LOAD_VECTOR_UNALIGNEDl(1)
223  LOAD_VECTOR_UNALIGNEDl(2)
224  LOAD_VECTOR_UNALIGNEDl(3)
225  LOAD_VECTOR_UNALIGNEDl(4)
226  LOAD_VECTOR_UNALIGNEDl(5)
227  LOAD_VECTOR_UNALIGNEDl(6)
228  LOAD_VECTOR_UNALIGNEDl(7)
229  LOAD_VECTOR_UNALIGNEDl(8)
230  LOAD_VECTOR_UNALIGNEDl(9)
231  LOAD_VECTOR_UNALIGNEDl(10)
232  LOAD_VECTOR_UNALIGNEDl(11)
233  LOAD_VECTOR_UNALIGNEDl(12)
234  LOAD_VECTOR_UNALIGNEDl(13)
235  LOAD_VECTOR_UNALIGNEDl(14)
236  LOAD_VECTOR_UNALIGNEDl(15)
237  LOAD_VECTOR_UNALIGNEDh(16)
238  LOAD_VECTOR_UNALIGNEDh(17)
239  LOAD_VECTOR_UNALIGNEDh(18)
240  LOAD_VECTOR_UNALIGNEDh(19)
241  LOAD_VECTOR_UNALIGNEDh(20)
242  LOAD_VECTOR_UNALIGNEDh(21)
243  LOAD_VECTOR_UNALIGNEDh(22)
244  LOAD_VECTOR_UNALIGNEDh(23)
245  LOAD_VECTOR_UNALIGNEDh(24)
246  LOAD_VECTOR_UNALIGNEDh(25)
247  LOAD_VECTOR_UNALIGNEDh(26)
248  LOAD_VECTOR_UNALIGNEDh(27)
249  LOAD_VECTOR_UNALIGNEDh(28)
250  LOAD_VECTOR_UNALIGNEDh(29)
251  LOAD_VECTOR_UNALIGNEDh(30)
252  LOAD_VECTOR_UNALIGNEDh(31)
253
254Lnovec:
255  lwz    r0, 136(r3) ; __cr
256  mtocrf  255,r0
257  lwz    r0, 148(r3) ; __ctr
258  mtctr  r0
259  lwz    r0, 0(r3)  ; __ssr0
260  mtctr  r0
261  lwz    r0, 8(r3)  ; do r0 now
262  lwz    r5,28(r3)  ; do r5 now
263  lwz    r4,24(r3)  ; do r4 now
264  lwz    r1,12(r3)  ; do sp now
265  lwz    r3,20(r3)  ; do r3 last
266  bctr
267
268#elif defined(__arm64__) || defined(__aarch64__)
269
270//
271// void libunwind::Registers_arm64::jumpto()
272//
273// On entry:
274//  thread_state pointer is in x0
275//
276  .p2align 2
277DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind15Registers_arm646jumptoEv)
278  // skip restore of x0,x1 for now
279  ldp    x2, x3,  [x0, #0x010]
280  ldp    x4, x5,  [x0, #0x020]
281  ldp    x6, x7,  [x0, #0x030]
282  ldp    x8, x9,  [x0, #0x040]
283  ldp    x10,x11, [x0, #0x050]
284  ldp    x12,x13, [x0, #0x060]
285  ldp    x14,x15, [x0, #0x070]
286  ldp    x16,x17, [x0, #0x080]
287  ldp    x18,x19, [x0, #0x090]
288  ldp    x20,x21, [x0, #0x0A0]
289  ldp    x22,x23, [x0, #0x0B0]
290  ldp    x24,x25, [x0, #0x0C0]
291  ldp    x26,x27, [x0, #0x0D0]
292  ldp    x28,x29, [x0, #0x0E0]
293  ldr    x30,     [x0, #0x100]  // restore pc into lr
294  ldr    x1,      [x0, #0x0F8]
295  mov    sp,x1                  // restore sp
296
297  ldp    d0, d1,  [x0, #0x110]
298  ldp    d2, d3,  [x0, #0x120]
299  ldp    d4, d5,  [x0, #0x130]
300  ldp    d6, d7,  [x0, #0x140]
301  ldp    d8, d9,  [x0, #0x150]
302  ldp    d10,d11, [x0, #0x160]
303  ldp    d12,d13, [x0, #0x170]
304  ldp    d14,d15, [x0, #0x180]
305  ldp    d16,d17, [x0, #0x190]
306  ldp    d18,d19, [x0, #0x1A0]
307  ldp    d20,d21, [x0, #0x1B0]
308  ldp    d22,d23, [x0, #0x1C0]
309  ldp    d24,d25, [x0, #0x1D0]
310  ldp    d26,d27, [x0, #0x1E0]
311  ldp    d28,d29, [x0, #0x1F0]
312  ldr    d30,     [x0, #0x200]
313  ldr    d31,     [x0, #0x208]
314
315  ldp    x0, x1,  [x0, #0x000]  // restore x0,x1
316  ret    x30                    // jump to pc
317
318#elif defined(__arm__) && !defined(__APPLE__)
319
320#if !defined(__ARM_ARCH_ISA_ARM)
321  .thumb
322#endif
323
324@
325@ void libunwind::Registers_arm::restoreCoreAndJumpTo()
326@
327@ On entry:
328@  thread_state pointer is in r0
329@
330  .p2align 2
331DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm20restoreCoreAndJumpToEv)
332#if !defined(__ARM_ARCH_ISA_ARM) && __ARM_ARCH_ISA_THUMB == 1
333  @ r8-r11: ldm into r1-r4, then mov to r8-r11
334  adds r0, #0x20
335  ldm r0!, {r1-r4}
336  subs r0, #0x30
337  mov r8, r1
338  mov r9, r2
339  mov r10, r3
340  mov r11, r4
341  @ r12 does not need loading, it it the intra-procedure-call scratch register
342  ldr r2, [r0, #0x34]
343  ldr r3, [r0, #0x3c]
344  mov sp, r2
345  mov lr, r3         @ restore pc into lr
346  ldm r0, {r0-r7}
347#else
348  @ Use lr as base so that r0 can be restored.
349  mov lr, r0
350  @ 32bit thumb-2 restrictions for ldm:
351  @ . the sp (r13) cannot be in the list
352  @ . the pc (r15) and lr (r14) cannot both be in the list in an LDM instruction
353  ldm lr, {r0-r12}
354  ldr sp, [lr, #52]
355  ldr lr, [lr, #60]  @ restore pc into lr
356#endif
357  JMP(lr)
358
359@
360@ static void libunwind::Registers_arm::restoreVFPWithFLDMD(unw_fpreg_t* values)
361@
362@ On entry:
363@  values pointer is in r0
364@
365  .p2align 2
366  .fpu vfpv3-d16
367DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFLDMDEPy)
368  @ VFP and iwMMX instructions are only available when compiling with the flags
369  @ that enable them. We do not want to do that in the library (because we do not
370  @ want the compiler to generate instructions that access those) but this is
371  @ only accessed if the personality routine needs these registers. Use of
372  @ these registers implies they are, actually, available on the target, so
373  @ it's ok to execute.
374  @ So, generate the instruction using the corresponding coprocessor mnemonic.
375  vldmia r0, {d0-d15}
376  JMP(lr)
377
378@
379@ static void libunwind::Registers_arm::restoreVFPWithFLDMX(unw_fpreg_t* values)
380@
381@ On entry:
382@  values pointer is in r0
383@
384  .p2align 2
385  .fpu vfpv3-d16
386DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFLDMXEPy)
387  vldmia r0, {d0-d15} @ fldmiax is deprecated in ARMv7+ and now behaves like vldmia
388  JMP(lr)
389
390@
391@ static void libunwind::Registers_arm::restoreVFPv3(unw_fpreg_t* values)
392@
393@ On entry:
394@  values pointer is in r0
395@
396  .p2align 2
397  .fpu vfpv3
398DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm12restoreVFPv3EPy)
399  vldmia r0, {d16-d31}
400  JMP(lr)
401
402#if defined(__ARM_WMMX)
403
404@
405@ static void libunwind::Registers_arm::restoreiWMMX(unw_fpreg_t* values)
406@
407@ On entry:
408@  values pointer is in r0
409@
410  .p2align 2
411  .arch armv5te
412DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm12restoreiWMMXEPy)
413  ldcl p1, cr0, [r0], #8  @ wldrd wR0, [r0], #8
414  ldcl p1, cr1, [r0], #8  @ wldrd wR1, [r0], #8
415  ldcl p1, cr2, [r0], #8  @ wldrd wR2, [r0], #8
416  ldcl p1, cr3, [r0], #8  @ wldrd wR3, [r0], #8
417  ldcl p1, cr4, [r0], #8  @ wldrd wR4, [r0], #8
418  ldcl p1, cr5, [r0], #8  @ wldrd wR5, [r0], #8
419  ldcl p1, cr6, [r0], #8  @ wldrd wR6, [r0], #8
420  ldcl p1, cr7, [r0], #8  @ wldrd wR7, [r0], #8
421  ldcl p1, cr8, [r0], #8  @ wldrd wR8, [r0], #8
422  ldcl p1, cr9, [r0], #8  @ wldrd wR9, [r0], #8
423  ldcl p1, cr10, [r0], #8  @ wldrd wR10, [r0], #8
424  ldcl p1, cr11, [r0], #8  @ wldrd wR11, [r0], #8
425  ldcl p1, cr12, [r0], #8  @ wldrd wR12, [r0], #8
426  ldcl p1, cr13, [r0], #8  @ wldrd wR13, [r0], #8
427  ldcl p1, cr14, [r0], #8  @ wldrd wR14, [r0], #8
428  ldcl p1, cr15, [r0], #8  @ wldrd wR15, [r0], #8
429  JMP(lr)
430
431@
432@ static void libunwind::Registers_arm::restoreiWMMXControl(unw_uint32_t* values)
433@
434@ On entry:
435@  values pointer is in r0
436@
437  .p2align 2
438  .arch armv5te
439DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreiWMMXControlEPj)
440  ldc2 p1, cr8, [r0], #4  @ wldrw wCGR0, [r0], #4
441  ldc2 p1, cr9, [r0], #4  @ wldrw wCGR1, [r0], #4
442  ldc2 p1, cr10, [r0], #4  @ wldrw wCGR2, [r0], #4
443  ldc2 p1, cr11, [r0], #4  @ wldrw wCGR3, [r0], #4
444  JMP(lr)
445
446#endif
447
448#elif defined(__or1k__)
449
450DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv)
451#
452# void libunwind::Registers_or1k::jumpto()
453#
454# On entry:
455#  thread_state pointer is in r3
456#
457
458  # restore integral registerrs
459  l.lwz     r0,  0(r3)
460  l.lwz     r1,  4(r3)
461  l.lwz     r2,  8(r3)
462  # skip r3 for now
463  l.lwz     r4, 16(r3)
464  l.lwz     r5, 20(r3)
465  l.lwz     r6, 24(r3)
466  l.lwz     r7, 28(r3)
467  l.lwz     r8, 32(r3)
468  l.lwz     r9, 36(r3)
469  l.lwz    r10, 40(r3)
470  l.lwz    r11, 44(r3)
471  l.lwz    r12, 48(r3)
472  l.lwz    r13, 52(r3)
473  l.lwz    r14, 56(r3)
474  l.lwz    r15, 60(r3)
475  l.lwz    r16, 64(r3)
476  l.lwz    r17, 68(r3)
477  l.lwz    r18, 72(r3)
478  l.lwz    r19, 76(r3)
479  l.lwz    r20, 80(r3)
480  l.lwz    r21, 84(r3)
481  l.lwz    r22, 88(r3)
482  l.lwz    r23, 92(r3)
483  l.lwz    r24, 96(r3)
484  l.lwz    r25,100(r3)
485  l.lwz    r26,104(r3)
486  l.lwz    r27,108(r3)
487  l.lwz    r28,112(r3)
488  l.lwz    r29,116(r3)
489  l.lwz    r30,120(r3)
490  l.lwz    r31,124(r3)
491
492  # at last, restore r3
493  l.lwz    r3,  12(r3)
494
495  # jump to pc
496  l.jr     r9
497   l.nop
498
499#endif
500
501#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */
502
503NO_EXEC_STACK_DIRECTIVE
504
505