Restore execute permissions
[platform/upstream/libffi.git] / .pc / msvc / src / x86 / ffi.c
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  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)
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
52   argp = stack;
53
54   if (ecif->cif->flags == FFI_TYPE_STRUCT
55 #ifdef X86_WIN64
56       && (ecif->cif->rtype->size != 1 && ecif->cif->rtype->size != 2
57           && ecif->cif->rtype->size != 4 && ecif->cif->rtype->size != 8)
58 #endif
59       )
60     {
61       *(void **) argp = ecif->rvalue;
62       argp += sizeof(void*);
63     }
64
65   p_argv = ecif->avalue;
66
67   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
68        i != 0;
69        i--, p_arg++)
70     {
71       size_t z;
72
73       /* Align if necessary */
74       if ((sizeof(void*) - 1) & (size_t) argp)
75         argp = (char *) ALIGN(argp, sizeof(void*));
76
77       z = (*p_arg)->size;
78 #ifdef X86_WIN64
79       if (z > sizeof(ffi_arg)
80           || ((*p_arg)->type == FFI_TYPE_STRUCT
81               && (z != 1 && z != 2 && z != 4 && z != 8))
82 #if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
83           || ((*p_arg)->type == FFI_TYPE_LONGDOUBLE)
84 #endif
85           )
86         {
87           z = sizeof(ffi_arg);
88           *(void **)argp = *p_argv;
89         }
90       else if ((*p_arg)->type == FFI_TYPE_FLOAT)
91         {
92           memcpy(argp, *p_argv, z);
93         }
94       else
95 #endif
96       if (z < sizeof(ffi_arg))
97         {
98           z = sizeof(ffi_arg);
99           switch ((*p_arg)->type)
100             {
101             case FFI_TYPE_SINT8:
102               *(ffi_sarg *) argp = (ffi_sarg)*(SINT8 *)(* p_argv);
103               break;
104
105             case FFI_TYPE_UINT8:
106               *(ffi_arg *) argp = (ffi_arg)*(UINT8 *)(* p_argv);
107               break;
108
109             case FFI_TYPE_SINT16:
110               *(ffi_sarg *) argp = (ffi_sarg)*(SINT16 *)(* p_argv);
111               break;
112
113             case FFI_TYPE_UINT16:
114               *(ffi_arg *) argp = (ffi_arg)*(UINT16 *)(* p_argv);
115               break;
116
117             case FFI_TYPE_SINT32:
118               *(ffi_sarg *) argp = (ffi_sarg)*(SINT32 *)(* p_argv);
119               break;
120
121             case FFI_TYPE_UINT32:
122               *(ffi_arg *) argp = (ffi_arg)*(UINT32 *)(* p_argv);
123               break;
124
125             case FFI_TYPE_STRUCT:
126               *(ffi_arg *) argp = *(ffi_arg *)(* p_argv);
127               break;
128
129             default:
130               FFI_ASSERT(0);
131             }
132         }
133       else
134         {
135           memcpy(argp, *p_argv, z);
136         }
137       p_argv++;
138 #ifdef X86_WIN64
139       argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
140 #else
141       argp += z;
142 #endif
143     }
144   
145   return;
146 }
147
148 /* Perform machine dependent cif processing */
149 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
150 {
151   /* Set the return type flag */
152   switch (cif->rtype->type)
153     {
154     case FFI_TYPE_VOID:
155 #ifdef X86
156     case FFI_TYPE_STRUCT:
157 #endif
158 #if defined(X86) || defined (X86_WIN32) || defined(X86_FREEBSD) || defined(X86_DARWIN) || defined(X86_WIN64)
159     case FFI_TYPE_UINT8:
160     case FFI_TYPE_UINT16:
161     case FFI_TYPE_SINT8:
162     case FFI_TYPE_SINT16:
163 #endif
164 #ifdef X86_WIN64
165     case FFI_TYPE_UINT32:
166     case FFI_TYPE_SINT32:
167 #endif
168
169     case FFI_TYPE_SINT64:
170     case FFI_TYPE_FLOAT:
171     case FFI_TYPE_DOUBLE:
172 #ifndef X86_WIN64
173 #if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
174     case FFI_TYPE_LONGDOUBLE:
175 #endif
176 #endif
177       cif->flags = (unsigned) cif->rtype->type;
178       break;
179
180     case FFI_TYPE_UINT64:
181 #ifdef X86_WIN64
182     case FFI_TYPE_POINTER:
183 #endif
184       cif->flags = FFI_TYPE_SINT64;
185       break;
186
187 #ifndef X86
188     case FFI_TYPE_STRUCT:
189       if (cif->rtype->size == 1)
190         {
191           cif->flags = FFI_TYPE_SMALL_STRUCT_1B; /* same as char size */
192         }
193       else if (cif->rtype->size == 2)
194         {
195           cif->flags = FFI_TYPE_SMALL_STRUCT_2B; /* same as short size */
196         }
197       else if (cif->rtype->size == 4)
198         {
199 #ifdef X86_WIN64
200           cif->flags = FFI_TYPE_SMALL_STRUCT_4B;
201 #else
202           cif->flags = FFI_TYPE_INT; /* same as int type */
203 #endif
204         }
205       else if (cif->rtype->size == 8)
206         {
207           cif->flags = FFI_TYPE_SINT64; /* same as int64 type */
208         }
209       else
210         {
211           cif->flags = FFI_TYPE_STRUCT;
212 #ifdef X86_WIN64
213           // allocate space for return value pointer
214           cif->bytes += ALIGN(sizeof(void*), FFI_SIZEOF_ARG);
215 #endif
216         }
217       break;
218 #endif
219
220     default:
221 #ifdef X86_WIN64
222       cif->flags = FFI_TYPE_SINT64;
223       break;
224     case FFI_TYPE_INT:
225       cif->flags = FFI_TYPE_SINT32;
226 #else
227       cif->flags = FFI_TYPE_INT;
228 #endif
229       break;
230     }
231
232 #ifdef X86_DARWIN
233   cif->bytes = (cif->bytes + 15) & ~0xF;
234 #endif
235
236 #ifdef X86_WIN64
237   {
238     unsigned int i;
239     ffi_type **ptr;
240
241     for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
242       {
243         if (((*ptr)->alignment - 1) & cif->bytes)
244           cif->bytes = ALIGN(cif->bytes, (*ptr)->alignment);
245         cif->bytes += ALIGN((*ptr)->size, FFI_SIZEOF_ARG);
246       }
247   }
248   // ensure space for storing four registers
249   cif->bytes += 4 * sizeof(ffi_arg);
250 #endif
251
252   return FFI_OK;
253 }
254
255 extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
256                           unsigned, unsigned, unsigned *, void (*fn)(void));
257
258 #ifdef X86_WIN32
259 extern void ffi_call_STDCALL(void (*)(char *, extended_cif *), extended_cif *,
260                           unsigned, unsigned, unsigned *, void (*fn)(void));
261
262 #endif /* X86_WIN32 */
263 #ifdef X86_WIN64
264 extern int
265 ffi_call_win64(void (*)(char *, extended_cif *), extended_cif *,
266                unsigned, unsigned, unsigned *, void (*fn)(void));
267 #endif
268
269 void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
270 {
271   extended_cif ecif;
272
273   ecif.cif = cif;
274   ecif.avalue = avalue;
275   
276   /* If the return value is a struct and we don't have a return */
277   /* value address then we need to make one                     */
278
279 #ifdef X86_WIN64
280   if (rvalue == NULL
281       && cif->flags == FFI_TYPE_STRUCT
282       && cif->rtype->size != 1 && cif->rtype->size != 2
283       && cif->rtype->size != 4 && cif->rtype->size != 8)
284     {
285       ecif.rvalue = alloca((cif->rtype->size + 0xF) & ~0xF);
286     }
287 #else
288   if (rvalue == NULL
289       && cif->flags == FFI_TYPE_STRUCT)
290     {
291       ecif.rvalue = alloca(cif->rtype->size);
292     }
293 #endif
294   else
295     ecif.rvalue = rvalue;
296     
297   
298   switch (cif->abi) 
299     {
300 #ifdef X86_WIN64
301     case FFI_WIN64:
302       {
303         // Make copies of all struct arguments
304         // NOTE: not sure if responsibility should be here or in caller
305         unsigned int i;
306         for (i=0; i < cif->nargs;i++) {
307           size_t size = cif->arg_types[i]->size;
308           if ((cif->arg_types[i]->type == FFI_TYPE_STRUCT
309                && (size != 1 && size != 2 && size != 4 && size != 8))
310 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
311               || cif->arg_types[i]->type == FFI_TYPE_LONGDOUBLE
312 #endif
313               )
314             {
315               void *local = alloca(size);
316               memcpy(local, avalue[i], size);
317               avalue[i] = local;
318             }
319         }
320         ffi_call_win64(ffi_prep_args, &ecif, cif->bytes,
321                        cif->flags, ecif.rvalue, fn);
322       }
323       break;
324 #else
325     case FFI_SYSV:
326       ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
327                     fn);
328       break;
329 #ifdef X86_WIN32
330     case FFI_STDCALL:
331       ffi_call_STDCALL(ffi_prep_args, &ecif, cif->bytes, cif->flags,
332                        ecif.rvalue, fn);
333       break;
334 #endif /* X86_WIN32 */
335 #endif /* X86_WIN64 */
336     default:
337       FFI_ASSERT(0);
338       break;
339     }
340 }
341
342
343 /** private members **/
344
345 static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
346                                          void** args, ffi_cif* cif);
347 void FFI_HIDDEN ffi_closure_SYSV (ffi_closure *)
348      __attribute__ ((regparm(1)));
349 unsigned int FFI_HIDDEN ffi_closure_SYSV_inner (ffi_closure *, void **, void *)
350      __attribute__ ((regparm(1)));
351 void FFI_HIDDEN ffi_closure_raw_SYSV (ffi_raw_closure *)
352      __attribute__ ((regparm(1)));
353 #ifdef X86_WIN32
354 void FFI_HIDDEN ffi_closure_STDCALL (ffi_closure *)
355      __attribute__ ((regparm(1)));
356 #endif
357 #ifdef X86_WIN64
358 void FFI_HIDDEN ffi_closure_win64 (ffi_closure *);
359 #endif
360
361 /* This function is jumped to by the trampoline */
362
363 #ifdef X86_WIN64
364 void * FFI_HIDDEN
365 ffi_closure_win64_inner (ffi_closure *closure, void *args) {
366   ffi_cif       *cif;
367   void         **arg_area;
368   void          *result;
369   void          *resp = &result;
370
371   cif         = closure->cif;
372   arg_area    = (void**) alloca (cif->nargs * sizeof (void*));  
373
374   /* this call will initialize ARG_AREA, such that each
375    * element in that array points to the corresponding 
376    * value on the stack; and if the function returns
377    * a structure, it will change RESP to point to the
378    * structure return address.  */
379
380   ffi_prep_incoming_args_SYSV(args, &resp, arg_area, cif);
381   
382   (closure->fun) (cif, resp, arg_area, closure->user_data);
383
384   /* The result is returned in rax.  This does the right thing for
385      result types except for floats; we have to 'mov xmm0, rax' in the
386      caller to correct this.
387      TODO: structure sizes of 3 5 6 7 are returned by reference, too!!!
388   */
389   return cif->rtype->size > sizeof(void *) ? resp : *(void **)resp;
390 }
391
392 #else
393 unsigned int FFI_HIDDEN
394 ffi_closure_SYSV_inner (closure, respp, args)
395      ffi_closure *closure;
396      void **respp;
397      void *args;
398 {
399   /* our various things...  */
400   ffi_cif       *cif;
401   void         **arg_area;
402
403   cif         = closure->cif;
404   arg_area    = (void**) alloca (cif->nargs * sizeof (void*));  
405
406   /* this call will initialize ARG_AREA, such that each
407    * element in that array points to the corresponding 
408    * value on the stack; and if the function returns
409    * a structure, it will change RESP to point to the
410    * structure return address.  */
411
412   ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif);
413
414   (closure->fun) (cif, *respp, arg_area, closure->user_data);
415
416   return cif->flags;
417 }
418 #endif /* !X86_WIN64 */
419
420 static void
421 ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue,
422                             ffi_cif *cif)
423 {
424   register unsigned int i;
425   register void **p_argv;
426   register char *argp;
427   register ffi_type **p_arg;
428
429   argp = stack;
430
431 #ifdef X86_WIN64
432   if (cif->rtype->size > sizeof(ffi_arg)
433       || (cif->flags == FFI_TYPE_STRUCT
434           && (cif->rtype->size != 1 && cif->rtype->size != 2
435               && cif->rtype->size != 4 && cif->rtype->size != 8))) {
436     *rvalue = *(void **) argp;
437     argp += sizeof(void *);
438   }
439 #else
440   if ( cif->flags == FFI_TYPE_STRUCT ) {
441     *rvalue = *(void **) argp;
442     argp += sizeof(void *);
443   }
444 #endif
445
446   p_argv = avalue;
447
448   for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
449     {
450       size_t z;
451
452       /* Align if necessary */
453       if ((sizeof(void*) - 1) & (size_t) argp) {
454         argp = (char *) ALIGN(argp, sizeof(void*));
455       }
456
457 #ifdef X86_WIN64
458       if ((*p_arg)->size > sizeof(ffi_arg)
459           || ((*p_arg)->type == FFI_TYPE_STRUCT
460               && ((*p_arg)->size != 1 && (*p_arg)->size != 2
461                   && (*p_arg)->size != 4 && (*p_arg)->size != 8)))
462         {
463           z = sizeof(void *);
464           *p_argv = *(void **)argp;
465         }
466       else
467 #endif
468         {
469           z = (*p_arg)->size;
470           
471           /* because we're little endian, this is what it turns into.   */
472           
473           *p_argv = (void*) argp;
474         }
475           
476       p_argv++;
477 #ifdef X86_WIN64
478       argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
479 #else
480       argp += z;
481 #endif
482     }
483   
484   return;
485 }
486
487 #define FFI_INIT_TRAMPOLINE_WIN64(TRAMP,FUN,CTX,MASK) \
488 { unsigned char *__tramp = (unsigned char*)(TRAMP); \
489    void*  __fun = (void*)(FUN); \
490    void*  __ctx = (void*)(CTX); \
491    *(unsigned char*) &__tramp[0] = 0x41; \
492    *(unsigned char*) &__tramp[1] = 0xbb; \
493    *(unsigned int*) &__tramp[2] = MASK; /* mov $mask, %r11 */ \
494    *(unsigned char*) &__tramp[6] = 0x48; \
495    *(unsigned char*) &__tramp[7] = 0xb8; \
496    *(void**) &__tramp[8] = __ctx; /* mov __ctx, %rax */ \
497    *(unsigned char *)  &__tramp[16] = 0x49; \
498    *(unsigned char *)  &__tramp[17] = 0xba; \
499    *(void**) &__tramp[18] = __fun; /* mov __fun, %r10 */ \
500    *(unsigned char *)  &__tramp[26] = 0x41; \
501    *(unsigned char *)  &__tramp[27] = 0xff; \
502    *(unsigned char *)  &__tramp[28] = 0xe2; /* jmp %r10 */ \
503  }
504
505 /* How to make a trampoline.  Derived from gcc/config/i386/i386.c. */
506
507 #define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \
508 ({ unsigned char *__tramp = (unsigned char*)(TRAMP); \
509    unsigned int  __fun = (unsigned int)(FUN); \
510    unsigned int  __ctx = (unsigned int)(CTX); \
511    unsigned int  __dis = __fun - (__ctx + 10);  \
512    *(unsigned char*) &__tramp[0] = 0xb8; \
513    *(unsigned int*)  &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
514    *(unsigned char *)  &__tramp[5] = 0xe9; \
515    *(unsigned int*)  &__tramp[6] = __dis; /* jmp __fun  */ \
516  })
517
518 #define FFI_INIT_TRAMPOLINE_STDCALL(TRAMP,FUN,CTX,SIZE)  \
519 ({ unsigned char *__tramp = (unsigned char*)(TRAMP); \
520    unsigned int  __fun = (unsigned int)(FUN); \
521    unsigned int  __ctx = (unsigned int)(CTX); \
522    unsigned int  __dis = __fun - (__ctx + 10); \
523    unsigned short __size = (unsigned short)(SIZE); \
524    *(unsigned char*) &__tramp[0] = 0xb8; \
525    *(unsigned int*)  &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
526    *(unsigned char *)  &__tramp[5] = 0xe8; \
527    *(unsigned int*)  &__tramp[6] = __dis; /* call __fun  */ \
528    *(unsigned char *)  &__tramp[10] = 0xc2; \
529    *(unsigned short*)  &__tramp[11] = __size; /* ret __size  */ \
530  })
531
532 /* the cif must already be prep'ed */
533
534 ffi_status
535 ffi_prep_closure_loc (ffi_closure* closure,
536                       ffi_cif* cif,
537                       void (*fun)(ffi_cif*,void*,void**,void*),
538                       void *user_data,
539                       void *codeloc)
540 {
541 #ifdef X86_WIN64
542 #define ISFLOAT(IDX) (cif->arg_types[IDX]->type == FFI_TYPE_FLOAT || cif->arg_types[IDX]->type == FFI_TYPE_DOUBLE)
543 #define FLAG(IDX) (cif->nargs>(IDX)&&ISFLOAT(IDX)?(1<<(IDX)):0)
544   if (cif->abi == FFI_WIN64) 
545     {
546       int mask = FLAG(0)|FLAG(1)|FLAG(2)|FLAG(3);
547       FFI_INIT_TRAMPOLINE_WIN64 (&closure->tramp[0],
548                                  &ffi_closure_win64,
549                                  codeloc, mask);
550       /* make sure we can execute here */
551     }
552 #else
553   if (cif->abi == FFI_SYSV)
554     {
555       FFI_INIT_TRAMPOLINE (&closure->tramp[0],
556                            &ffi_closure_SYSV,
557                            (void*)codeloc);
558     }
559 #ifdef X86_WIN32
560   else if (cif->abi == FFI_STDCALL)
561     {
562       FFI_INIT_TRAMPOLINE_STDCALL (&closure->tramp[0],
563                                    &ffi_closure_STDCALL,
564                                    (void*)codeloc, cif->bytes);
565     }
566 #endif /* X86_WIN32 */
567 #endif /* !X86_WIN64 */
568   else
569     {
570       return FFI_BAD_ABI;
571     }
572     
573   closure->cif  = cif;
574   closure->user_data = user_data;
575   closure->fun  = fun;
576
577   return FFI_OK;
578 }
579
580 /* ------- Native raw API support -------------------------------- */
581
582 #if !FFI_NO_RAW_API
583
584 ffi_status
585 ffi_prep_raw_closure_loc (ffi_raw_closure* closure,
586                           ffi_cif* cif,
587                           void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
588                           void *user_data,
589                           void *codeloc)
590 {
591   int i;
592
593   if (cif->abi != FFI_SYSV) {
594     return FFI_BAD_ABI;
595   }
596
597   // we currently don't support certain kinds of arguments for raw
598   // closures.  This should be implemented by a separate assembly language
599   // routine, since it would require argument processing, something we
600   // don't do now for performance.
601
602   for (i = cif->nargs-1; i >= 0; i--)
603     {
604       FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_STRUCT);
605       FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE);
606     }
607   
608
609   FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV,
610                        codeloc);
611     
612   closure->cif  = cif;
613   closure->user_data = user_data;
614   closure->fun  = fun;
615
616   return FFI_OK;
617 }
618
619 static void 
620 ffi_prep_args_raw(char *stack, extended_cif *ecif)
621 {
622   memcpy (stack, ecif->avalue, ecif->cif->bytes);
623 }
624
625 /* we borrow this routine from libffi (it must be changed, though, to
626  * actually call the function passed in the first argument.  as of
627  * libffi-1.20, this is not the case.)
628  */
629
630 extern void
631 ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *, unsigned, 
632               unsigned, unsigned *, void (*fn)(void));
633
634 #ifdef X86_WIN32
635 extern void
636 ffi_call_STDCALL(void (*)(char *, extended_cif *), extended_cif *, unsigned,
637                  unsigned, unsigned *, void (*fn)(void));
638 #endif /* X86_WIN32 */
639
640 void
641 ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *fake_avalue)
642 {
643   extended_cif ecif;
644   void **avalue = (void **)fake_avalue;
645
646   ecif.cif = cif;
647   ecif.avalue = avalue;
648   
649   /* If the return value is a struct and we don't have a return */
650   /* value address then we need to make one                     */
651
652   if ((rvalue == NULL) && 
653       (cif->rtype->type == FFI_TYPE_STRUCT))
654     {
655       ecif.rvalue = alloca(cif->rtype->size);
656     }
657   else
658     ecif.rvalue = rvalue;
659     
660   
661   switch (cif->abi) 
662     {
663     case FFI_SYSV:
664       ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
665                     ecif.rvalue, fn);
666       break;
667 #ifdef X86_WIN32
668     case FFI_STDCALL:
669       ffi_call_STDCALL(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
670                        ecif.rvalue, fn);
671       break;
672 #endif /* X86_WIN32 */
673     default:
674       FFI_ASSERT(0);
675       break;
676     }
677 }
678
679 #endif
680
681 #endif /* !__x86_64__  || X86_WIN64 */
682