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