1//===------------------------ UnwindRegistersSave.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(__i386__)
15
16#
17# extern int unw_getcontext(unw_context_t* thread_state)
18#
19# On entry:
20#   +                       +
21#   +-----------------------+
22#   + thread_state pointer  +
23#   +-----------------------+
24#   + return address        +
25#   +-----------------------+   <-- SP
26#   +                       +
27#
28DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
29  push  %eax
30  movl  8(%esp), %eax
31  movl  %ebx,  4(%eax)
32  movl  %ecx,  8(%eax)
33  movl  %edx, 12(%eax)
34  movl  %edi, 16(%eax)
35  movl  %esi, 20(%eax)
36  movl  %ebp, 24(%eax)
37  movl  %esp, %edx
38  addl  $8, %edx
39  movl  %edx, 28(%eax)  # store what sp was at call site as esp
40  # skip ss
41  # skip eflags
42  movl  4(%esp), %edx
43  movl  %edx, 40(%eax)  # store return address as eip
44  # skip cs
45  # skip ds
46  # skip es
47  # skip fs
48  # skip gs
49  movl  (%esp), %edx
50  movl  %edx, (%eax)  # store original eax
51  popl  %eax
52  xorl  %eax, %eax    # return UNW_ESUCCESS
53  ret
54
55#elif defined(__x86_64__)
56
57#
58# extern int unw_getcontext(unw_context_t* thread_state)
59#
60# On entry:
61#  thread_state pointer is in rdi
62#
63DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
64  movq  %rax,   (%rdi)
65  movq  %rbx,  8(%rdi)
66  movq  %rcx, 16(%rdi)
67  movq  %rdx, 24(%rdi)
68  movq  %rdi, 32(%rdi)
69  movq  %rsi, 40(%rdi)
70  movq  %rbp, 48(%rdi)
71  movq  %rsp, 56(%rdi)
72  addq  $8,   56(%rdi)
73  movq  %r8,  64(%rdi)
74  movq  %r9,  72(%rdi)
75  movq  %r10, 80(%rdi)
76  movq  %r11, 88(%rdi)
77  movq  %r12, 96(%rdi)
78  movq  %r13,104(%rdi)
79  movq  %r14,112(%rdi)
80  movq  %r15,120(%rdi)
81  movq  (%rsp),%rsi
82  movq  %rsi,128(%rdi) # store return address as rip
83  # skip rflags
84  # skip cs
85  # skip fs
86  # skip gs
87  xorl  %eax, %eax    # return UNW_ESUCCESS
88  ret
89
90# elif defined(__mips__)
91
92#
93# extern int unw_getcontext(unw_context_t* thread_state)
94#
95# Just trap for the time being.
96DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
97  teq $0, $0
98
99#elif defined(__ppc__)
100
101;
102; extern int unw_getcontext(unw_context_t* thread_state)
103;
104; On entry:
105;  thread_state pointer is in r3
106;
107DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
108  stw    r0,  8(r3)
109  mflr  r0
110  stw    r0,  0(r3)  ; store lr as ssr0
111  stw    r1, 12(r3)
112  stw    r2, 16(r3)
113  stw    r3, 20(r3)
114  stw    r4, 24(r3)
115  stw    r5, 28(r3)
116  stw    r6, 32(r3)
117  stw    r7, 36(r3)
118  stw    r8, 40(r3)
119  stw    r9, 44(r3)
120  stw     r10, 48(r3)
121  stw     r11, 52(r3)
122  stw     r12, 56(r3)
123  stw     r13, 60(r3)
124  stw     r14, 64(r3)
125  stw     r15, 68(r3)
126  stw     r16, 72(r3)
127  stw     r17, 76(r3)
128  stw     r18, 80(r3)
129  stw     r19, 84(r3)
130  stw     r20, 88(r3)
131  stw     r21, 92(r3)
132  stw     r22, 96(r3)
133  stw     r23,100(r3)
134  stw     r24,104(r3)
135  stw     r25,108(r3)
136  stw     r26,112(r3)
137  stw     r27,116(r3)
138  stw     r28,120(r3)
139  stw     r29,124(r3)
140  stw     r30,128(r3)
141  stw     r31,132(r3)
142
143  ; save VRSave register
144  mfspr  r0,256
145  stw    r0,156(r3)
146  ; save CR registers
147  mfcr  r0
148  stw    r0,136(r3)
149  ; save CTR register
150  mfctr  r0
151  stw    r0,148(r3)
152
153  ; save float registers
154  stfd    f0, 160(r3)
155  stfd    f1, 168(r3)
156  stfd    f2, 176(r3)
157  stfd    f3, 184(r3)
158  stfd    f4, 192(r3)
159  stfd    f5, 200(r3)
160  stfd    f6, 208(r3)
161  stfd    f7, 216(r3)
162  stfd    f8, 224(r3)
163  stfd    f9, 232(r3)
164  stfd    f10,240(r3)
165  stfd    f11,248(r3)
166  stfd    f12,256(r3)
167  stfd    f13,264(r3)
168  stfd    f14,272(r3)
169  stfd    f15,280(r3)
170  stfd    f16,288(r3)
171  stfd    f17,296(r3)
172  stfd    f18,304(r3)
173  stfd    f19,312(r3)
174  stfd    f20,320(r3)
175  stfd    f21,328(r3)
176  stfd    f22,336(r3)
177  stfd    f23,344(r3)
178  stfd    f24,352(r3)
179  stfd    f25,360(r3)
180  stfd    f26,368(r3)
181  stfd    f27,376(r3)
182  stfd    f28,384(r3)
183  stfd    f29,392(r3)
184  stfd    f30,400(r3)
185  stfd    f31,408(r3)
186
187
188  ; save vector registers
189
190  subi  r4,r1,16
191  rlwinm  r4,r4,0,0,27  ; mask low 4-bits
192  ; r4 is now a 16-byte aligned pointer into the red zone
193
194#define SAVE_VECTOR_UNALIGNED(_vec, _offset) \
195  stvx  _vec,0,r4           @\
196  lwz    r5, 0(r4)          @\
197  stw    r5, _offset(r3)    @\
198  lwz    r5, 4(r4)          @\
199  stw    r5, _offset+4(r3)  @\
200  lwz    r5, 8(r4)          @\
201  stw    r5, _offset+8(r3)  @\
202  lwz    r5, 12(r4)         @\
203  stw    r5, _offset+12(r3)
204
205  SAVE_VECTOR_UNALIGNED( v0, 424+0x000)
206  SAVE_VECTOR_UNALIGNED( v1, 424+0x010)
207  SAVE_VECTOR_UNALIGNED( v2, 424+0x020)
208  SAVE_VECTOR_UNALIGNED( v3, 424+0x030)
209  SAVE_VECTOR_UNALIGNED( v4, 424+0x040)
210  SAVE_VECTOR_UNALIGNED( v5, 424+0x050)
211  SAVE_VECTOR_UNALIGNED( v6, 424+0x060)
212  SAVE_VECTOR_UNALIGNED( v7, 424+0x070)
213  SAVE_VECTOR_UNALIGNED( v8, 424+0x080)
214  SAVE_VECTOR_UNALIGNED( v9, 424+0x090)
215  SAVE_VECTOR_UNALIGNED(v10, 424+0x0A0)
216  SAVE_VECTOR_UNALIGNED(v11, 424+0x0B0)
217  SAVE_VECTOR_UNALIGNED(v12, 424+0x0C0)
218  SAVE_VECTOR_UNALIGNED(v13, 424+0x0D0)
219  SAVE_VECTOR_UNALIGNED(v14, 424+0x0E0)
220  SAVE_VECTOR_UNALIGNED(v15, 424+0x0F0)
221  SAVE_VECTOR_UNALIGNED(v16, 424+0x100)
222  SAVE_VECTOR_UNALIGNED(v17, 424+0x110)
223  SAVE_VECTOR_UNALIGNED(v18, 424+0x120)
224  SAVE_VECTOR_UNALIGNED(v19, 424+0x130)
225  SAVE_VECTOR_UNALIGNED(v20, 424+0x140)
226  SAVE_VECTOR_UNALIGNED(v21, 424+0x150)
227  SAVE_VECTOR_UNALIGNED(v22, 424+0x160)
228  SAVE_VECTOR_UNALIGNED(v23, 424+0x170)
229  SAVE_VECTOR_UNALIGNED(v24, 424+0x180)
230  SAVE_VECTOR_UNALIGNED(v25, 424+0x190)
231  SAVE_VECTOR_UNALIGNED(v26, 424+0x1A0)
232  SAVE_VECTOR_UNALIGNED(v27, 424+0x1B0)
233  SAVE_VECTOR_UNALIGNED(v28, 424+0x1C0)
234  SAVE_VECTOR_UNALIGNED(v29, 424+0x1D0)
235  SAVE_VECTOR_UNALIGNED(v30, 424+0x1E0)
236  SAVE_VECTOR_UNALIGNED(v31, 424+0x1F0)
237
238  li  r3, 0    ; return UNW_ESUCCESS
239  blr
240
241
242#elif defined(__arm64__) || defined(__aarch64__)
243
244//
245// extern int unw_getcontext(unw_context_t* thread_state)
246//
247// On entry:
248//  thread_state pointer is in x0
249//
250  .p2align 2
251DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
252  stp    x0, x1,  [x0, #0x000]
253  stp    x2, x3,  [x0, #0x010]
254  stp    x4, x5,  [x0, #0x020]
255  stp    x6, x7,  [x0, #0x030]
256  stp    x8, x9,  [x0, #0x040]
257  stp    x10,x11, [x0, #0x050]
258  stp    x12,x13, [x0, #0x060]
259  stp    x14,x15, [x0, #0x070]
260  stp    x16,x17, [x0, #0x080]
261  stp    x18,x19, [x0, #0x090]
262  stp    x20,x21, [x0, #0x0A0]
263  stp    x22,x23, [x0, #0x0B0]
264  stp    x24,x25, [x0, #0x0C0]
265  stp    x26,x27, [x0, #0x0D0]
266  stp    x28,x29, [x0, #0x0E0]
267  str    x30,     [x0, #0x0F0]
268  mov    x1,sp
269  str    x1,      [x0, #0x0F8]
270  str    x30,     [x0, #0x100]    // store return address as pc
271  // skip cpsr
272  stp    d0, d1,  [x0, #0x110]
273  stp    d2, d3,  [x0, #0x120]
274  stp    d4, d5,  [x0, #0x130]
275  stp    d6, d7,  [x0, #0x140]
276  stp    d8, d9,  [x0, #0x150]
277  stp    d10,d11, [x0, #0x160]
278  stp    d12,d13, [x0, #0x170]
279  stp    d14,d15, [x0, #0x180]
280  stp    d16,d17, [x0, #0x190]
281  stp    d18,d19, [x0, #0x1A0]
282  stp    d20,d21, [x0, #0x1B0]
283  stp    d22,d23, [x0, #0x1C0]
284  stp    d24,d25, [x0, #0x1D0]
285  stp    d26,d27, [x0, #0x1E0]
286  stp    d28,d29, [x0, #0x1F0]
287  str    d30,     [x0, #0x200]
288  str    d31,     [x0, #0x208]
289  mov    x0, #0                   // return UNW_ESUCCESS
290  ret
291
292#elif defined(__arm__) && !defined(__APPLE__)
293
294#if !defined(__ARM_ARCH_ISA_ARM)
295  .thumb
296#endif
297
298@
299@ extern int unw_getcontext(unw_context_t* thread_state)
300@
301@ On entry:
302@  thread_state pointer is in r0
303@
304@ Per EHABI #4.7 this only saves the core integer registers.
305@ EHABI #7.4.5 notes that in general all VRS registers should be restored
306@ however this is very hard to do for VFP registers because it is unknown
307@ to the library how many registers are implemented by the architecture.
308@ Instead, VFP registers are demand saved by logic external to unw_getcontext.
309@
310  .p2align 2
311DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
312#if !defined(__ARM_ARCH_ISA_ARM) && __ARM_ARCH_ISA_THUMB == 1
313  stm r0!, {r0-r7}
314  mov r1, r8
315  mov r2, r9
316  mov r3, r10
317  stm r0!, {r1-r3}
318  mov r1, r11
319  mov r2, sp
320  mov r3, lr
321  str r1, [r0, #0]   @ r11
322  @ r12 does not need storing, it it the intra-procedure-call scratch register
323  str r2, [r0, #8]   @ sp
324  str r3, [r0, #12]  @ lr
325  str r3, [r0, #16]  @ store return address as pc
326  @ T1 does not have a non-cpsr-clobbering register-zeroing instruction.
327  @ It is safe to use here though because we are about to return, and cpsr is
328  @ not expected to be preserved.
329  movs r0, #0        @ return UNW_ESUCCESS
330#else
331  @ 32bit thumb-2 restrictions for stm:
332  @ . the sp (r13) cannot be in the list
333  @ . the pc (r15) cannot be in the list in an STM instruction
334  stm r0, {r0-r12}
335  str sp, [r0, #52]
336  str lr, [r0, #56]
337  str lr, [r0, #60]  @ store return address as pc
338  mov r0, #0         @ return UNW_ESUCCESS
339#endif
340  JMP(lr)
341
342@
343@ static void libunwind::Registers_arm::saveVFPWithFSTMD(unw_fpreg_t* values)
344@
345@ On entry:
346@  values pointer is in r0
347@
348  .p2align 2
349  .fpu vfpv3-d16
350DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMDEPy)
351  vstmia r0, {d0-d15}
352  JMP(lr)
353
354@
355@ static void libunwind::Registers_arm::saveVFPWithFSTMX(unw_fpreg_t* values)
356@
357@ On entry:
358@  values pointer is in r0
359@
360  .p2align 2
361  .fpu vfpv3-d16
362DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMXEPy)
363  vstmia r0, {d0-d15} @ fstmiax is deprecated in ARMv7+ and now behaves like vstmia
364  JMP(lr)
365
366@
367@ static void libunwind::Registers_arm::saveVFPv3(unw_fpreg_t* values)
368@
369@ On entry:
370@  values pointer is in r0
371@
372  .p2align 2
373  .fpu vfpv3
374DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveVFPv3EPy)
375  @ VFP and iwMMX instructions are only available when compiling with the flags
376  @ that enable them. We do not want to do that in the library (because we do not
377  @ want the compiler to generate instructions that access those) but this is
378  @ only accessed if the personality routine needs these registers. Use of
379  @ these registers implies they are, actually, available on the target, so
380  @ it's ok to execute.
381  @ So, generate the instructions using the corresponding coprocessor mnemonic.
382  vstmia r0, {d16-d31}
383  JMP(lr)
384
385#if defined(_LIBUNWIND_ARM_WMMX)
386
387@
388@ static void libunwind::Registers_arm::saveiWMMX(unw_fpreg_t* values)
389@
390@ On entry:
391@  values pointer is in r0
392@
393  .p2align 2
394  .arch armv5te
395DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveiWMMXEPy)
396  stcl p1, cr0, [r0], #8  @ wstrd wR0, [r0], #8
397  stcl p1, cr1, [r0], #8  @ wstrd wR1, [r0], #8
398  stcl p1, cr2, [r0], #8  @ wstrd wR2, [r0], #8
399  stcl p1, cr3, [r0], #8  @ wstrd wR3, [r0], #8
400  stcl p1, cr4, [r0], #8  @ wstrd wR4, [r0], #8
401  stcl p1, cr5, [r0], #8  @ wstrd wR5, [r0], #8
402  stcl p1, cr6, [r0], #8  @ wstrd wR6, [r0], #8
403  stcl p1, cr7, [r0], #8  @ wstrd wR7, [r0], #8
404  stcl p1, cr8, [r0], #8  @ wstrd wR8, [r0], #8
405  stcl p1, cr9, [r0], #8  @ wstrd wR9, [r0], #8
406  stcl p1, cr10, [r0], #8  @ wstrd wR10, [r0], #8
407  stcl p1, cr11, [r0], #8  @ wstrd wR11, [r0], #8
408  stcl p1, cr12, [r0], #8  @ wstrd wR12, [r0], #8
409  stcl p1, cr13, [r0], #8  @ wstrd wR13, [r0], #8
410  stcl p1, cr14, [r0], #8  @ wstrd wR14, [r0], #8
411  stcl p1, cr15, [r0], #8  @ wstrd wR15, [r0], #8
412  JMP(lr)
413
414@
415@ static void libunwind::Registers_arm::saveiWMMXControl(unw_uint32_t* values)
416@
417@ On entry:
418@  values pointer is in r0
419@
420  .p2align 2
421  .arch armv5te
422DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveiWMMXControlEPj)
423  stc2 p1, cr8, [r0], #4  @ wstrw wCGR0, [r0], #4
424  stc2 p1, cr9, [r0], #4  @ wstrw wCGR1, [r0], #4
425  stc2 p1, cr10, [r0], #4  @ wstrw wCGR2, [r0], #4
426  stc2 p1, cr11, [r0], #4  @ wstrw wCGR3, [r0], #4
427  JMP(lr)
428
429#endif
430
431#elif defined(__or1k__)
432
433#
434# extern int unw_getcontext(unw_context_t* thread_state)
435#
436# On entry:
437#  thread_state pointer is in r3
438#
439DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
440  l.sw       0(r3), r0
441  l.sw       4(r3), r1
442  l.sw       8(r3), r2
443  l.sw      12(r3), r3
444  l.sw      16(r3), r4
445  l.sw      20(r3), r5
446  l.sw      24(r3), r6
447  l.sw      28(r3), r7
448  l.sw      32(r3), r8
449  l.sw      36(r3), r9
450  l.sw      40(r3), r10
451  l.sw      44(r3), r11
452  l.sw      48(r3), r12
453  l.sw      52(r3), r13
454  l.sw      56(r3), r14
455  l.sw      60(r3), r15
456  l.sw      64(r3), r16
457  l.sw      68(r3), r17
458  l.sw      72(r3), r18
459  l.sw      76(r3), r19
460  l.sw      80(r3), r20
461  l.sw      84(r3), r21
462  l.sw      88(r3), r22
463  l.sw      92(r3), r23
464  l.sw      96(r3), r24
465  l.sw     100(r3), r25
466  l.sw     104(r3), r26
467  l.sw     108(r3), r27
468  l.sw     112(r3), r28
469  l.sw     116(r3), r29
470  l.sw     120(r3), r30
471  l.sw     124(r3), r31
472#endif
473
474NO_EXEC_STACK_DIRECTIVE
475
476