1 /* -----------------------------------------------------------------------
2 ffiw64.c - Copyright (c) 2014 Red Hat, Inc.
4 x86 win64 Foreign Function Interface
6 Permission is hereby granted, free of charge, to any person obtaining
7 a copy of this software and associated documentation files (the
8 ``Software''), to deal in the Software without restriction, including
9 without limitation the rights to use, copy, modify, merge, publish,
10 distribute, sublicense, and/or sell copies of the Software, and to
11 permit persons to whom the Software is furnished to do so, subject to
12 the following conditions:
14 The above copyright notice and this permission notice shall be included
15 in all copies or substantial portions of the Software.
17 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
18 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 DEALINGS IN THE SOFTWARE.
25 ----------------------------------------------------------------------- */
28 #include <ffi_common.h>
34 struct win64_call_frame
37 UINT64 retaddr
; /* 8 */
39 UINT64 flags
; /* 24 */
40 UINT64 rvalue
; /* 32 */
43 extern void ffi_call_win64 (void *stack
, struct win64_call_frame
*,
44 void *closure
) FFI_HIDDEN
;
47 ffi_prep_cif_machdep (ffi_cif
*cif
)
51 if (cif
->abi
!= FFI_WIN64
)
54 flags
= cif
->rtype
->type
;
59 case FFI_TYPE_LONGDOUBLE
:
60 flags
= FFI_TYPE_STRUCT
;
62 case FFI_TYPE_COMPLEX
:
63 flags
= FFI_TYPE_STRUCT
;
66 switch (cif
->rtype
->size
)
69 flags
= FFI_TYPE_UINT64
;
72 flags
= FFI_TYPE_SMALL_STRUCT_4B
;
75 flags
= FFI_TYPE_SMALL_STRUCT_2B
;
78 flags
= FFI_TYPE_SMALL_STRUCT_1B
;
85 /* Each argument either fits in a register, an 8 byte slot, or is
86 passed by reference with the pointer in the 8 byte slot. */
88 n
+= (flags
== FFI_TYPE_STRUCT
);
97 ffi_call_int (ffi_cif
*cif
, void (*fn
)(void), void *rvalue
,
98 void **avalue
, void *closure
)
103 struct win64_call_frame
*frame
;
105 FFI_ASSERT(cif
->abi
== FFI_WIN64
);
110 /* If we have no return value for a structure, we need to create one.
111 Otherwise we can ignore the return type entirely. */
114 if (flags
== FFI_TYPE_STRUCT
)
115 rsize
= cif
->rtype
->size
;
117 flags
= FFI_TYPE_VOID
;
120 stack
= alloca(cif
->bytes
+ sizeof(struct win64_call_frame
) + rsize
);
121 frame
= (struct win64_call_frame
*)((char *)stack
+ cif
->bytes
);
125 frame
->fn
= (uintptr_t)fn
;
126 frame
->flags
= flags
;
127 frame
->rvalue
= (uintptr_t)rvalue
;
130 if (flags
== FFI_TYPE_STRUCT
)
132 stack
[0] = (uintptr_t)rvalue
;
136 for (i
= 0, n
= cif
->nargs
; i
< n
; ++i
, ++j
)
138 switch (cif
->arg_types
[i
]->size
)
141 stack
[j
] = *(UINT64
*)avalue
[i
];
144 stack
[j
] = *(UINT32
*)avalue
[i
];
147 stack
[j
] = *(UINT16
*)avalue
[i
];
150 stack
[j
] = *(UINT8
*)avalue
[i
];
153 stack
[j
] = (uintptr_t)avalue
[i
];
158 ffi_call_win64 (stack
, frame
, closure
);
162 ffi_call (ffi_cif
*cif
, void (*fn
)(void), void *rvalue
, void **avalue
)
164 ffi_call_int (cif
, fn
, rvalue
, avalue
, NULL
);
168 ffi_call_go (ffi_cif
*cif
, void (*fn
)(void), void *rvalue
,
169 void **avalue
, void *closure
)
171 ffi_call_int (cif
, fn
, rvalue
, avalue
, closure
);
175 extern void ffi_closure_win64(void) FFI_HIDDEN
;
176 extern void ffi_go_closure_win64(void) FFI_HIDDEN
;
179 ffi_prep_closure_loc (ffi_closure
* closure
,
181 void (*fun
)(ffi_cif
*, void*, void**, void*),
185 static const unsigned char trampoline
[16] = {
186 /* leaq -0x7(%rip),%r10 # 0x0 */
187 0x4c, 0x8d, 0x15, 0xf9, 0xff, 0xff, 0xff,
188 /* jmpq *0x3(%rip) # 0x10 */
189 0xff, 0x25, 0x03, 0x00, 0x00, 0x00,
193 unsigned char *tramp
= closure
->tramp
;
195 if (cif
->abi
!= FFI_WIN64
)
198 memcpy (tramp
, trampoline
, sizeof(trampoline
));
199 *(UINT64
*)(tramp
+ 16) = (uintptr_t)ffi_closure_win64
;
203 closure
->user_data
= user_data
;
209 ffi_prep_go_closure (ffi_go_closure
* closure
, ffi_cif
* cif
,
210 void (*fun
)(ffi_cif
*, void*, void**, void*))
212 if (cif
->abi
!= FFI_WIN64
)
215 closure
->tramp
= ffi_go_closure_win64
;
222 struct win64_closure_frame
231 ffi_closure_win64_inner(ffi_cif
*cif
,
232 void (*fun
)(ffi_cif
*, void*, void**, void*),
234 struct win64_closure_frame
*frame
)
238 int i
, n
, nreg
, flags
;
240 avalue
= alloca(cif
->nargs
* sizeof(void *));
241 rvalue
= frame
->rvalue
;
244 /* When returning a structure, the address is in the first argument.
245 We must also be prepared to return the same address in eax, so
246 install that address in the frame and pretend we return a pointer. */
248 if (flags
== FFI_TYPE_STRUCT
)
250 rvalue
= (void *)(uintptr_t)frame
->args
[0];
251 frame
->rvalue
[0] = frame
->args
[0];
255 for (i
= 0, n
= cif
->nargs
; i
< n
; ++i
, ++nreg
)
257 size_t size
= cif
->arg_types
[i
]->size
;
258 size_t type
= cif
->arg_types
[i
]->type
;
261 if (type
== FFI_TYPE_DOUBLE
|| type
== FFI_TYPE_FLOAT
)
264 a
= &frame
->fargs
[nreg
];
266 a
= &frame
->args
[nreg
];
268 else if (size
== 1 || size
== 2 || size
== 4 || size
== 8)
269 a
= &frame
->args
[nreg
];
271 a
= (void *)(uintptr_t)frame
->args
[nreg
];
276 /* Invoke the closure. */
277 fun (cif
, rvalue
, avalue
, user_data
);
281 #endif /* X86_WIN64 */