Update README with a new port
[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 .macro E which
26         .align  8
27         .org    0b + \which * 8
28 .endm
29
30         .text
31
32 /* ffi_call_win64 (void *stack, struct win64_call_frame *frame, void *r10)
33
34    Bit o trickiness here -- FRAME is the base of the stack frame
35    for this function.  This has been allocated by ffi_call.  We also
36    deallocate some of the stack that has been alloca'd.  */
37
38         .align  8
39         .globl  ffi_call_win64
40
41         SEH(.seh_proc ffi_call_win64)
42 ffi_call_win64:
43         cfi_startproc
44         /* Set up the local stack frame and install it in rbp/rsp.  */
45         movq    (%rsp), %rax
46         movq    %rbp, (arg1)
47         movq    %rax, 8(arg1)
48         movq    arg1, %rbp
49         cfi_def_cfa(%rbp, 16)
50         cfi_rel_offset(%rbp, 0)
51         SEH(.seh_pushreg %rbp)
52         SEH(.seh_setframe %rbp, 0)
53         SEH(.seh_endprologue)
54         movq    arg0, %rsp
55
56         movq    arg2, %r10
57
58         /* Load all slots into both general and xmm registers.  */
59         movq    (%rsp), %rcx
60         movsd   (%rsp), %xmm0
61         movq    8(%rsp), %rdx
62         movsd   8(%rsp), %xmm1
63         movq    16(%rsp), %r8
64         movsd   16(%rsp), %xmm2
65         movq    24(%rsp), %r9
66         movsd   24(%rsp), %xmm3
67
68         call    *16(%rbp)
69
70         movl    24(%rbp), %ecx
71         movq    32(%rbp), %r8
72         leaq    0f(%rip), %r10
73         cmpl    $FFI_TYPE_SMALL_STRUCT_4B, %ecx
74         leaq    (%r10, %rcx, 8), %r10
75         ja      99f
76         jmp     *%r10
77
78 /* Below, we're space constrained most of the time.  Thus we eschew the
79    modern "mov, pop, ret" sequence (5 bytes) for "leave, ret" (2 bytes).  */
80 .macro epilogue
81         leaveq
82         cfi_remember_state
83         cfi_def_cfa(%rsp, 8)
84         cfi_restore(%rbp)
85         ret
86         cfi_restore_state
87 .endm
88
89         .align  8
90 0:
91 E FFI_TYPE_VOID
92         epilogue
93 E FFI_TYPE_INT
94         movslq  %eax, %rax
95         movq    %rax, (%r8)
96         epilogue
97 E FFI_TYPE_FLOAT
98         movss   %xmm0, (%r8)
99         epilogue
100 E FFI_TYPE_DOUBLE
101         movsd   %xmm0, (%r8)
102         epilogue
103 E FFI_TYPE_LONGDOUBLE
104         call    PLT(C(abort))
105 E FFI_TYPE_UINT8
106         movzbl  %al, %eax
107         movq    %rax, (%r8)
108         epilogue
109 E FFI_TYPE_SINT8
110         movsbq  %al, %rax
111         jmp     98f
112 E FFI_TYPE_UINT16
113         movzwl  %ax, %eax
114         movq    %rax, (%r8)
115         epilogue
116 E FFI_TYPE_SINT16
117         movswq  %ax, %rax
118         jmp     98f
119 E FFI_TYPE_UINT32
120         movl    %eax, %eax
121         movq    %rax, (%r8)
122         epilogue
123 E FFI_TYPE_SINT32
124         movslq  %eax, %rax
125         movq    %rax, (%r8)
126         epilogue
127 E FFI_TYPE_UINT64
128 98:     movq    %rax, (%r8)
129         epilogue
130 E FFI_TYPE_SINT64
131         movq    %rax, (%r8)
132         epilogue
133 E FFI_TYPE_STRUCT
134         epilogue
135 E FFI_TYPE_POINTER
136         movq    %rax, (%r8)
137         epilogue
138 E FFI_TYPE_COMPLEX
139         call    PLT(C(abort))
140 E FFI_TYPE_SMALL_STRUCT_1B
141         movb    %al, (%r8)
142         epilogue
143 E FFI_TYPE_SMALL_STRUCT_2B
144         movw    %ax, (%r8)
145         epilogue
146 E FFI_TYPE_SMALL_STRUCT_4B
147         movl    %eax, (%r8)
148         epilogue
149
150         .align  8
151 99:     call    PLT(C(abort))
152
153 .purgem epilogue
154
155         cfi_endproc
156         SEH(.seh_endproc)
157
158
159 /* 32 bytes of outgoing register stack space, 8 bytes of alignment,
160    16 bytes of result, 32 bytes of xmm registers.  */
161 #define ffi_clo_FS      (32+8+16+32)
162 #define ffi_clo_OFF_R   (32+8)
163 #define ffi_clo_OFF_X   (32+8+16)
164
165         .align  8
166         .globl  ffi_go_closure_win64
167
168         SEH(.seh_proc ffi_go_closure_win64)
169 ffi_go_closure_win64:
170         cfi_startproc
171         /* Save all integer arguments into the incoming reg stack space.  */
172         movq    %rcx, 8(%rsp)
173         movq    %rdx, 16(%rsp)
174         movq    %r8, 24(%rsp)
175         movq    %r9, 32(%rsp)
176
177         movq    8(%r10), arg0                   /* load cif */
178         movq    16(%r10), arg1                  /* load fun */
179         movq    %r10, arg2                      /* closure is user_data */
180         jmp     0f
181         cfi_endproc
182         SEH(.seh_endproc)
183
184         .align  8
185         .globl  ffi_closure_win64
186
187         SEH(.seh_proc ffi_closure_win64)
188 ffi_closure_win64:
189         cfi_startproc
190         /* Save all integer arguments into the incoming reg stack space.  */
191         movq    %rcx, 8(%rsp)
192         movq    %rdx, 16(%rsp)
193         movq    %r8, 24(%rsp)
194         movq    %r9, 32(%rsp)
195
196         movq    FFI_TRAMPOLINE_SIZE(%r10), arg0         /* load cif */
197         movq    FFI_TRAMPOLINE_SIZE+8(%r10), arg1       /* load fun */
198         movq    FFI_TRAMPOLINE_SIZE+16(%r10), arg2      /* load user_data */
199 0:
200         subq    $ffi_clo_FS, %rsp
201         cfi_adjust_cfa_offset(ffi_clo_FS)
202         SEH(.seh_stackalloc ffi_clo_FS)
203         SEH(.seh_endprologue)
204
205         /* Save all sse arguments into the stack frame.  */
206         movsd   %xmm0, ffi_clo_OFF_X(%rsp)
207         movsd   %xmm1, ffi_clo_OFF_X+8(%rsp)
208         movsd   %xmm2, ffi_clo_OFF_X+16(%rsp)
209         movsd   %xmm3, ffi_clo_OFF_X+24(%rsp)
210
211         leaq    ffi_clo_OFF_R(%rsp), arg3
212         call    ffi_closure_win64_inner
213
214         /* Load the result into both possible result registers.  */
215         movq    ffi_clo_OFF_R(%rsp), %rax
216         movsd   ffi_clo_OFF_R(%rsp), %xmm0
217
218         addq    $ffi_clo_FS, %rsp
219         cfi_adjust_cfa_offset(-ffi_clo_FS)
220         ret
221
222         cfi_endproc
223         SEH(.seh_endproc)