Merge pull request #238 from KubaKaszycki/master
[libffi.git] / src / x86 / win64.S
1 #define LIBFFI_ASM
2 #include <fficonfig.h>
3 #include <ffi.h>
4 #include <ffi_cfi.h>
5 #include "asmnames.h"
6
7 #if defined(HAVE_AS_CFI_PSEUDO_OP)
8         .cfi_sections   .debug_frame
9 #endif
10
11 #ifdef X86_WIN64
12 #define SEH(...) __VA_ARGS__
13 #define arg0    %rcx
14 #define arg1    %rdx
15 #define arg2    %r8
16 #define arg3    %r9
17 #else
18 #define SEH(...)
19 #define arg0    %rdi
20 #define arg1    %rsi
21 #define arg2    %rdx
22 #define arg3    %rcx
23 #endif
24
25 /* This macro allows the safe creation of jump tables without an
26    actual table.  The entry points into the table are all 8 bytes.
27    The use of ORG asserts that we're at the correct location.  */
28 /* ??? The clang assembler doesn't handle .org with symbolic expressions.  */
29 #if defined(__clang__) || defined(__APPLE__) || (defined (__sun__) && defined(__svr4__))
30 # define E(BASE, X)     .balign 8
31 #else
32 # define E(BASE, X)     .balign 8; .org BASE + X * 8
33 #endif
34
35         .text
36
37 /* ffi_call_win64 (void *stack, struct win64_call_frame *frame, void *r10)
38
39    Bit o trickiness here -- FRAME is the base of the stack frame
40    for this function.  This has been allocated by ffi_call.  We also
41    deallocate some of the stack that has been alloca'd.  */
42
43         .align  8
44         .globl  C(ffi_call_win64)
45
46         SEH(.seh_proc ffi_call_win64)
47 C(ffi_call_win64):
48         cfi_startproc
49         /* Set up the local stack frame and install it in rbp/rsp.  */
50         movq    (%rsp), %rax
51         movq    %rbp, (arg1)
52         movq    %rax, 8(arg1)
53         movq    arg1, %rbp
54         cfi_def_cfa(%rbp, 16)
55         cfi_rel_offset(%rbp, 0)
56         SEH(.seh_pushreg %rbp)
57         SEH(.seh_setframe %rbp, 0)
58         SEH(.seh_endprologue)
59         movq    arg0, %rsp
60
61         movq    arg2, %r10
62
63         /* Load all slots into both general and xmm registers.  */
64         movq    (%rsp), %rcx
65         movsd   (%rsp), %xmm0
66         movq    8(%rsp), %rdx
67         movsd   8(%rsp), %xmm1
68         movq    16(%rsp), %r8
69         movsd   16(%rsp), %xmm2
70         movq    24(%rsp), %r9
71         movsd   24(%rsp), %xmm3
72
73         call    *16(%rbp)
74
75         movl    24(%rbp), %ecx
76         movq    32(%rbp), %r8
77         leaq    0f(%rip), %r10
78         cmpl    $FFI_TYPE_SMALL_STRUCT_4B, %ecx
79         leaq    (%r10, %rcx, 8), %r10
80         ja      99f
81         jmp     *%r10
82
83 /* Below, we're space constrained most of the time.  Thus we eschew the
84    modern "mov, pop, ret" sequence (5 bytes) for "leave, ret" (2 bytes).  */
85 .macro epilogue
86         leaveq
87         cfi_remember_state
88         cfi_def_cfa(%rsp, 8)
89         cfi_restore(%rbp)
90         ret
91         cfi_restore_state
92 .endm
93
94         .align  8
95 0:
96 E(0b, FFI_TYPE_VOID)
97         epilogue
98 E(0b, FFI_TYPE_INT)
99         movslq  %eax, %rax
100         movq    %rax, (%r8)
101         epilogue
102 E(0b, FFI_TYPE_FLOAT)
103         movss   %xmm0, (%r8)
104         epilogue
105 E(0b, FFI_TYPE_DOUBLE)
106         movsd   %xmm0, (%r8)
107         epilogue
108 E(0b, FFI_TYPE_LONGDOUBLE)
109         call    PLT(C(abort))
110 E(0b, FFI_TYPE_UINT8)
111         movzbl  %al, %eax
112         movq    %rax, (%r8)
113         epilogue
114 E(0b, FFI_TYPE_SINT8)
115         movsbq  %al, %rax
116         jmp     98f
117 E(0b, FFI_TYPE_UINT16)
118         movzwl  %ax, %eax
119         movq    %rax, (%r8)
120         epilogue
121 E(0b, FFI_TYPE_SINT16)
122         movswq  %ax, %rax
123         jmp     98f
124 E(0b, FFI_TYPE_UINT32)
125         movl    %eax, %eax
126         movq    %rax, (%r8)
127         epilogue
128 E(0b, FFI_TYPE_SINT32)
129         movslq  %eax, %rax
130         movq    %rax, (%r8)
131         epilogue
132 E(0b, FFI_TYPE_UINT64)
133 98:     movq    %rax, (%r8)
134         epilogue
135 E(0b, FFI_TYPE_SINT64)
136         movq    %rax, (%r8)
137         epilogue
138 E(0b, FFI_TYPE_STRUCT)
139         epilogue
140 E(0b, FFI_TYPE_POINTER)
141         movq    %rax, (%r8)
142         epilogue
143 E(0b, FFI_TYPE_COMPLEX)
144         call    PLT(C(abort))
145 E(0b, FFI_TYPE_SMALL_STRUCT_1B)
146         movb    %al, (%r8)
147         epilogue
148 E(0b, FFI_TYPE_SMALL_STRUCT_2B)
149         movw    %ax, (%r8)
150         epilogue
151 E(0b, FFI_TYPE_SMALL_STRUCT_4B)
152         movl    %eax, (%r8)
153         epilogue
154
155         .align  8
156 99:     call    PLT(C(abort))
157
158         epilogue
159
160         cfi_endproc
161         SEH(.seh_endproc)
162
163
164 /* 32 bytes of outgoing register stack space, 8 bytes of alignment,
165    16 bytes of result, 32 bytes of xmm registers.  */
166 #define ffi_clo_FS      (32+8+16+32)
167 #define ffi_clo_OFF_R   (32+8)
168 #define ffi_clo_OFF_X   (32+8+16)
169
170         .align  8
171         .globl  C(ffi_go_closure_win64)
172
173         SEH(.seh_proc ffi_go_closure_win64)
174 C(ffi_go_closure_win64):
175         cfi_startproc
176         /* Save all integer arguments into the incoming reg stack space.  */
177         movq    %rcx, 8(%rsp)
178         movq    %rdx, 16(%rsp)
179         movq    %r8, 24(%rsp)
180         movq    %r9, 32(%rsp)
181
182         movq    8(%r10), %rcx                   /* load cif */
183         movq    16(%r10), %rdx                  /* load fun */
184         movq    %r10, %r8                       /* closure is user_data */
185         jmp     0f
186         cfi_endproc
187         SEH(.seh_endproc)
188
189         .align  8
190         .globl  C(ffi_closure_win64)
191
192         SEH(.seh_proc ffi_closure_win64)
193 C(ffi_closure_win64):
194         cfi_startproc
195         /* Save all integer arguments into the incoming reg stack space.  */
196         movq    %rcx, 8(%rsp)
197         movq    %rdx, 16(%rsp)
198         movq    %r8, 24(%rsp)
199         movq    %r9, 32(%rsp)
200
201         movq    FFI_TRAMPOLINE_SIZE(%r10), %rcx         /* load cif */
202         movq    FFI_TRAMPOLINE_SIZE+8(%r10), %rdx       /* load fun */
203         movq    FFI_TRAMPOLINE_SIZE+16(%r10), %r8       /* load user_data */
204 0:
205         subq    $ffi_clo_FS, %rsp
206         cfi_adjust_cfa_offset(ffi_clo_FS)
207         SEH(.seh_stackalloc ffi_clo_FS)
208         SEH(.seh_endprologue)
209
210         /* Save all sse arguments into the stack frame.  */
211         movsd   %xmm0, ffi_clo_OFF_X(%rsp)
212         movsd   %xmm1, ffi_clo_OFF_X+8(%rsp)
213         movsd   %xmm2, ffi_clo_OFF_X+16(%rsp)
214         movsd   %xmm3, ffi_clo_OFF_X+24(%rsp)
215
216         leaq    ffi_clo_OFF_R(%rsp), %r9
217         call    C(ffi_closure_win64_inner)
218
219         /* Load the result into both possible result registers.  */
220         movq    ffi_clo_OFF_R(%rsp), %rax
221         movsd   ffi_clo_OFF_R(%rsp), %xmm0
222
223         addq    $ffi_clo_FS, %rsp
224         cfi_adjust_cfa_offset(-ffi_clo_FS)
225         ret
226
227         cfi_endproc
228         SEH(.seh_endproc)
229
230 #if defined __ELF__ && defined __linux__
231         .section        .note.GNU-stack,"",@progbits
232 #endif