Ruby: ext/fiddle/libffi-3.2.1/src/x86/ffi.c Source File

Ruby 3.0.5p211 (2022-11-24 revision ba5cf0f7c52d4d35cc6a173c89eda98ceffa2dcf)

ffi.c
Go to the documentation of this file.
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
43/* ffi_prep_args is called by the assembly routine once stack space
44 has been allocated for the function's arguments */
45
46unsigned int ffi_prep_args(char *stack, extended_cif *ecif);
47 unsigned int ffi_prep_args(char *stack, extended_cif *ecif)
48{
49 register unsigned int i;
50 register void **p_argv;
51 register char *argp;
52 register ffi_type **p_arg;
53#ifndef X86_WIN64
54 const int cabi = ecif->cif->abi;
55 const int dir = (cabi == FFI_PASCAL || cabi == FFI_REGISTER) ? -1 : +1;
56 unsigned int stack_args_count = 0;
57 void *p_stack_data[3];
58 char *argp2 = stack;
59#else
60 #define dir 1
61#endif
62
63 argp = stack;
64
65 if ((ecif->cif->flags == FFI_TYPE_STRUCT
66 || ecif->cif->flags == FFI_TYPE_MS_STRUCT)
67#ifdef X86_WIN64
68 && ((ecif->cif->rtype->size & (1 | 2 | 4 | 8)) == 0)
69#endif
70 )
71 {
72#ifndef X86_WIN64
73 /* For fastcall/thiscall/register this is first register-passed
74 argument. */
75 if (cabi == FFI_THISCALL || cabi == FFI_FASTCALL || cabi == FFI_REGISTER)
76 {
77 p_stack_data[stack_args_count] = argp;
78 ++stack_args_count;
79 }
80#endif
81
82 *(void **) argp = ecif->rvalue;
83 argp += sizeof(void*);
84 }
85
86 p_arg = ecif->cif->arg_types;
87 p_argv = ecif->avalue;
88 if (dir < 0)
89 {
90 const int nargs = ecif->cif->nargs - 1;
91 if (nargs > 0)
92 {
93 p_arg += nargs;
94 p_argv += nargs;
95 }
96 }
97
98 for (i = ecif->cif->nargs;
99 i != 0;
100 i--, p_arg += dir, p_argv += dir)
101 {
102 size_t z;
103
104 /* Align if necessary */
105 if ((sizeof(void*) - 1) & (size_t) argp)
106 argp = (char *) ALIGN(argp, sizeof(void*));
107
108 z = (*p_arg)->size;
109
110#ifdef X86_WIN64
111 if (z > FFI_SIZEOF_ARG
112 || ((*p_arg)->type == FFI_TYPE_STRUCT
113 && (z & (1 | 2 | 4 | 8)) == 0)
114#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
115 || ((*p_arg)->type == FFI_TYPE_LONGDOUBLE)
116#endif
117 )
118 {
119 z = FFI_SIZEOF_ARG;
120 *(void **)argp = *p_argv;
121 }
122 else if ((*p_arg)->type == FFI_TYPE_FLOAT)
123 {
124 memcpy(argp, *p_argv, z);
125 }
126 else
127#endif
128 if (z < FFI_SIZEOF_ARG)
129 {
130 z = FFI_SIZEOF_ARG;
131 switch ((*p_arg)->type)
132 {
133 case FFI_TYPE_SINT8:
134 *(ffi_sarg *) argp = (ffi_sarg)*(SINT8 *)(* p_argv);
135 break;
136
137 case FFI_TYPE_UINT8:
138 *(ffi_arg *) argp = (ffi_arg)*(UINT8 *)(* p_argv);
139 break;
140
141 case FFI_TYPE_SINT16:
142 *(ffi_sarg *) argp = (ffi_sarg)*(SINT16 *)(* p_argv);
143 break;
144
145 case FFI_TYPE_UINT16:
146 *(ffi_arg *) argp = (ffi_arg)*(UINT16 *)(* p_argv);
147 break;
148
149 case FFI_TYPE_SINT32:
150 *(ffi_sarg *) argp = (ffi_sarg)*(SINT32 *)(* p_argv);
151 break;
152
153 case FFI_TYPE_UINT32:
154 *(ffi_arg *) argp = (ffi_arg)*(UINT32 *)(* p_argv);
155 break;
156
157 case FFI_TYPE_STRUCT:
158 *(ffi_arg *) argp = *(ffi_arg *)(* p_argv);
159 break;
160
161 default:
162 FFI_ASSERT(0);
163 }
164 }
165 else
166 {
167 memcpy(argp, *p_argv, z);
168 }
169
170#ifndef X86_WIN64
171 /* For thiscall/fastcall/register convention register-passed arguments
172 are the first two none-floating-point arguments with a size
173 smaller or equal to sizeof (void*). */
174 if ((z == FFI_SIZEOF_ARG)
175 && ((cabi == FFI_REGISTER)
176 || (cabi == FFI_THISCALL && stack_args_count < 1)
177 || (cabi == FFI_FASTCALL && stack_args_count < 2))
178 && ((*p_arg)->type != FFI_TYPE_FLOAT && (*p_arg)->type != FFI_TYPE_STRUCT)
179 )
180 {
181 if (dir < 0 && stack_args_count > 2)
182 {
183 /* Iterating arguments backwards, so first register-passed argument
184 will be passed last. Shift temporary values to make place. */
185 p_stack_data[0] = p_stack_data[1];
186 p_stack_data[1] = p_stack_data[2];
187 stack_args_count = 2;
188 }
189
190 p_stack_data[stack_args_count] = argp;
191 ++stack_args_count;
192 }
193#endif
194
195#ifdef X86_WIN64
196 argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
197#else
198 argp += z;
199#endif
200 }
201
202#ifndef X86_WIN64
203 /* We need to move the register-passed arguments for thiscall/fastcall/register
204 on top of stack, so that those can be moved to registers by call-handler. */
205 if (stack_args_count > 0)
206 {
207 int i;
208 if (dir < 0 && stack_args_count > 1)
209 {
210 /* Reverse order if iterating arguments backwards */
211 ffi_arg tmp = *(ffi_arg*) p_stack_data[0];
212 *(ffi_arg*) p_stack_data[0] = *(ffi_arg*) p_stack_data[stack_args_count - 1];
213 *(ffi_arg*) p_stack_data[stack_args_count - 1] = tmp;
214 }
215
216 for (i = 0; i < stack_args_count; i++)
217 {
218 if (p_stack_data[i] != argp2)
219 {
220 ffi_arg tmp = *(ffi_arg*) p_stack_data[i];
221 memmove (argp2 + FFI_SIZEOF_ARG, argp2, (size_t) ((char*) p_stack_data[i] - (char*)argp2));
222 *(ffi_arg *) argp2 = tmp;
223 }
224
225 argp2 += FFI_SIZEOF_ARG;
226 }
227 }
228
229 return stack_args_count;
230#endif
231 return 0;
232}
233
234/* Perform machine dependent cif processing */
235ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
236{
237 unsigned int i;
238 ffi_type **ptr;
239
240 /* Set the return type flag */
241 switch (cif->rtype->type)
242 {
243 case FFI_TYPE_VOID:
244 case FFI_TYPE_UINT8:
245 case FFI_TYPE_UINT16:
246 case FFI_TYPE_SINT8:
247 case FFI_TYPE_SINT16:
248#ifdef X86_WIN64
249 case FFI_TYPE_UINT32:
250 case FFI_TYPE_SINT32:
251#endif
252 case FFI_TYPE_SINT64:
253 case FFI_TYPE_FLOAT:
254 case FFI_TYPE_DOUBLE:
255#ifndef X86_WIN64
256#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
257 case FFI_TYPE_LONGDOUBLE:
258#endif
259#endif
260 cif->flags = (unsigned) cif->rtype->type;
261 break;
262
263 case FFI_TYPE_UINT64:
264#ifdef X86_WIN64
265 case FFI_TYPE_POINTER:
266#endif
267 cif->flags = FFI_TYPE_SINT64;
268 break;
269
270 case FFI_TYPE_STRUCT:
271#ifndef X86
272 if (cif->rtype->size == 1)
273 {
274 cif->flags = FFI_TYPE_SMALL_STRUCT_1B; /* same as char size */
275 }
276 else if (cif->rtype->size == 2)
277 {
278 cif->flags = FFI_TYPE_SMALL_STRUCT_2B; /* same as short size */
279 }
280 else if (cif->rtype->size == 4)
281 {
282#ifdef X86_WIN64
283 cif->flags = FFI_TYPE_SMALL_STRUCT_4B;
284#else
285 cif->flags = FFI_TYPE_INT; /* same as int type */
286#endif
287 }
288 else if (cif->rtype->size == 8)
289 {
290 cif->flags = FFI_TYPE_SINT64; /* same as int64 type */
291 }
292 else
293#endif
294 {
295#ifdef X86_WIN32
296 if (cif->abi == FFI_MS_CDECL)
297 cif->flags = FFI_TYPE_MS_STRUCT;
298 else
299#endif
300 cif->flags = FFI_TYPE_STRUCT;
301 /* allocate space for return value pointer */
302 cif->bytes += ALIGN(sizeof(void*), FFI_SIZEOF_ARG);
303 }
304 break;
305
306 default:
307#ifdef X86_WIN64
308 cif->flags = FFI_TYPE_SINT64;
309 break;
310 case FFI_TYPE_INT:
311 cif->flags = FFI_TYPE_SINT32;
312#else
313 cif->flags = FFI_TYPE_INT;
314#endif
315 break;
316 }
317
318 for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
319 {
320 if (((*ptr)->alignment - 1) & cif->bytes)
321 cif->bytes = ALIGN(cif->bytes, (*ptr)->alignment);
322 cif->bytes += (unsigned)ALIGN((*ptr)->size, FFI_SIZEOF_ARG);
323 }
324
325#ifdef X86_WIN64
326 /* ensure space for storing four registers */
327 cif->bytes += 4 * FFI_SIZEOF_ARG;
328#endif
329
330#ifndef X86_WIN32
331#ifndef X86_WIN64
332 if (cif->abi == FFI_SYSV || cif->abi == FFI_UNIX64)
333#endif
334 cif->bytes = (cif->bytes + 15) & ~0xF;
335#endif
336
337 return FFI_OK;
338}
339
340#ifdef X86_WIN64
341extern int
342ffi_call_win64(unsigned int (*)(char *, extended_cif *), extended_cif *,
343 unsigned, unsigned, unsigned *, void (*fn)(void));
344#else
345extern void
346ffi_call_win32(unsigned int (*)(char *, extended_cif *), extended_cif *,
347 unsigned, unsigned, unsigned, unsigned *, void (*fn)(void));
348 extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
349 unsigned, unsigned, unsigned *, void (*fn)(void));
350#endif
351
352 void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
353{
354 extended_cif ecif;
355
356 ecif.cif = cif;
357 ecif.avalue = avalue;
358
359 /* If the return value is a struct and we don't have a return */
360 /* value address then we need to make one */
361
362#ifdef X86_WIN64
363 if (rvalue == NULL
364 && cif->flags == FFI_TYPE_STRUCT
365 && ((cif->rtype->size & (1 | 2 | 4 | 8)) == 0))
366 {
367 ecif.rvalue = alloca((cif->rtype->size + 0xF) & ~0xF);
368 }
369#else
370 if (rvalue == NULL
371 && (cif->flags == FFI_TYPE_STRUCT
372 || cif->flags == FFI_TYPE_MS_STRUCT))
373 {
374 ecif.rvalue = alloca(cif->rtype->size);
375 }
376#endif
377 else
378 ecif.rvalue = rvalue;
379
380
381 switch (cif->abi)
382 {
383#ifdef X86_WIN64
384 case FFI_WIN64:
385 ffi_call_win64(ffi_prep_args, &ecif, cif->bytes,
386 cif->flags, ecif.rvalue, fn);
387 break;
388#else
389#ifndef X86_WIN32
390 case FFI_SYSV:
391 ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
392 fn);
393 break;
394#else
395 case FFI_SYSV:
396 case FFI_MS_CDECL:
397#endif
398 case FFI_STDCALL:
399 case FFI_THISCALL:
400 case FFI_FASTCALL:
401 case FFI_PASCAL:
402 case FFI_REGISTER:
403 ffi_call_win32(ffi_prep_args, &ecif, cif->abi, cif->bytes, cif->flags,
404 ecif.rvalue, fn);
405 break;
406#endif
407 default:
408 FFI_ASSERT(0);
409 break;
410 }
411}
412
413
416/* The following __attribute__((regparm(1))) decorations will have no effect
417 on MSVC or SUNPRO_C -- standard conventions apply. */
418static unsigned int ffi_prep_incoming_args (char *stack, void **ret,
419 void** args, ffi_cif* cif);
420 void FFI_HIDDEN ffi_closure_SYSV (ffi_closure *)
421 __attribute__ ((regparm(1)));
422unsigned int FFI_HIDDEN ffi_closure_SYSV_inner (ffi_closure *, void **, void *)
423 __attribute__ ((regparm(1)));
424unsigned int FFI_HIDDEN ffi_closure_WIN32_inner (ffi_closure *, void **, void *)
425 __attribute__ ((regparm(1)));
426void FFI_HIDDEN ffi_closure_raw_SYSV (ffi_raw_closure *)
427 __attribute__ ((regparm(1)));
428#ifdef X86_WIN32
429void FFI_HIDDEN ffi_closure_raw_THISCALL (ffi_raw_closure *)
430 __attribute__ ((regparm(1)));
431#endif
432#ifndef X86_WIN64
433void FFI_HIDDEN ffi_closure_STDCALL (ffi_closure *);
434void FFI_HIDDEN ffi_closure_THISCALL (ffi_closure *);
435void FFI_HIDDEN ffi_closure_FASTCALL (ffi_closure *);
436void FFI_HIDDEN ffi_closure_REGISTER (ffi_closure *);
437#else
438void FFI_HIDDEN ffi_closure_win64 (ffi_closure *);
439#endif
440
441/* This function is jumped to by the trampoline */
442
443#ifdef X86_WIN64
444void * FFI_HIDDEN
445ffi_closure_win64_inner (ffi_closure *closure, void *args) {
446 ffi_cif *cif;
447 void **arg_area;
448 void *result;
449 void *resp = &result;
450
451 cif = closure->cif;
452 arg_area = (void**) alloca (cif->nargs * sizeof (void*));
453
454 /* this call will initialize ARG_AREA, such that each
455 * element in that array points to the corresponding
456 * value on the stack; and if the function returns
457 * a structure, it will change RESP to point to the
458 * structure return address. */
459
460 ffi_prep_incoming_args(args, &resp, arg_area, cif);
461
462 (closure->fun) (cif, resp, arg_area, closure->user_data);
463
464 /* The result is returned in rax. This does the right thing for
465 result types except for floats; we have to 'mov xmm0, rax' in the
466 caller to correct this.
467 TODO: structure sizes of 3 5 6 7 are returned by reference, too!!!
468 */
469 return cif->rtype->size > sizeof(void *) ? resp : *(void **)resp;
470}
471
472#else
473unsigned int FFI_HIDDEN __attribute__ ((regparm(1)))
474 ffi_closure_SYSV_inner (ffi_closure *closure, void **respp, void *args)
475{
476 /* our various things... */
477 ffi_cif *cif;
478 void **arg_area;
479
480 cif = closure->cif;
481 arg_area = (void**) alloca (cif->nargs * sizeof (void*));
482
483 /* this call will initialize ARG_AREA, such that each
484 * element in that array points to the corresponding
485 * value on the stack; and if the function returns
486 * a structure, it will change RESP to point to the
487 * structure return address. */
488
489 ffi_prep_incoming_args(args, respp, arg_area, cif);
490
491 (closure->fun) (cif, *respp, arg_area, closure->user_data);
492
493 return cif->flags;
494}
495
496 unsigned int FFI_HIDDEN __attribute__ ((regparm(1)))
497ffi_closure_WIN32_inner (ffi_closure *closure, void **respp, void *args)
498{
499 /* our various things... */
500 ffi_cif *cif;
501 void **arg_area;
502 unsigned int ret;
503
504 cif = closure->cif;
505 arg_area = (void**) alloca (cif->nargs * sizeof (void*));
506
507 /* this call will initialize ARG_AREA, such that each
508 * element in that array points to the corresponding
509 * value on the stack; and if the function returns
510 * a structure, it will change RESP to point to the
511 * structure return address. */
512
513 ret = ffi_prep_incoming_args(args, respp, arg_area, cif);
514
515 (closure->fun) (cif, *respp, arg_area, closure->user_data);
516
517 return ret;
518}
519#endif /* !X86_WIN64 */
520
521static unsigned int
522ffi_prep_incoming_args(char *stack, void **rvalue, void **avalue,
523 ffi_cif *cif)
524{
525 register unsigned int i;
526 register void **p_argv;
527 register char *argp;
528 register ffi_type **p_arg;
529#ifndef X86_WIN64
530 const int cabi = cif->abi;
531 const int dir = (cabi == FFI_PASCAL || cabi == FFI_REGISTER) ? -1 : +1;
532 const unsigned int max_stack_count = (cabi == FFI_THISCALL) ? 1
533 : (cabi == FFI_FASTCALL) ? 2
534 : (cabi == FFI_REGISTER) ? 3
535 : 0;
536 unsigned int passed_regs = 0;
537 void *p_stack_data[3] = { stack - 1 };
538#else
539 #define dir 1
540#endif
541
542 argp = stack;
543#ifndef X86_WIN64
544 argp += max_stack_count * FFI_SIZEOF_ARG;
545#endif
546
547 if ((cif->flags == FFI_TYPE_STRUCT
548 || cif->flags == FFI_TYPE_MS_STRUCT)
549#ifdef X86_WIN64
550 && ((cif->rtype->size & (1 | 2 | 4 | 8)) == 0)
551#endif
552 )
553 {
554#ifndef X86_WIN64
555 if (passed_regs < max_stack_count)
556 {
557 *rvalue = *(void**) (stack + (passed_regs*FFI_SIZEOF_ARG));
558 ++passed_regs;
559 }
560 else
561#endif
562 {
563 *rvalue = *(void **) argp;
564 argp += sizeof(void *);
565 }
566 }
567
568#ifndef X86_WIN64
569 /* Do register arguments first */
570 for (i = 0, p_arg = cif->arg_types;
571 i < cif->nargs && passed_regs < max_stack_count;
572 i++, p_arg++)
573 {
574 size_t sz;
575 if ((*p_arg)->type == FFI_TYPE_FLOAT
576 || (*p_arg)->type == FFI_TYPE_STRUCT)
577 continue;
578
579 sz = (*p_arg)->size;
580 if(sz == 0 || sz > FFI_SIZEOF_ARG)
581 continue;
582
583 p_stack_data[passed_regs] = avalue + i;
584 avalue[i] = stack + (passed_regs*FFI_SIZEOF_ARG);
585 ++passed_regs;
586 }
587#endif
588
589 p_arg = cif->arg_types;
590 p_argv = avalue;
591 if (dir < 0)
592 {
593 const int nargs = cif->nargs - 1;
594 if (nargs > 0)
595 {
596 p_arg += nargs;
597 p_argv += nargs;
598 }
599 }
600
601 for (i = cif->nargs;
602 i != 0;
603 i--, p_arg += dir, p_argv += dir)
604 {
605 size_t z;
606
607 /* Align if necessary */
608 if ((sizeof(void*) - 1) & (size_t) argp)
609 argp = (char *) ALIGN(argp, sizeof(void*));
610
611 z = (*p_arg)->size;
612
613#ifdef X86_WIN64
614 if (z > FFI_SIZEOF_ARG
615 || ((*p_arg)->type == FFI_TYPE_STRUCT
616 && (z & (1 | 2 | 4 | 8)) == 0)
617#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
618 || ((*p_arg)->type == FFI_TYPE_LONGDOUBLE)
619#endif
620 )
621 {
622 z = FFI_SIZEOF_ARG;
623 *p_argv = *(void **)argp;
624 }
625 else
626#else
627 if (passed_regs > 0
628 && z <= FFI_SIZEOF_ARG
629 && (p_argv == p_stack_data[0]
630 || p_argv == p_stack_data[1]
631 || p_argv == p_stack_data[2]))
632 {
633 /* Already assigned a register value */
634 continue;
635 }
636 else
637#endif
638 {
639 /* because we're little endian, this is what it turns into. */
640 *p_argv = (void*) argp;
641 }
642
643#ifdef X86_WIN64
644 argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
645#else
646 argp += z;
647#endif
648 }
649
650 return (int)((size_t)argp - (size_t)stack);
651}
652
653#define FFI_INIT_TRAMPOLINE_WIN64(TRAMP,FUN,CTX,MASK) \
654{ unsigned char *__tramp = (unsigned char*)(TRAMP); \
655 void* __fun = (void*)(FUN); \
656 void* __ctx = (void*)(CTX); \
657 *(unsigned char*) &__tramp[0] = 0x41; \
658 *(unsigned char*) &__tramp[1] = 0xbb; \
659 *(unsigned int*) &__tramp[2] = MASK; /* mov $mask, %r11 */ \
660 *(unsigned char*) &__tramp[6] = 0x48; \
661 *(unsigned char*) &__tramp[7] = 0xb8; \
662 *(void**) &__tramp[8] = __ctx; /* mov __ctx, %rax */ \
663 *(unsigned char *) &__tramp[16] = 0x49; \
664 *(unsigned char *) &__tramp[17] = 0xba; \
665 *(void**) &__tramp[18] = __fun; /* mov __fun, %r10 */ \
666 *(unsigned char *) &__tramp[26] = 0x41; \
667 *(unsigned char *) &__tramp[27] = 0xff; \
668 *(unsigned char *) &__tramp[28] = 0xe2; /* jmp %r10 */ \
669 }
670
671/* How to make a trampoline. Derived from gcc/config/i386/i386.c. */
672
673#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \
674{ unsigned char *__tramp = (unsigned char*)(TRAMP); \
675 unsigned int __fun = (unsigned int)(FUN); \
676 unsigned int __ctx = (unsigned int)(CTX); \
677 unsigned int __dis = __fun - (__ctx + 10); \
678 *(unsigned char*) &__tramp[0] = 0xb8; \
679 *(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
680 *(unsigned char*) &__tramp[5] = 0xe9; \
681 *(unsigned int*) &__tramp[6] = __dis; /* jmp __fun */ \
682 }
683
684#define FFI_INIT_TRAMPOLINE_RAW_THISCALL(TRAMP,FUN,CTX,SIZE) \
685{ unsigned char *__tramp = (unsigned char*)(TRAMP); \
686 unsigned int __fun = (unsigned int)(FUN); \
687 unsigned int __ctx = (unsigned int)(CTX); \
688 unsigned int __dis = __fun - (__ctx + 49); \
689 unsigned short __size = (unsigned short)(SIZE); \
690 *(unsigned int *) &__tramp[0] = 0x8324048b; /* mov (%esp), %eax */ \
691 *(unsigned int *) &__tramp[4] = 0x4c890cec; /* sub $12, %esp */ \
692 *(unsigned int *) &__tramp[8] = 0x04890424; /* mov %ecx, 4(%esp) */ \
693 *(unsigned char*) &__tramp[12] = 0x24; /* mov %eax, (%esp) */ \
694 *(unsigned char*) &__tramp[13] = 0xb8; \
695 *(unsigned int *) &__tramp[14] = __size; /* mov __size, %eax */ \
696 *(unsigned int *) &__tramp[18] = 0x08244c8d; /* lea 8(%esp), %ecx */ \
697 *(unsigned int *) &__tramp[22] = 0x4802e8c1; /* shr $2, %eax ; dec %eax */ \
698 *(unsigned short*) &__tramp[26] = 0x0b74; /* jz 1f */ \
699 *(unsigned int *) &__tramp[28] = 0x8908518b; /* 2b: mov 8(%ecx), %edx */ \
700 *(unsigned int *) &__tramp[32] = 0x04c18311; /* mov %edx, (%ecx) ; add $4, %ecx */ \
701 *(unsigned char*) &__tramp[36] = 0x48; /* dec %eax */ \
702 *(unsigned short*) &__tramp[37] = 0xf575; /* jnz 2b ; 1f: */ \
703 *(unsigned char*) &__tramp[39] = 0xb8; \
704 *(unsigned int*) &__tramp[40] = __ctx; /* movl __ctx, %eax */ \
705 *(unsigned char *) &__tramp[44] = 0xe8; \
706 *(unsigned int*) &__tramp[45] = __dis; /* call __fun */ \
707 *(unsigned char*) &__tramp[49] = 0xc2; /* ret */ \
708 *(unsigned short*) &__tramp[50] = (__size + 8); /* ret (__size + 8) */ \
709 }
710
711#define FFI_INIT_TRAMPOLINE_WIN32(TRAMP,FUN,CTX) \
712{ unsigned char *__tramp = (unsigned char*)(TRAMP); \
713 unsigned int __fun = (unsigned int)(FUN); \
714 unsigned int __ctx = (unsigned int)(CTX); \
715 unsigned int __dis = __fun - (__ctx + 10); \
716 *(unsigned char*) &__tramp[0] = 0x68; \
717 *(unsigned int*) &__tramp[1] = __ctx; /* push __ctx */ \
718 *(unsigned char*) &__tramp[5] = 0xe9; \
719 *(unsigned int*) &__tramp[6] = __dis; /* jmp __fun */ \
720 }
721
722/* the cif must already be prep'ed */
723
724ffi_status
725 ffi_prep_closure_loc (ffi_closure* closure,
726 ffi_cif* cif,
727 void (*fun)(ffi_cif*,void*,void**,void*),
728 void *user_data,
729 void *codeloc)
730{
731#ifdef X86_WIN64
732#define ISFLOAT(IDX) (cif->arg_types[IDX]->type == FFI_TYPE_FLOAT || cif->arg_types[IDX]->type == FFI_TYPE_DOUBLE)
733#define FLAG(IDX) (cif->nargs>(IDX)&&ISFLOAT(IDX)?(1<<(IDX)):0)
734 if (cif->abi == FFI_WIN64)
735 {
736 int mask = FLAG(0)|FLAG(1)|FLAG(2)|FLAG(3);
737 FFI_INIT_TRAMPOLINE_WIN64 (&closure->tramp[0],
738 &ffi_closure_win64,
739 codeloc, mask);
740 /* make sure we can execute here */
741 }
742#else
743 if (cif->abi == FFI_SYSV)
744 {
745 FFI_INIT_TRAMPOLINE (&closure->tramp[0],
746 &ffi_closure_SYSV,
747 (void*)codeloc);
748 }
749 else if (cif->abi == FFI_REGISTER)
750 {
751 FFI_INIT_TRAMPOLINE_WIN32 (&closure->tramp[0],
752 &ffi_closure_REGISTER,
753 (void*)codeloc);
754 }
755 else if (cif->abi == FFI_FASTCALL)
756 {
757 FFI_INIT_TRAMPOLINE_WIN32 (&closure->tramp[0],
758 &ffi_closure_FASTCALL,
759 (void*)codeloc);
760 }
761 else if (cif->abi == FFI_THISCALL)
762 {
763 FFI_INIT_TRAMPOLINE_WIN32 (&closure->tramp[0],
764 &ffi_closure_THISCALL,
765 (void*)codeloc);
766 }
767 else if (cif->abi == FFI_STDCALL || cif->abi == FFI_PASCAL)
768 {
769 FFI_INIT_TRAMPOLINE_WIN32 (&closure->tramp[0],
770 &ffi_closure_STDCALL,
771 (void*)codeloc);
772 }
773#ifdef X86_WIN32
774 else if (cif->abi == FFI_MS_CDECL)
775 {
776 FFI_INIT_TRAMPOLINE (&closure->tramp[0],
777 &ffi_closure_SYSV,
778 (void*)codeloc);
779 }
780#endif /* X86_WIN32 */
781#endif /* !X86_WIN64 */
782 else
783 {
784 return FFI_BAD_ABI;
785 }
786
787 closure->cif = cif;
788 closure->user_data = user_data;
789 closure->fun = fun;
790
791 return FFI_OK;
792}
793
794/* ------- Native raw API support -------------------------------- */
795
796#if !FFI_NO_RAW_API
797
798ffi_status
799ffi_prep_raw_closure_loc (ffi_raw_closure* closure,
800 ffi_cif* cif,
801 void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
802 void *user_data,
803 void *codeloc)
804{
805 int i;
806
807 if (cif->abi != FFI_SYSV
808#ifdef X86_WIN32
809 && cif->abi != FFI_THISCALL
810#endif
811 )
812 return FFI_BAD_ABI;
813
814 /* we currently don't support certain kinds of arguments for raw
815 closures. This should be implemented by a separate assembly
816 language routine, since it would require argument processing,
817 something we don't do now for performance. */
818
819 for (i = cif->nargs-1; i >= 0; i--)
820 {
821 FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_STRUCT);
822 FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE);
823 }
824
825#ifdef X86_WIN32
826 if (cif->abi == FFI_SYSV)
827 {
828#endif
829 FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV,
830 codeloc);
831#ifdef X86_WIN32
832 }
833 else if (cif->abi == FFI_THISCALL)
834 {
835 FFI_INIT_TRAMPOLINE_RAW_THISCALL (&closure->tramp[0], &ffi_closure_raw_THISCALL, codeloc, cif->bytes);
836 }
837#endif
838 closure->cif = cif;
839 closure->user_data = user_data;
840 closure->fun = fun;
841
842 return FFI_OK;
843}
844
845static unsigned int
846ffi_prep_args_raw(char *stack, extended_cif *ecif)
847{
848 const ffi_cif *cif = ecif->cif;
849 unsigned int i, passed_regs = 0;
850
851#ifndef X86_WIN64
852 const unsigned int abi = cif->abi;
853 const unsigned int max_regs = (abi == FFI_THISCALL) ? 1
854 : (abi == FFI_FASTCALL) ? 2
855 : (abi == FFI_REGISTER) ? 3
856 : 0;
857
858 if (cif->flags == FFI_TYPE_STRUCT)
859 ++passed_regs;
860
861 for (i = 0; i < cif->nargs && passed_regs <= max_regs; i++)
862 {
863 size_t sz;
864 if (cif->arg_types[i]->type == FFI_TYPE_FLOAT
865 || cif->arg_types[i]->type == FFI_TYPE_STRUCT)
866 continue;
867
868 sz = cif->arg_types[i]->size;
869 if (sz == 0 || sz > FFI_SIZEOF_ARG)
870 continue;
871
872 ++passed_regs;
873 }
874#endif
875
876 memcpy (stack, ecif->avalue, cif->bytes);
877 return passed_regs;
878}
879
880/* we borrow this routine from libffi (it must be changed, though, to
881 * actually call the function passed in the first argument. as of
882 * libffi-1.20, this is not the case.)
883 */
884
885void
886ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *fake_avalue)
887{
888 extended_cif ecif;
889 void **avalue = (void **)fake_avalue;
890
891 ecif.cif = cif;
892 ecif.avalue = avalue;
893
894 /* If the return value is a struct and we don't have a return */
895 /* value address then we need to make one */
896
897 if (rvalue == NULL
898 && (cif->flags == FFI_TYPE_STRUCT
899 || cif->flags == FFI_TYPE_MS_STRUCT))
900 {
901 ecif.rvalue = alloca(cif->rtype->size);
902 }
903 else
904 ecif.rvalue = rvalue;
905
906
907 switch (cif->abi)
908 {
909#ifndef X86_WIN32
910 case FFI_SYSV:
911 ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
912 ecif.rvalue, fn);
913 break;
914#else
915 case FFI_SYSV:
916 case FFI_MS_CDECL:
917#endif
918#ifndef X86_WIN64
919 case FFI_STDCALL:
920 case FFI_THISCALL:
921 case FFI_FASTCALL:
922 case FFI_PASCAL:
923 case FFI_REGISTER:
924 ffi_call_win32(ffi_prep_args_raw, &ecif, cif->abi, cif->bytes, cif->flags,
925 ecif.rvalue, fn);
926 break;
927#endif
928 default:
929 FFI_ASSERT(0);
930 break;
931 }
932}
933
934#endif
935
936#endif /* !__x86_64__ || X86_WIN64 */
937
ffi_closure_SYSV_inner
void FFI_HIDDEN ffi_closure_SYSV_inner(ffi_closure *closure, struct call_context *context, void *stack)
Definition: ffi.c:964
ffi_prep_closure_loc
ffi_status ffi_prep_closure_loc(ffi_closure *closure, ffi_cif *cif, void(*fun)(ffi_cif *, void *, void **, void *), void *user_data, void *codeloc)
Definition: ffi.c:928
ffi_prep_cif_machdep
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
Definition: ffi.c:758
ffi_call
void ffi_call(ffi_cif *cif, void(*fn)(void), void *rvalue, void **avalue)
Definition: ffi.c:813
FFI_INIT_TRAMPOLINE
#define FFI_INIT_TRAMPOLINE(TRAMP, FUN, CTX, FLAGS)
Definition: ffi.c:915
ffi_call_SYSV
void ffi_call_SYSV(unsigned(*)(struct call_context *context, unsigned char *, extended_cif *), struct call_context *context, extended_cif *, size_t, void(*fn)(void))
ffi_arg
unsigned long ffi_arg
Definition: ffitarget.h:30
FFI_SYSV
@ FFI_SYSV
Definition: ffitarget.h:36
ffi_sarg
signed long ffi_sarg
Definition: ffitarget.h:31
FFI_TYPE_LONGDOUBLE
#define FFI_TYPE_LONGDOUBLE
Definition: ffi.c:40
ffi_prep_args
void ffi_prep_args(char *stack, extended_cif *ecif)
Definition: ffi.c:46
mask
enum @11::@13::@14 mask
ptr
struct RIMemo * ptr
Definition: debug.c:88
ffi_common.h
UINT16
unsigned short UINT16
Definition: ffi_common.h:97
SINT16
signed short SINT16
Definition: ffi_common.h:98
alloca
#define alloca
Definition: ffi_common.h:27
SINT32
signed int SINT32
Definition: ffi_common.h:100
ALIGN
#define ALIGN(v, a)
Definition: ffi_common.h:77
SINT8
signed char SINT8
Definition: ffi_common.h:96
FFI_ASSERT
#define FFI_ASSERT(x)
Definition: ffi_common.h:72
UINT8
unsigned char UINT8
Definition: ffi_common.h:95
UINT32
unsigned int UINT32
Definition: ffi_common.h:99
memcpy
#define memcpy(d, s, n)
Definition: ffi_common.h:55
FFI_HIDDEN
#define FFI_HIDDEN
Definition: fficonfig.h:27
__attribute__
void *PTR64 __attribute__((mode(DI)))
Definition: ffi.c:41
memmove
void * memmove(void *, const void *, size_t)
Definition: memmove.c:7
ffi_closure_SYSV
void ffi_closure_SYSV(void)
Definition: ffi.c:53
FFI_SIZEOF_ARG
#define FFI_SIZEOF_ARG
Definition: ffitarget.h:77
NULL
#define NULL
Definition: regenc.h:69
extended_cif
Definition: ffi_common.h:87
extended_cif::rvalue
void * rvalue
Definition: ffi_common.h:89
extended_cif::cif
ffi_cif * cif
Definition: ffi_common.h:88
extended_cif::avalue
void ** avalue
Definition: ffi_common.h:90
if
if((ID)(DISPID) nameid !=nameid)
Definition: win32ole.c:357
ffi_prep_raw_closure_loc
ffi_status ffi_prep_raw_closure_loc(ffi_raw_closure *closure, ffi_cif *cif, void(*fun)(ffi_cif *, void *, ffi_raw *, void *), void *user_data, void *codeloc)
Definition: ffi.c:799
ffi_raw_call
void ffi_raw_call(ffi_cif *cif, void(*fn)(void), void *rvalue, ffi_raw *fake_avalue)
Definition: ffi.c:886
FFI_INIT_TRAMPOLINE_WIN64
#define FFI_INIT_TRAMPOLINE_WIN64(TRAMP, FUN, CTX, MASK)
Definition: ffi.c:653
ffi_call_win32
void ffi_call_win32(unsigned int(*)(char *, extended_cif *), extended_cif *, unsigned, unsigned, unsigned, unsigned *, void(*fn)(void))
FFI_INIT_TRAMPOLINE_RAW_THISCALL
#define FFI_INIT_TRAMPOLINE_RAW_THISCALL(TRAMP, FUN, CTX, SIZE)
Definition: ffi.c:684
FFI_INIT_TRAMPOLINE_WIN32
#define FFI_INIT_TRAMPOLINE_WIN32(TRAMP, FUN, CTX)
Definition: ffi.c:711
FFI_TYPE_MS_STRUCT
#define FFI_TYPE_MS_STRUCT
Definition: ffitarget.h:129
FFI_FASTCALL
@ FFI_FASTCALL
Definition: ffitarget.h:109
FFI_STDCALL
@ FFI_STDCALL
Definition: ffitarget.h:110
FFI_THISCALL
@ FFI_THISCALL
Definition: ffitarget.h:108
FFI_PASCAL
@ FFI_PASCAL
Definition: ffitarget.h:111
FFI_REGISTER
@ FFI_REGISTER
Definition: ffitarget.h:112
FFI_UNIX64
@ FFI_UNIX64
Definition: ffitarget.h:107
FFI_TYPE_SMALL_STRUCT_1B
#define FFI_TYPE_SMALL_STRUCT_1B
Definition: ffitarget.h:126
FFI_TYPE_SMALL_STRUCT_4B
#define FFI_TYPE_SMALL_STRUCT_4B
Definition: ffitarget.h:128
FFI_TYPE_SMALL_STRUCT_2B
#define FFI_TYPE_SMALL_STRUCT_2B
Definition: ffitarget.h:127