1 /* -----------------------------------------------------------------------
2 ffiw64.c - Copyright (c) 2018 Anthony Green
3 Copyright (c) 2014 Red Hat, Inc.
5 x86 win64 Foreign Function Interface
7 Permission is hereby granted, free of charge, to any person obtaining
8 a copy of this software and associated documentation files (the
9 ``Software''), to deal in the Software without restriction, including
10 without limitation the rights to use, copy, modify, merge, publish,
11 distribute, sublicense, and/or sell copies of the Software, and to
12 permit persons to whom the Software is furnished to do so, subject to
13 the following conditions:
15 The above copyright notice and this permission notice shall be included
16 in all copies or substantial portions of the Software.
18 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 DEALINGS IN THE SOFTWARE.
26 ----------------------------------------------------------------------- */
28 #if defined(__x86_64__) || defined(_M_AMD64)
30 #include <ffi_common.h>
36 #define EFI64(name) name
38 #define EFI64(name) FFI_HIDDEN name##_efi64
41 struct win64_call_frame
44 UINT64 retaddr; /* 8 */
46 UINT64 flags; /* 24 */
47 UINT64 rvalue; /* 32 */
50 extern void ffi_call_win64 (void *stack, struct win64_call_frame *,
51 void *closure) FFI_HIDDEN;
54 EFI64(ffi_prep_cif_machdep)(ffi_cif *cif)
67 flags = cif->rtype->type;
72 case FFI_TYPE_LONGDOUBLE:
73 /* GCC returns long double values by reference, like a struct */
74 if (cif->abi == FFI_GNUW64)
75 flags = FFI_TYPE_STRUCT;
77 case FFI_TYPE_COMPLEX:
78 flags = FFI_TYPE_STRUCT;
81 switch (cif->rtype->size)
84 flags = FFI_TYPE_UINT64;
87 flags = FFI_TYPE_SMALL_STRUCT_4B;
90 flags = FFI_TYPE_SMALL_STRUCT_2B;
93 flags = FFI_TYPE_SMALL_STRUCT_1B;
100 /* Each argument either fits in a register, an 8 byte slot, or is
101 passed by reference with the pointer in the 8 byte slot. */
103 n += (flags == FFI_TYPE_STRUCT);
112 ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
113 void **avalue, void *closure)
118 struct win64_call_frame *frame;
120 FFI_ASSERT(cif->abi == FFI_GNUW64 || cif->abi == FFI_WIN64);
125 /* If we have no return value for a structure, we need to create one.
126 Otherwise we can ignore the return type entirely. */
129 if (flags == FFI_TYPE_STRUCT)
130 rsize = cif->rtype->size;
132 flags = FFI_TYPE_VOID;
135 stack = alloca(cif->bytes + sizeof(struct win64_call_frame) + rsize);
136 frame = (struct win64_call_frame *)((char *)stack + cif->bytes);
140 frame->fn = (uintptr_t)fn;
141 frame->flags = flags;
142 frame->rvalue = (uintptr_t)rvalue;
145 if (flags == FFI_TYPE_STRUCT)
147 stack[0] = (uintptr_t)rvalue;
151 for (i = 0, n = cif->nargs; i < n; ++i, ++j)
153 switch (cif->arg_types[i]->size)
156 stack[j] = *(UINT64 *)avalue[i];
159 stack[j] = *(UINT32 *)avalue[i];
162 stack[j] = *(UINT16 *)avalue[i];
165 stack[j] = *(UINT8 *)avalue[i];
168 stack[j] = (uintptr_t)avalue[i];
173 ffi_call_win64 (stack, frame, closure);
177 EFI64(ffi_call)(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
179 ffi_call_int (cif, fn, rvalue, avalue, NULL);
183 EFI64(ffi_call_go)(ffi_cif *cif, void (*fn)(void), void *rvalue,
184 void **avalue, void *closure)
186 ffi_call_int (cif, fn, rvalue, avalue, closure);
190 extern void ffi_closure_win64(void) FFI_HIDDEN;
191 #if defined(FFI_EXEC_STATIC_TRAMP)
192 extern void ffi_closure_win64_alt(void) FFI_HIDDEN;
195 #ifdef FFI_GO_CLOSURES
196 extern void ffi_go_closure_win64(void) FFI_HIDDEN;
200 EFI64(ffi_prep_closure_loc)(ffi_closure* closure,
202 void (*fun)(ffi_cif*, void*, void**, void*),
206 static const unsigned char trampoline[FFI_TRAMPOLINE_SIZE - 8] = {
208 0xf3, 0x0f, 0x1e, 0xfa,
209 /* leaq -0xb(%rip),%r10 # 0x0 */
210 0x4c, 0x8d, 0x15, 0xf5, 0xff, 0xff, 0xff,
211 /* jmpq *0x7(%rip) # 0x18 */
212 0xff, 0x25, 0x07, 0x00, 0x00, 0x00,
214 0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00
216 char *tramp = closure->tramp;
227 #if defined(FFI_EXEC_STATIC_TRAMP)
228 if (ffi_tramp_is_present(closure))
230 /* Initialize the static trampoline's parameters. */
231 ffi_tramp_set_parms (closure->ftramp, ffi_closure_win64_alt, closure);
236 /* Initialize the dynamic trampoline. */
237 memcpy (tramp, trampoline, sizeof(trampoline));
238 *(UINT64 *)(tramp + sizeof (trampoline)) = (uintptr_t)ffi_closure_win64;
243 closure->user_data = user_data;
248 #ifdef FFI_GO_CLOSURES
250 EFI64(ffi_prep_go_closure)(ffi_go_closure* closure, ffi_cif* cif,
251 void (*fun)(ffi_cif*, void*, void**, void*))
262 closure->tramp = ffi_go_closure_win64;
270 struct win64_closure_frame
278 /* Force the inner function to use the MS ABI. When compiling on win64
279 this is a nop. When compiling on unix, this simplifies the assembly,
280 and places the burden of saving the extra call-saved registers on
282 int FFI_HIDDEN __attribute__((ms_abi))
283 ffi_closure_win64_inner(ffi_cif *cif,
284 void (*fun)(ffi_cif*, void*, void**, void*),
286 struct win64_closure_frame *frame)
290 int i, n, nreg, flags;
292 avalue = alloca(cif->nargs * sizeof(void *));
293 rvalue = frame->rvalue;
296 /* When returning a structure, the address is in the first argument.
297 We must also be prepared to return the same address in eax, so
298 install that address in the frame and pretend we return a pointer. */
300 if (flags == FFI_TYPE_STRUCT)
302 rvalue = (void *)(uintptr_t)frame->args[0];
303 frame->rvalue[0] = frame->args[0];
307 for (i = 0, n = cif->nargs; i < n; ++i, ++nreg)
309 size_t size = cif->arg_types[i]->size;
310 size_t type = cif->arg_types[i]->type;
313 if (type == FFI_TYPE_DOUBLE || type == FFI_TYPE_FLOAT)
316 a = &frame->fargs[nreg];
318 a = &frame->args[nreg];
320 else if (size == 1 || size == 2 || size == 4 || size == 8)
321 a = &frame->args[nreg];
323 a = (void *)(uintptr_t)frame->args[nreg];
328 /* Invoke the closure. */
329 fun (cif, rvalue, avalue, user_data);
333 #endif /* __x86_64__ */