]>
Commit | Line | Data |
---|---|---|
b1760f7f RH |
1 | /* ----------------------------------------------------------------------- |
2 | ffi.c - Copyright (c) 1996, 1998, 1999, 2001, 2007, 2008 Red Hat, Inc. | |
3 | Copyright (c) 2002 Ranjit Mathew | |
4 | Copyright (c) 2002 Bo Thorsen | |
5 | Copyright (c) 2002 Roger Sayle | |
6 | Copyright (C) 2008, 2010 Free Software Foundation, Inc. | |
7 | ||
8 | x86 Foreign Function Interface | |
9 | ||
10 | Permission is hereby granted, free of charge, to any person obtaining | |
11 | a copy of this software and associated documentation files (the | |
12 | ``Software''), to deal in the Software without restriction, including | |
13 | without limitation the rights to use, copy, modify, merge, publish, | |
14 | distribute, sublicense, and/or sell copies of the Software, and to | |
15 | permit persons to whom the Software is furnished to do so, subject to | |
16 | the following conditions: | |
17 | ||
18 | The above copyright notice and this permission notice shall be included | |
19 | in all copies or substantial portions of the Software. | |
20 | ||
21 | THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, | |
22 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
23 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
24 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | |
25 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
26 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
27 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
28 | DEALINGS IN THE SOFTWARE. | |
29 | ----------------------------------------------------------------------- */ | |
30 | ||
31 | #if !defined(__x86_64__) || defined(_WIN64) || defined(__CYGWIN__) | |
32 | ||
33 | #ifdef _WIN64 | |
34 | #include <windows.h> | |
35 | #endif | |
36 | ||
37 | #include <ffi.h> | |
38 | #include <ffi_common.h> | |
39 | ||
40 | #include <stdlib.h> | |
41 | ||
42 | /* ffi_prep_args is called by the assembly routine once stack space | |
43 | has been allocated for the function's arguments */ | |
44 | ||
45 | void ffi_prep_args(char *stack, extended_cif *ecif) | |
46 | { | |
47 | register unsigned int i; | |
48 | register void **p_argv; | |
49 | register char *argp; | |
50 | register ffi_type **p_arg; | |
51 | #ifdef X86_WIN32 | |
52 | size_t p_stack_args[2]; | |
53 | void *p_stack_data[2]; | |
54 | char *argp2 = stack; | |
55 | int stack_args_count = 0; | |
56 | int cabi = ecif->cif->abi; | |
57 | #endif | |
58 | ||
59 | argp = stack; | |
60 | ||
61 | if ((ecif->cif->flags == FFI_TYPE_STRUCT | |
62 | || ecif->cif->flags == FFI_TYPE_MS_STRUCT) | |
63 | #ifdef X86_WIN64 | |
64 | && (ecif->cif->rtype->size != 1 && ecif->cif->rtype->size != 2 | |
65 | && ecif->cif->rtype->size != 4 && ecif->cif->rtype->size != 8) | |
66 | #endif | |
67 | ) | |
68 | { | |
69 | *(void **) argp = ecif->rvalue; | |
70 | #ifdef X86_WIN32 | |
71 | /* For fastcall/thiscall this is first register-passed | |
72 | argument. */ | |
73 | if (cabi == FFI_THISCALL || cabi == FFI_FASTCALL) | |
74 | { | |
75 | p_stack_args[stack_args_count] = sizeof (void*); | |
76 | p_stack_data[stack_args_count] = argp; | |
77 | ++stack_args_count; | |
78 | } | |
79 | #endif | |
80 | argp += sizeof(void*); | |
81 | } | |
82 | ||
83 | p_argv = ecif->avalue; | |
84 | ||
85 | for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; | |
86 | i != 0; | |
87 | i--, p_arg++) | |
88 | { | |
89 | size_t z; | |
90 | ||
91 | /* Align if necessary */ | |
92 | if ((sizeof(void*) - 1) & (size_t) argp) | |
93 | argp = (char *) ALIGN(argp, sizeof(void*)); | |
94 | ||
95 | z = (*p_arg)->size; | |
96 | #ifdef X86_WIN64 | |
97 | if (z > sizeof(ffi_arg) | |
98 | || ((*p_arg)->type == FFI_TYPE_STRUCT | |
99 | && (z != 1 && z != 2 && z != 4 && z != 8)) | |
100 | #if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE | |
101 | || ((*p_arg)->type == FFI_TYPE_LONGDOUBLE) | |
102 | #endif | |
103 | ) | |
104 | { | |
105 | z = sizeof(ffi_arg); | |
106 | *(void **)argp = *p_argv; | |
107 | } | |
108 | else if ((*p_arg)->type == FFI_TYPE_FLOAT) | |
109 | { | |
110 | memcpy(argp, *p_argv, z); | |
111 | } | |
112 | else | |
113 | #endif | |
114 | if (z < sizeof(ffi_arg)) | |
115 | { | |
116 | z = sizeof(ffi_arg); | |
117 | switch ((*p_arg)->type) | |
118 | { | |
119 | case FFI_TYPE_SINT8: | |
120 | *(ffi_sarg *) argp = (ffi_sarg)*(SINT8 *)(* p_argv); | |
121 | break; | |
122 | ||
123 | case FFI_TYPE_UINT8: | |
124 | *(ffi_arg *) argp = (ffi_arg)*(UINT8 *)(* p_argv); | |
125 | break; | |
126 | ||
127 | case FFI_TYPE_SINT16: | |
128 | *(ffi_sarg *) argp = (ffi_sarg)*(SINT16 *)(* p_argv); | |
129 | break; | |
130 | ||
131 | case FFI_TYPE_UINT16: | |
132 | *(ffi_arg *) argp = (ffi_arg)*(UINT16 *)(* p_argv); | |
133 | break; | |
134 | ||
135 | case FFI_TYPE_SINT32: | |
136 | *(ffi_sarg *) argp = (ffi_sarg)*(SINT32 *)(* p_argv); | |
137 | break; | |
138 | ||
139 | case FFI_TYPE_UINT32: | |
140 | *(ffi_arg *) argp = (ffi_arg)*(UINT32 *)(* p_argv); | |
141 | break; | |
142 | ||
143 | case FFI_TYPE_STRUCT: | |
144 | *(ffi_arg *) argp = *(ffi_arg *)(* p_argv); | |
145 | break; | |
146 | ||
147 | default: | |
148 | FFI_ASSERT(0); | |
149 | } | |
150 | } | |
151 | else | |
152 | { | |
153 | memcpy(argp, *p_argv, z); | |
154 | } | |
155 | ||
156 | #ifdef X86_WIN32 | |
157 | /* For thiscall/fastcall convention register-passed arguments | |
158 | are the first two none-floating-point arguments with a size | |
159 | smaller or equal to sizeof (void*). */ | |
160 | if ((cabi == FFI_THISCALL && stack_args_count < 1) | |
161 | || (cabi == FFI_FASTCALL && stack_args_count < 2)) | |
162 | { | |
163 | if (z <= 4 | |
164 | && ((*p_arg)->type != FFI_TYPE_FLOAT | |
165 | && (*p_arg)->type != FFI_TYPE_STRUCT)) | |
166 | { | |
167 | p_stack_args[stack_args_count] = z; | |
168 | p_stack_data[stack_args_count] = argp; | |
169 | ++stack_args_count; | |
170 | } | |
171 | } | |
172 | #endif | |
173 | p_argv++; | |
174 | #ifdef X86_WIN64 | |
175 | argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1); | |
176 | #else | |
177 | argp += z; | |
178 | #endif | |
179 | } | |
180 | ||
181 | #ifdef X86_WIN32 | |
182 | /* We need to move the register-passed arguments for thiscall/fastcall | |
183 | on top of stack, so that those can be moved to registers ecx/edx by | |
184 | call-handler. */ | |
185 | if (stack_args_count > 0) | |
186 | { | |
187 | size_t zz = (p_stack_args[0] + 3) & ~3; | |
188 | char *h; | |
189 | ||
190 | /* Move first argument to top-stack position. */ | |
191 | if (p_stack_data[0] != argp2) | |
192 | { | |
193 | h = alloca (zz + 1); | |
194 | memcpy (h, p_stack_data[0], zz); | |
195 | memmove (argp2 + zz, argp2, | |
196 | (size_t) ((char *) p_stack_data[0] - (char*)argp2)); | |
197 | memcpy (argp2, h, zz); | |
198 | } | |
199 | ||
200 | argp2 += zz; | |
201 | --stack_args_count; | |
202 | if (zz > 4) | |
203 | stack_args_count = 0; | |
204 | ||
205 | /* If we have a second argument, then move it on top | |
206 | after the first one. */ | |
207 | if (stack_args_count > 0 && p_stack_data[1] != argp2) | |
208 | { | |
209 | zz = p_stack_args[1]; | |
210 | zz = (zz + 3) & ~3; | |
211 | h = alloca (zz + 1); | |
212 | h = alloca (zz + 1); | |
213 | memcpy (h, p_stack_data[1], zz); | |
214 | memmove (argp2 + zz, argp2, (size_t) ((char*) p_stack_data[1] - (char*)argp2)); | |
215 | memcpy (argp2, h, zz); | |
216 | } | |
217 | } | |
218 | #endif | |
219 | return; | |
220 | } | |
221 | ||
222 | /* Perform machine dependent cif processing */ | |
223 | ffi_status ffi_prep_cif_machdep(ffi_cif *cif) | |
224 | { | |
225 | unsigned int i; | |
226 | ffi_type **ptr; | |
227 | ||
228 | /* Set the return type flag */ | |
229 | switch (cif->rtype->type) | |
230 | { | |
231 | case FFI_TYPE_VOID: | |
232 | case FFI_TYPE_UINT8: | |
233 | case FFI_TYPE_UINT16: | |
234 | case FFI_TYPE_SINT8: | |
235 | case FFI_TYPE_SINT16: | |
236 | #ifdef X86_WIN64 | |
237 | case FFI_TYPE_UINT32: | |
238 | case FFI_TYPE_SINT32: | |
239 | #endif | |
240 | case FFI_TYPE_SINT64: | |
241 | case FFI_TYPE_FLOAT: | |
242 | case FFI_TYPE_DOUBLE: | |
243 | #ifndef X86_WIN64 | |
244 | #if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE | |
245 | case FFI_TYPE_LONGDOUBLE: | |
246 | #endif | |
247 | #endif | |
248 | cif->flags = (unsigned) cif->rtype->type; | |
249 | break; | |
250 | ||
251 | case FFI_TYPE_UINT64: | |
252 | #ifdef X86_WIN64 | |
253 | case FFI_TYPE_POINTER: | |
254 | #endif | |
255 | cif->flags = FFI_TYPE_SINT64; | |
256 | break; | |
257 | ||
258 | case FFI_TYPE_STRUCT: | |
259 | #ifndef X86 | |
260 | if (cif->rtype->size == 1) | |
261 | { | |
262 | cif->flags = FFI_TYPE_SMALL_STRUCT_1B; /* same as char size */ | |
263 | } | |
264 | else if (cif->rtype->size == 2) | |
265 | { | |
266 | cif->flags = FFI_TYPE_SMALL_STRUCT_2B; /* same as short size */ | |
267 | } | |
268 | else if (cif->rtype->size == 4) | |
269 | { | |
270 | #ifdef X86_WIN64 | |
271 | cif->flags = FFI_TYPE_SMALL_STRUCT_4B; | |
272 | #else | |
273 | cif->flags = FFI_TYPE_INT; /* same as int type */ | |
274 | #endif | |
275 | } | |
276 | else if (cif->rtype->size == 8) | |
277 | { | |
278 | cif->flags = FFI_TYPE_SINT64; /* same as int64 type */ | |
279 | } | |
280 | else | |
281 | #endif | |
282 | { | |
283 | #ifdef X86_WIN32 | |
284 | if (cif->abi == FFI_MS_CDECL) | |
285 | cif->flags = FFI_TYPE_MS_STRUCT; | |
286 | else | |
287 | #endif | |
288 | cif->flags = FFI_TYPE_STRUCT; | |
289 | /* allocate space for return value pointer */ | |
290 | cif->bytes += ALIGN(sizeof(void*), FFI_SIZEOF_ARG); | |
291 | } | |
292 | break; | |
293 | ||
294 | default: | |
295 | #ifdef X86_WIN64 | |
296 | cif->flags = FFI_TYPE_SINT64; | |
297 | break; | |
298 | case FFI_TYPE_INT: | |
299 | cif->flags = FFI_TYPE_SINT32; | |
300 | #else | |
301 | cif->flags = FFI_TYPE_INT; | |
302 | #endif | |
303 | break; | |
304 | } | |
305 | ||
306 | for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) | |
307 | { | |
308 | if (((*ptr)->alignment - 1) & cif->bytes) | |
309 | cif->bytes = ALIGN(cif->bytes, (*ptr)->alignment); | |
310 | cif->bytes += ALIGN((*ptr)->size, FFI_SIZEOF_ARG); | |
311 | } | |
312 | ||
313 | #ifdef X86_WIN64 | |
314 | /* ensure space for storing four registers */ | |
315 | cif->bytes += 4 * sizeof(ffi_arg); | |
316 | #endif | |
317 | ||
318 | #ifdef X86_DARWIN | |
319 | cif->bytes = (cif->bytes + 15) & ~0xF; | |
320 | #endif | |
321 | ||
322 | return FFI_OK; | |
323 | } | |
324 | ||
325 | #ifdef X86_WIN64 | |
326 | extern int | |
327 | ffi_call_win64(void (*)(char *, extended_cif *), extended_cif *, | |
328 | unsigned, unsigned, unsigned *, void (*fn)(void)); | |
329 | #elif defined(X86_WIN32) | |
330 | extern void | |
331 | ffi_call_win32(void (*)(char *, extended_cif *), extended_cif *, | |
332 | unsigned, unsigned, unsigned, unsigned *, void (*fn)(void)); | |
333 | #else | |
334 | extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *, | |
335 | unsigned, unsigned, unsigned *, void (*fn)(void)); | |
336 | #endif | |
337 | ||
338 | void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) | |
339 | { | |
340 | extended_cif ecif; | |
341 | ||
342 | ecif.cif = cif; | |
343 | ecif.avalue = avalue; | |
344 | ||
345 | /* If the return value is a struct and we don't have a return */ | |
346 | /* value address then we need to make one */ | |
347 | ||
348 | #ifdef X86_WIN64 | |
349 | if (rvalue == NULL | |
350 | && cif->flags == FFI_TYPE_STRUCT | |
351 | && cif->rtype->size != 1 && cif->rtype->size != 2 | |
352 | && cif->rtype->size != 4 && cif->rtype->size != 8) | |
353 | { | |
354 | ecif.rvalue = alloca((cif->rtype->size + 0xF) & ~0xF); | |
355 | } | |
356 | #else | |
357 | if (rvalue == NULL | |
358 | && (cif->flags == FFI_TYPE_STRUCT | |
359 | || cif->flags == FFI_TYPE_MS_STRUCT)) | |
360 | { | |
361 | ecif.rvalue = alloca(cif->rtype->size); | |
362 | } | |
363 | #endif | |
364 | else | |
365 | ecif.rvalue = rvalue; | |
366 | ||
367 | ||
368 | switch (cif->abi) | |
369 | { | |
370 | #ifdef X86_WIN64 | |
371 | case FFI_WIN64: | |
372 | ffi_call_win64(ffi_prep_args, &ecif, cif->bytes, | |
373 | cif->flags, ecif.rvalue, fn); | |
374 | break; | |
375 | #elif defined(X86_WIN32) | |
376 | case FFI_SYSV: | |
377 | case FFI_STDCALL: | |
378 | case FFI_MS_CDECL: | |
379 | ffi_call_win32(ffi_prep_args, &ecif, cif->abi, cif->bytes, cif->flags, | |
380 | ecif.rvalue, fn); | |
381 | break; | |
382 | case FFI_THISCALL: | |
383 | case FFI_FASTCALL: | |
384 | { | |
385 | unsigned int abi = cif->abi; | |
386 | unsigned int i, passed_regs = 0; | |
387 | ||
388 | if (cif->flags == FFI_TYPE_STRUCT) | |
389 | ++passed_regs; | |
390 | ||
391 | for (i=0; i < cif->nargs && passed_regs < 2;i++) | |
392 | { | |
393 | size_t sz; | |
394 | ||
395 | if (cif->arg_types[i]->type == FFI_TYPE_FLOAT | |
396 | || cif->arg_types[i]->type == FFI_TYPE_STRUCT) | |
397 | continue; | |
398 | sz = (cif->arg_types[i]->size + 3) & ~3; | |
399 | if (sz == 0 || sz > 4) | |
400 | continue; | |
401 | ++passed_regs; | |
402 | } | |
403 | if (passed_regs < 2 && abi == FFI_FASTCALL) | |
404 | abi = FFI_THISCALL; | |
405 | if (passed_regs < 1 && abi == FFI_THISCALL) | |
406 | abi = FFI_STDCALL; | |
407 | ffi_call_win32(ffi_prep_args, &ecif, abi, cif->bytes, cif->flags, | |
408 | ecif.rvalue, fn); | |
409 | } | |
410 | break; | |
411 | #else | |
412 | case FFI_SYSV: | |
413 | ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, | |
414 | fn); | |
415 | break; | |
416 | #endif | |
417 | default: | |
418 | FFI_ASSERT(0); | |
419 | break; | |
420 | } | |
421 | } | |
422 | ||
423 | ||
424 | /** private members **/ | |
425 | ||
426 | /* The following __attribute__((regparm(1))) decorations will have no effect | |
427 | on MSVC - standard cdecl convention applies. */ | |
428 | static void ffi_prep_incoming_args_SYSV (char *stack, void **ret, | |
429 | void** args, ffi_cif* cif); | |
430 | void FFI_HIDDEN ffi_closure_SYSV (ffi_closure *) | |
431 | __attribute__ ((regparm(1))); | |
432 | unsigned int FFI_HIDDEN ffi_closure_SYSV_inner (ffi_closure *, void **, void *) | |
433 | __attribute__ ((regparm(1))); | |
434 | void FFI_HIDDEN ffi_closure_raw_SYSV (ffi_raw_closure *) | |
435 | __attribute__ ((regparm(1))); | |
436 | #ifdef X86_WIN32 | |
437 | void FFI_HIDDEN ffi_closure_raw_THISCALL (ffi_raw_closure *) | |
438 | __attribute__ ((regparm(1))); | |
439 | void FFI_HIDDEN ffi_closure_STDCALL (ffi_closure *) | |
440 | __attribute__ ((regparm(1))); | |
441 | void FFI_HIDDEN ffi_closure_THISCALL (ffi_closure *) | |
442 | __attribute__ ((regparm(1))); | |
443 | #endif | |
444 | #ifdef X86_WIN64 | |
445 | void FFI_HIDDEN ffi_closure_win64 (ffi_closure *); | |
446 | #endif | |
447 | ||
448 | /* This function is jumped to by the trampoline */ | |
449 | ||
450 | #ifdef X86_WIN64 | |
451 | void * FFI_HIDDEN | |
452 | ffi_closure_win64_inner (ffi_closure *closure, void *args) { | |
453 | ffi_cif *cif; | |
454 | void **arg_area; | |
455 | void *result; | |
456 | void *resp = &result; | |
457 | ||
458 | cif = closure->cif; | |
459 | arg_area = (void**) alloca (cif->nargs * sizeof (void*)); | |
460 | ||
461 | /* this call will initialize ARG_AREA, such that each | |
462 | * element in that array points to the corresponding | |
463 | * value on the stack; and if the function returns | |
464 | * a structure, it will change RESP to point to the | |
465 | * structure return address. */ | |
466 | ||
467 | ffi_prep_incoming_args_SYSV(args, &resp, arg_area, cif); | |
468 | ||
469 | (closure->fun) (cif, resp, arg_area, closure->user_data); | |
470 | ||
471 | /* The result is returned in rax. This does the right thing for | |
472 | result types except for floats; we have to 'mov xmm0, rax' in the | |
473 | caller to correct this. | |
474 | TODO: structure sizes of 3 5 6 7 are returned by reference, too!!! | |
475 | */ | |
476 | return cif->rtype->size > sizeof(void *) ? resp : *(void **)resp; | |
477 | } | |
478 | ||
479 | #else | |
480 | unsigned int FFI_HIDDEN __attribute__ ((regparm(1))) | |
481 | ffi_closure_SYSV_inner (ffi_closure *closure, void **respp, void *args) | |
482 | { | |
483 | /* our various things... */ | |
484 | ffi_cif *cif; | |
485 | void **arg_area; | |
486 | ||
487 | cif = closure->cif; | |
488 | arg_area = (void**) alloca (cif->nargs * sizeof (void*)); | |
489 | ||
490 | /* this call will initialize ARG_AREA, such that each | |
491 | * element in that array points to the corresponding | |
492 | * value on the stack; and if the function returns | |
493 | * a structure, it will change RESP to point to the | |
494 | * structure return address. */ | |
495 | ||
496 | ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif); | |
497 | ||
498 | (closure->fun) (cif, *respp, arg_area, closure->user_data); | |
499 | ||
500 | return cif->flags; | |
501 | } | |
502 | #endif /* !X86_WIN64 */ | |
503 | ||
504 | static void | |
505 | ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue, | |
506 | ffi_cif *cif) | |
507 | { | |
508 | register unsigned int i; | |
509 | register void **p_argv; | |
510 | register char *argp; | |
511 | register ffi_type **p_arg; | |
512 | ||
513 | argp = stack; | |
514 | ||
515 | #ifdef X86_WIN64 | |
516 | if (cif->rtype->size > sizeof(ffi_arg) | |
517 | || (cif->flags == FFI_TYPE_STRUCT | |
518 | && (cif->rtype->size != 1 && cif->rtype->size != 2 | |
519 | && cif->rtype->size != 4 && cif->rtype->size != 8))) { | |
520 | *rvalue = *(void **) argp; | |
521 | argp += sizeof(void *); | |
522 | } | |
523 | #else | |
524 | if ( cif->flags == FFI_TYPE_STRUCT | |
525 | || cif->flags == FFI_TYPE_MS_STRUCT ) { | |
526 | *rvalue = *(void **) argp; | |
527 | argp += sizeof(void *); | |
528 | } | |
529 | #endif | |
530 | ||
531 | p_argv = avalue; | |
532 | ||
533 | for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) | |
534 | { | |
535 | size_t z; | |
536 | ||
537 | /* Align if necessary */ | |
538 | if ((sizeof(void*) - 1) & (size_t) argp) { | |
539 | argp = (char *) ALIGN(argp, sizeof(void*)); | |
540 | } | |
541 | ||
542 | #ifdef X86_WIN64 | |
543 | if ((*p_arg)->size > sizeof(ffi_arg) | |
544 | || ((*p_arg)->type == FFI_TYPE_STRUCT | |
545 | && ((*p_arg)->size != 1 && (*p_arg)->size != 2 | |
546 | && (*p_arg)->size != 4 && (*p_arg)->size != 8))) | |
547 | { | |
548 | z = sizeof(void *); | |
549 | *p_argv = *(void **)argp; | |
550 | } | |
551 | else | |
552 | #endif | |
553 | { | |
554 | z = (*p_arg)->size; | |
555 | ||
556 | /* because we're little endian, this is what it turns into. */ | |
557 | ||
558 | *p_argv = (void*) argp; | |
559 | } | |
560 | ||
561 | p_argv++; | |
562 | #ifdef X86_WIN64 | |
563 | argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1); | |
564 | #else | |
565 | argp += z; | |
566 | #endif | |
567 | } | |
568 | ||
569 | return; | |
570 | } | |
571 | ||
572 | #define FFI_INIT_TRAMPOLINE_WIN64(TRAMP,FUN,CTX,MASK) \ | |
573 | { unsigned char *__tramp = (unsigned char*)(TRAMP); \ | |
574 | void* __fun = (void*)(FUN); \ | |
575 | void* __ctx = (void*)(CTX); \ | |
576 | *(unsigned char*) &__tramp[0] = 0x41; \ | |
577 | *(unsigned char*) &__tramp[1] = 0xbb; \ | |
578 | *(unsigned int*) &__tramp[2] = MASK; /* mov $mask, %r11 */ \ | |
579 | *(unsigned char*) &__tramp[6] = 0x48; \ | |
580 | *(unsigned char*) &__tramp[7] = 0xb8; \ | |
581 | *(void**) &__tramp[8] = __ctx; /* mov __ctx, %rax */ \ | |
582 | *(unsigned char *) &__tramp[16] = 0x49; \ | |
583 | *(unsigned char *) &__tramp[17] = 0xba; \ | |
584 | *(void**) &__tramp[18] = __fun; /* mov __fun, %r10 */ \ | |
585 | *(unsigned char *) &__tramp[26] = 0x41; \ | |
586 | *(unsigned char *) &__tramp[27] = 0xff; \ | |
587 | *(unsigned char *) &__tramp[28] = 0xe2; /* jmp %r10 */ \ | |
588 | } | |
589 | ||
590 | /* How to make a trampoline. Derived from gcc/config/i386/i386.c. */ | |
591 | ||
592 | #define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \ | |
593 | { unsigned char *__tramp = (unsigned char*)(TRAMP); \ | |
594 | unsigned int __fun = (unsigned int)(FUN); \ | |
595 | unsigned int __ctx = (unsigned int)(CTX); \ | |
596 | unsigned int __dis = __fun - (__ctx + 10); \ | |
597 | *(unsigned char*) &__tramp[0] = 0xb8; \ | |
598 | *(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \ | |
599 | *(unsigned char *) &__tramp[5] = 0xe9; \ | |
600 | *(unsigned int*) &__tramp[6] = __dis; /* jmp __fun */ \ | |
601 | } | |
602 | ||
603 | #define FFI_INIT_TRAMPOLINE_THISCALL(TRAMP,FUN,CTX,SIZE) \ | |
604 | { unsigned char *__tramp = (unsigned char*)(TRAMP); \ | |
605 | unsigned int __fun = (unsigned int)(FUN); \ | |
606 | unsigned int __ctx = (unsigned int)(CTX); \ | |
607 | unsigned int __dis = __fun - (__ctx + 49); \ | |
608 | unsigned short __size = (unsigned short)(SIZE); \ | |
609 | *(unsigned int *) &__tramp[0] = 0x8324048b; /* mov (%esp), %eax */ \ | |
610 | *(unsigned int *) &__tramp[4] = 0x4c890cec; /* sub $12, %esp */ \ | |
611 | *(unsigned int *) &__tramp[8] = 0x04890424; /* mov %ecx, 4(%esp) */ \ | |
612 | *(unsigned char*) &__tramp[12] = 0x24; /* mov %eax, (%esp) */ \ | |
613 | *(unsigned char*) &__tramp[13] = 0xb8; \ | |
614 | *(unsigned int *) &__tramp[14] = __size; /* mov __size, %eax */ \ | |
615 | *(unsigned int *) &__tramp[18] = 0x08244c8d; /* lea 8(%esp), %ecx */ \ | |
616 | *(unsigned int *) &__tramp[22] = 0x4802e8c1; /* shr $2, %eax ; dec %eax */ \ | |
617 | *(unsigned short*) &__tramp[26] = 0x0b74; /* jz 1f */ \ | |
618 | *(unsigned int *) &__tramp[28] = 0x8908518b; /* 2b: mov 8(%ecx), %edx */ \ | |
619 | *(unsigned int *) &__tramp[32] = 0x04c18311; /* mov %edx, (%ecx) ; add $4, %ecx */ \ | |
620 | *(unsigned char*) &__tramp[36] = 0x48; /* dec %eax */ \ | |
621 | *(unsigned short*) &__tramp[37] = 0xf575; /* jnz 2b ; 1f: */ \ | |
622 | *(unsigned char*) &__tramp[39] = 0xb8; \ | |
623 | *(unsigned int*) &__tramp[40] = __ctx; /* movl __ctx, %eax */ \ | |
624 | *(unsigned char *) &__tramp[44] = 0xe8; \ | |
625 | *(unsigned int*) &__tramp[45] = __dis; /* call __fun */ \ | |
626 | *(unsigned char*) &__tramp[49] = 0xc2; /* ret */ \ | |
627 | *(unsigned short*) &__tramp[50] = (__size + 8); /* ret (__size + 8) */ \ | |
628 | } | |
629 | ||
630 | #define FFI_INIT_TRAMPOLINE_STDCALL(TRAMP,FUN,CTX,SIZE) \ | |
631 | { unsigned char *__tramp = (unsigned char*)(TRAMP); \ | |
632 | unsigned int __fun = (unsigned int)(FUN); \ | |
633 | unsigned int __ctx = (unsigned int)(CTX); \ | |
634 | unsigned int __dis = __fun - (__ctx + 10); \ | |
635 | unsigned short __size = (unsigned short)(SIZE); \ | |
636 | *(unsigned char*) &__tramp[0] = 0xb8; \ | |
637 | *(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \ | |
638 | *(unsigned char *) &__tramp[5] = 0xe8; \ | |
639 | *(unsigned int*) &__tramp[6] = __dis; /* call __fun */ \ | |
640 | *(unsigned char *) &__tramp[10] = 0xc2; \ | |
641 | *(unsigned short*) &__tramp[11] = __size; /* ret __size */ \ | |
642 | } | |
643 | ||
644 | /* the cif must already be prep'ed */ | |
645 | ||
646 | ffi_status | |
647 | ffi_prep_closure_loc (ffi_closure* closure, | |
648 | ffi_cif* cif, | |
649 | void (*fun)(ffi_cif*,void*,void**,void*), | |
650 | void *user_data, | |
651 | void *codeloc) | |
652 | { | |
653 | #ifdef X86_WIN64 | |
654 | #define ISFLOAT(IDX) (cif->arg_types[IDX]->type == FFI_TYPE_FLOAT || cif->arg_types[IDX]->type == FFI_TYPE_DOUBLE) | |
655 | #define FLAG(IDX) (cif->nargs>(IDX)&&ISFLOAT(IDX)?(1<<(IDX)):0) | |
656 | if (cif->abi == FFI_WIN64) | |
657 | { | |
658 | int mask = FLAG(0)|FLAG(1)|FLAG(2)|FLAG(3); | |
659 | FFI_INIT_TRAMPOLINE_WIN64 (&closure->tramp[0], | |
660 | &ffi_closure_win64, | |
661 | codeloc, mask); | |
662 | /* make sure we can execute here */ | |
663 | } | |
664 | #else | |
665 | if (cif->abi == FFI_SYSV) | |
666 | { | |
667 | FFI_INIT_TRAMPOLINE (&closure->tramp[0], | |
668 | &ffi_closure_SYSV, | |
669 | (void*)codeloc); | |
670 | } | |
671 | #ifdef X86_WIN32 | |
672 | else if (cif->abi == FFI_THISCALL) | |
673 | { | |
674 | FFI_INIT_TRAMPOLINE_THISCALL (&closure->tramp[0], | |
675 | &ffi_closure_THISCALL, | |
676 | (void*)codeloc, | |
677 | cif->bytes); | |
678 | } | |
679 | else if (cif->abi == FFI_STDCALL) | |
680 | { | |
681 | FFI_INIT_TRAMPOLINE_STDCALL (&closure->tramp[0], | |
682 | &ffi_closure_STDCALL, | |
683 | (void*)codeloc, cif->bytes); | |
684 | } | |
685 | else if (cif->abi == FFI_MS_CDECL) | |
686 | { | |
687 | FFI_INIT_TRAMPOLINE (&closure->tramp[0], | |
688 | &ffi_closure_SYSV, | |
689 | (void*)codeloc); | |
690 | } | |
691 | #endif /* X86_WIN32 */ | |
692 | #endif /* !X86_WIN64 */ | |
693 | else | |
694 | { | |
695 | return FFI_BAD_ABI; | |
696 | } | |
697 | ||
698 | closure->cif = cif; | |
699 | closure->user_data = user_data; | |
700 | closure->fun = fun; | |
701 | ||
702 | return FFI_OK; | |
703 | } | |
704 | ||
705 | /* ------- Native raw API support -------------------------------- */ | |
706 | ||
707 | #if !FFI_NO_RAW_API | |
708 | ||
709 | ffi_status | |
710 | ffi_prep_raw_closure_loc (ffi_raw_closure* closure, | |
711 | ffi_cif* cif, | |
712 | void (*fun)(ffi_cif*,void*,ffi_raw*,void*), | |
713 | void *user_data, | |
714 | void *codeloc) | |
715 | { | |
716 | int i; | |
717 | ||
718 | if (cif->abi != FFI_SYSV) { | |
719 | #ifdef X86_WIN32 | |
720 | if (cif->abi != FFI_THISCALL) | |
721 | #endif | |
722 | return FFI_BAD_ABI; | |
723 | } | |
724 | ||
725 | /* we currently don't support certain kinds of arguments for raw | |
726 | closures. This should be implemented by a separate assembly | |
727 | language routine, since it would require argument processing, | |
728 | something we don't do now for performance. */ | |
729 | ||
730 | for (i = cif->nargs-1; i >= 0; i--) | |
731 | { | |
732 | FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_STRUCT); | |
733 | FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE); | |
734 | } | |
735 | ||
736 | #ifdef X86_WIN32 | |
737 | if (cif->abi == FFI_SYSV) | |
738 | { | |
739 | #endif | |
740 | FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV, | |
741 | codeloc); | |
742 | #ifdef X86_WIN32 | |
743 | } | |
744 | else if (cif->abi == FFI_THISCALL) | |
745 | { | |
746 | FFI_INIT_TRAMPOLINE_THISCALL (&closure->tramp[0], &ffi_closure_raw_THISCALL, | |
747 | codeloc, cif->bytes); | |
748 | } | |
749 | #endif | |
750 | closure->cif = cif; | |
751 | closure->user_data = user_data; | |
752 | closure->fun = fun; | |
753 | ||
754 | return FFI_OK; | |
755 | } | |
756 | ||
757 | static void | |
758 | ffi_prep_args_raw(char *stack, extended_cif *ecif) | |
759 | { | |
760 | memcpy (stack, ecif->avalue, ecif->cif->bytes); | |
761 | } | |
762 | ||
763 | /* we borrow this routine from libffi (it must be changed, though, to | |
764 | * actually call the function passed in the first argument. as of | |
765 | * libffi-1.20, this is not the case.) | |
766 | */ | |
767 | ||
768 | void | |
769 | ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *fake_avalue) | |
770 | { | |
771 | extended_cif ecif; | |
772 | void **avalue = (void **)fake_avalue; | |
773 | ||
774 | ecif.cif = cif; | |
775 | ecif.avalue = avalue; | |
776 | ||
777 | /* If the return value is a struct and we don't have a return */ | |
778 | /* value address then we need to make one */ | |
779 | ||
780 | if (rvalue == NULL | |
781 | && (cif->flags == FFI_TYPE_STRUCT | |
782 | || cif->flags == FFI_TYPE_MS_STRUCT)) | |
783 | { | |
784 | ecif.rvalue = alloca(cif->rtype->size); | |
785 | } | |
786 | else | |
787 | ecif.rvalue = rvalue; | |
788 | ||
789 | ||
790 | switch (cif->abi) | |
791 | { | |
792 | #ifdef X86_WIN32 | |
793 | case FFI_SYSV: | |
794 | case FFI_STDCALL: | |
795 | case FFI_MS_CDECL: | |
796 | ffi_call_win32(ffi_prep_args_raw, &ecif, cif->abi, cif->bytes, cif->flags, | |
797 | ecif.rvalue, fn); | |
798 | break; | |
799 | case FFI_THISCALL: | |
800 | case FFI_FASTCALL: | |
801 | { | |
802 | unsigned int abi = cif->abi; | |
803 | unsigned int i, passed_regs = 0; | |
804 | ||
805 | if (cif->flags == FFI_TYPE_STRUCT) | |
806 | ++passed_regs; | |
807 | ||
808 | for (i=0; i < cif->nargs && passed_regs < 2;i++) | |
809 | { | |
810 | size_t sz; | |
811 | ||
812 | if (cif->arg_types[i]->type == FFI_TYPE_FLOAT | |
813 | || cif->arg_types[i]->type == FFI_TYPE_STRUCT) | |
814 | continue; | |
815 | sz = (cif->arg_types[i]->size + 3) & ~3; | |
816 | if (sz == 0 || sz > 4) | |
817 | continue; | |
818 | ++passed_regs; | |
819 | } | |
820 | if (passed_regs < 2 && abi == FFI_FASTCALL) | |
821 | cif->abi = abi = FFI_THISCALL; | |
822 | if (passed_regs < 1 && abi == FFI_THISCALL) | |
823 | cif->abi = abi = FFI_STDCALL; | |
824 | ffi_call_win32(ffi_prep_args_raw, &ecif, abi, cif->bytes, cif->flags, | |
825 | ecif.rvalue, fn); | |
826 | } | |
827 | break; | |
828 | #else | |
829 | case FFI_SYSV: | |
830 | ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags, | |
831 | ecif.rvalue, fn); | |
832 | break; | |
833 | #endif | |
834 | default: | |
835 | FFI_ASSERT(0); | |
836 | break; | |
837 | } | |
838 | } | |
839 | ||
840 | #endif | |
841 | ||
842 | #endif /* !__x86_64__ || X86_WIN64 */ | |
843 |