Back to index

plt-scheme  4.2.1
ffi.c
Go to the documentation of this file.
00001 /* -----------------------------------------------------------------------
00002    ffi.c - Copyright (c) 1998 Geoffrey Keating
00003    Copyright (C) 2007, 2008 Free Software Foundation, Inc
00004 
00005    PowerPC Foreign Function Interface
00006 
00007    Permission is hereby granted, free of charge, to any person obtaining
00008    a copy of this software and associated documentation files (the
00009    ``Software''), to deal in the Software without restriction, including
00010    without limitation the rights to use, copy, modify, merge, publish,
00011    distribute, sublicense, and/or sell copies of the Software, and to
00012    permit persons to whom the Software is furnished to do so, subject to
00013    the following conditions:
00014 
00015    The above copyright notice and this permission notice shall be included
00016    in all copies or substantial portions of the Software.
00017 
00018    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
00019    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00020    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00021    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
00022    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00023    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00024    OTHER DEALINGS IN THE SOFTWARE.
00025    ----------------------------------------------------------------------- */
00026 
00027 #include <ffi.h>
00028 #include <ffi_common.h>
00029 
00030 #include <stdlib.h>
00031 #include <stdio.h>
00032 
00033 
00034 extern void ffi_closure_SYSV (void);
00035 extern void FFI_HIDDEN ffi_closure_LINUX64 (void);
00036 
00037 enum {
00038   /* The assembly depends on these exact flags.  */
00039   FLAG_RETURNS_SMST  = 1 << (31-31), /* Used for FFI_SYSV small structs.  */
00040   FLAG_RETURNS_NOTHING  = 1 << (31-30), /* These go in cr7 */
00041   FLAG_RETURNS_FP       = 1 << (31-29),
00042   FLAG_RETURNS_64BITS   = 1 << (31-28),
00043 
00044   FLAG_RETURNS_128BITS  = 1 << (31-27), /* cr6  */
00045 
00046   FLAG_SYSV_SMST_R4     = 1 << (31-16), /* cr4, use r4 for FFI_SYSV 8 byte
00047                                       structs.  */
00048   FLAG_SYSV_SMST_R3     = 1 << (31-15), /* cr3, use r3 for FFI_SYSV 4 byte
00049                                       structs.  */
00050   FLAG_ARG_NEEDS_COPY   = 1 << (31- 7),
00051   FLAG_FP_ARGUMENTS     = 1 << (31- 6), /* cr1.eq; specified by ABI */
00052   FLAG_4_GPR_ARGUMENTS  = 1 << (31- 5),
00053   FLAG_RETVAL_REFERENCE = 1 << (31- 4)
00054 };
00055 
00056 /* About the SYSV ABI.  */
00057 unsigned int NUM_GPR_ARG_REGISTERS = 8;
00058 #ifndef __NO_FPRS__
00059 unsigned int NUM_FPR_ARG_REGISTERS = 8;
00060 #else
00061 unsigned int NUM_FPR_ARG_REGISTERS = 0;
00062 #endif
00063 
00064 enum { ASM_NEEDS_REGISTERS = 4 };
00065 
00066 /* ffi_prep_args_SYSV is called by the assembly routine once stack space
00067    has been allocated for the function's arguments.
00068 
00069    The stack layout we want looks like this:
00070 
00071    |   Return address from ffi_call_SYSV 4bytes  |      higher addresses
00072    |--------------------------------------------|
00073    |   Previous backchain pointer  4      |       stack pointer here
00074    |--------------------------------------------|<+ <<< on entry to
00075    |   Saved r28-r31               4*4    | |    ffi_call_SYSV
00076    |--------------------------------------------| |
00077    |   GPR registers r3-r10        8*4    | |    ffi_call_SYSV
00078    |--------------------------------------------| |
00079    |   FPR registers f1-f8 (optional)     8*8    | |
00080    |--------------------------------------------| |     stack  |
00081    |   Space for copied structures        | |    grows  |
00082    |--------------------------------------------| |     down    V
00083    |   Parameters that didn't fit in registers  | |
00084    |--------------------------------------------| |     lower addresses
00085    |   Space for callee's LR              4      | |
00086    |--------------------------------------------| |     stack pointer here
00087    |   Current backchain pointer   4      |-/    during
00088    |--------------------------------------------|   <<< ffi_call_SYSV
00089 
00090 */
00091 
00092 void
00093 ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
00094 {
00095   const unsigned bytes = ecif->cif->bytes;
00096   const unsigned flags = ecif->cif->flags;
00097 
00098   typedef union {
00099     char *c;
00100     unsigned *u;
00101     long long *ll;
00102     float *f;
00103     double *d;
00104   } valp;
00105 
00106   /* 'stacktop' points at the previous backchain pointer.  */
00107   valp stacktop;
00108 
00109   /* 'gpr_base' points at the space for gpr3, and grows upwards as
00110      we use GPR registers.  */
00111   valp gpr_base;
00112   int intarg_count;
00113 
00114   /* 'fpr_base' points at the space for fpr1, and grows upwards as
00115      we use FPR registers.  */
00116   valp fpr_base;
00117   int fparg_count;
00118 
00119   /* 'copy_space' grows down as we put structures in it.  It should
00120      stay 16-byte aligned.  */
00121   valp copy_space;
00122 
00123   /* 'next_arg' grows up as we put parameters in it.  */
00124   valp next_arg;
00125 
00126   int i, ii MAYBE_UNUSED;
00127   ffi_type **ptr;
00128   double double_tmp;
00129   union {
00130     void **v;
00131     char **c;
00132     signed char **sc;
00133     unsigned char **uc;
00134     signed short **ss;
00135     unsigned short **us;
00136     unsigned int **ui;
00137     long long **ll;
00138     float **f;
00139     double **d;
00140   } p_argv;
00141   size_t struct_copy_size;
00142   unsigned gprvalue;
00143 
00144   if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT)
00145     NUM_FPR_ARG_REGISTERS = 0;
00146 
00147   stacktop.c = (char *) stack + bytes;
00148   gpr_base.u = stacktop.u - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS;
00149   intarg_count = 0;
00150   fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS;
00151   fparg_count = 0;
00152   copy_space.c = ((flags & FLAG_FP_ARGUMENTS) ? fpr_base.c : gpr_base.c);
00153   next_arg.u = stack + 2;
00154 
00155   /* Check that everything starts aligned properly.  */
00156   FFI_ASSERT (((unsigned) (char *) stack & 0xF) == 0);
00157   FFI_ASSERT (((unsigned) copy_space.c & 0xF) == 0);
00158   FFI_ASSERT (((unsigned) stacktop.c & 0xF) == 0);
00159   FFI_ASSERT ((bytes & 0xF) == 0);
00160   FFI_ASSERT (copy_space.c >= next_arg.c);
00161 
00162   /* Deal with return values that are actually pass-by-reference.  */
00163   if (flags & FLAG_RETVAL_REFERENCE)
00164     {
00165       *gpr_base.u++ = (unsigned long) (char *) ecif->rvalue;
00166       intarg_count++;
00167     }
00168 
00169   /* Now for the arguments.  */
00170   p_argv.v = ecif->avalue;
00171   for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs;
00172        i > 0;
00173        i--, ptr++, p_argv.v++)
00174     {
00175       switch ((*ptr)->type)
00176        {
00177        case FFI_TYPE_FLOAT:
00178          /* With FFI_LINUX_SOFT_FLOAT floats are handled like UINT32.  */
00179          if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT)
00180            goto soft_float_prep;
00181          double_tmp = **p_argv.f;
00182          if (fparg_count >= NUM_FPR_ARG_REGISTERS)
00183            {
00184              *next_arg.f = (float) double_tmp;
00185              next_arg.u += 1;
00186            }
00187          else
00188            *fpr_base.d++ = double_tmp;
00189          fparg_count++;
00190          FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
00191          break;
00192 
00193        case FFI_TYPE_DOUBLE:
00194          /* With FFI_LINUX_SOFT_FLOAT doubles are handled like UINT64.  */
00195          if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT)
00196            goto soft_double_prep;
00197          double_tmp = **p_argv.d;
00198 
00199          if (fparg_count >= NUM_FPR_ARG_REGISTERS)
00200            {
00201              if (intarg_count >= NUM_GPR_ARG_REGISTERS
00202                 && intarg_count % 2 != 0)
00203               {
00204                 intarg_count++;
00205                 next_arg.u++;
00206               }
00207              *next_arg.d = double_tmp;
00208              next_arg.u += 2;
00209            }
00210          else
00211            *fpr_base.d++ = double_tmp;
00212          fparg_count++;
00213          FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
00214          break;
00215 
00216 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
00217        case FFI_TYPE_LONGDOUBLE:
00218          if ((ecif->cif->abi != FFI_LINUX)
00219               && (ecif->cif->abi != FFI_LINUX_SOFT_FLOAT))
00220            goto do_struct;
00221          /* The soft float ABI for long doubles works like this,
00222             a long double is passed in four consecutive gprs if available.
00223             A maximum of 2 long doubles can be passed in gprs.
00224             If we do not have 4 gprs left, the long double is passed on the
00225             stack, 4-byte aligned.  */
00226          if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT)
00227            {
00228              unsigned int int_tmp = (*p_argv.ui)[0];
00229              if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3)
00230               {
00231                 if (intarg_count < NUM_GPR_ARG_REGISTERS)
00232                   intarg_count += NUM_GPR_ARG_REGISTERS - intarg_count;
00233                 *next_arg.u = int_tmp;
00234                 next_arg.u++;
00235                 for (ii = 1; ii < 4; ii++)
00236                   {
00237                     int_tmp = (*p_argv.ui)[ii];
00238                     *next_arg.u = int_tmp;
00239                     next_arg.u++;
00240                   }
00241               }
00242              else
00243               {
00244                 *gpr_base.u++ = int_tmp;
00245                 for (ii = 1; ii < 4; ii++)
00246                   {
00247                     int_tmp = (*p_argv.ui)[ii];
00248                     *gpr_base.u++ = int_tmp;
00249                   }
00250               }
00251              intarg_count +=4;
00252            }
00253          else
00254            {
00255              double_tmp = (*p_argv.d)[0];
00256 
00257              if (fparg_count >= NUM_FPR_ARG_REGISTERS - 1)
00258               {
00259                 if (intarg_count >= NUM_GPR_ARG_REGISTERS
00260                     && intarg_count % 2 != 0)
00261                   {
00262                     intarg_count++;
00263                     next_arg.u++;
00264                   }
00265                 *next_arg.d = double_tmp;
00266                 next_arg.u += 2;
00267                 double_tmp = (*p_argv.d)[1];
00268                 *next_arg.d = double_tmp;
00269                 next_arg.u += 2;
00270               }
00271              else
00272               {
00273                 *fpr_base.d++ = double_tmp;
00274                 double_tmp = (*p_argv.d)[1];
00275                 *fpr_base.d++ = double_tmp;
00276               }
00277 
00278              fparg_count += 2;
00279              FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
00280            }
00281          break;
00282 #endif
00283 
00284        case FFI_TYPE_UINT64:
00285        case FFI_TYPE_SINT64:
00286        soft_double_prep:
00287          if (intarg_count == NUM_GPR_ARG_REGISTERS-1)
00288            intarg_count++;
00289          if (intarg_count >= NUM_GPR_ARG_REGISTERS)
00290            {
00291              if (intarg_count % 2 != 0)
00292               {
00293                 intarg_count++;
00294                 next_arg.u++;
00295               }
00296              *next_arg.ll = **p_argv.ll;
00297              next_arg.u += 2;
00298            }
00299          else
00300            {
00301              /* whoops: abi states only certain register pairs
00302               * can be used for passing long long int
00303               * specifically (r3,r4), (r5,r6), (r7,r8),
00304               * (r9,r10) and if next arg is long long but
00305               * not correct starting register of pair then skip
00306               * until the proper starting register
00307               */
00308              if (intarg_count % 2 != 0)
00309               {
00310                 intarg_count ++;
00311                 gpr_base.u++;
00312               }
00313              *gpr_base.ll++ = **p_argv.ll;
00314            }
00315          intarg_count += 2;
00316          break;
00317 
00318        case FFI_TYPE_STRUCT:
00319 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
00320        do_struct:
00321 #endif
00322          struct_copy_size = ((*ptr)->size + 15) & ~0xF;
00323          copy_space.c -= struct_copy_size;
00324          memcpy (copy_space.c, *p_argv.c, (*ptr)->size);
00325 
00326          gprvalue = (unsigned long) copy_space.c;
00327 
00328          FFI_ASSERT (copy_space.c > next_arg.c);
00329          FFI_ASSERT (flags & FLAG_ARG_NEEDS_COPY);
00330          goto putgpr;
00331 
00332        case FFI_TYPE_UINT8:
00333          gprvalue = **p_argv.uc;
00334          goto putgpr;
00335        case FFI_TYPE_SINT8:
00336          gprvalue = **p_argv.sc;
00337          goto putgpr;
00338        case FFI_TYPE_UINT16:
00339          gprvalue = **p_argv.us;
00340          goto putgpr;
00341        case FFI_TYPE_SINT16:
00342          gprvalue = **p_argv.ss;
00343          goto putgpr;
00344 
00345        case FFI_TYPE_INT:
00346        case FFI_TYPE_UINT32:
00347        case FFI_TYPE_SINT32:
00348        case FFI_TYPE_POINTER:
00349        soft_float_prep:
00350 
00351          gprvalue = **p_argv.ui;
00352 
00353        putgpr:
00354          if (intarg_count >= NUM_GPR_ARG_REGISTERS)
00355            *next_arg.u++ = gprvalue;
00356          else
00357            *gpr_base.u++ = gprvalue;
00358          intarg_count++;
00359          break;
00360        }
00361     }
00362 
00363   /* Check that we didn't overrun the stack...  */
00364   FFI_ASSERT (copy_space.c >= next_arg.c);
00365   FFI_ASSERT (gpr_base.u <= stacktop.u - ASM_NEEDS_REGISTERS);
00366   FFI_ASSERT (fpr_base.u
00367              <= stacktop.u - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS);
00368   FFI_ASSERT (flags & FLAG_4_GPR_ARGUMENTS || intarg_count <= 4);
00369 }
00370 
00371 /* About the LINUX64 ABI.  */
00372 enum {
00373   NUM_GPR_ARG_REGISTERS64 = 8,
00374   NUM_FPR_ARG_REGISTERS64 = 13
00375 };
00376 enum { ASM_NEEDS_REGISTERS64 = 4 };
00377 
00378 /* ffi_prep_args64 is called by the assembly routine once stack space
00379    has been allocated for the function's arguments.
00380 
00381    The stack layout we want looks like this:
00382 
00383    |   Ret addr from ffi_call_LINUX64     8bytes |      higher addresses
00384    |--------------------------------------------|
00385    |   CR save area                8bytes |
00386    |--------------------------------------------|
00387    |   Previous backchain pointer  8      |      stack pointer here
00388    |--------------------------------------------|<+ <<< on entry to
00389    |   Saved r28-r31               4*8    | |    ffi_call_LINUX64
00390    |--------------------------------------------| |
00391    |   GPR registers r3-r10        8*8    | |
00392    |--------------------------------------------| |
00393    |   FPR registers f1-f13 (optional)    13*8   | |
00394    |--------------------------------------------| |
00395    |   Parameter save area                 | |
00396    |--------------------------------------------| |
00397    |   TOC save area               8      | |
00398    |--------------------------------------------| |     stack  |
00399    |   Linker doubleword           8      | |    grows  |
00400    |--------------------------------------------| |     down   V
00401    |   Compiler doubleword         8      | |
00402    |--------------------------------------------| |     lower addresses
00403    |   Space for callee's LR              8      | |
00404    |--------------------------------------------| |
00405    |   CR save area                8      | |
00406    |--------------------------------------------| |     stack pointer here
00407    |   Current backchain pointer   8      |-/    during
00408    |--------------------------------------------|   <<< ffi_call_LINUX64
00409 
00410 */
00411 
00412 void FFI_HIDDEN
00413 ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
00414 {
00415   const unsigned long bytes = ecif->cif->bytes;
00416   const unsigned long flags = ecif->cif->flags;
00417 
00418   typedef union {
00419     char *c;
00420     unsigned long *ul;
00421     float *f;
00422     double *d;
00423   } valp;
00424 
00425   /* 'stacktop' points at the previous backchain pointer.  */
00426   valp stacktop;
00427 
00428   /* 'next_arg' points at the space for gpr3, and grows upwards as
00429      we use GPR registers, then continues at rest.  */
00430   valp gpr_base;
00431   valp gpr_end;
00432   valp rest;
00433   valp next_arg;
00434 
00435   /* 'fpr_base' points at the space for fpr3, and grows upwards as
00436      we use FPR registers.  */
00437   valp fpr_base;
00438   int fparg_count;
00439 
00440   int i, words;
00441   ffi_type **ptr;
00442   double double_tmp;
00443   union {
00444     void **v;
00445     char **c;
00446     signed char **sc;
00447     unsigned char **uc;
00448     signed short **ss;
00449     unsigned short **us;
00450     signed int **si;
00451     unsigned int **ui;
00452     unsigned long **ul;
00453     float **f;
00454     double **d;
00455   } p_argv;
00456   unsigned long gprvalue;
00457 
00458   stacktop.c = (char *) stack + bytes;
00459   gpr_base.ul = stacktop.ul - ASM_NEEDS_REGISTERS64 - NUM_GPR_ARG_REGISTERS64;
00460   gpr_end.ul = gpr_base.ul + NUM_GPR_ARG_REGISTERS64;
00461   rest.ul = stack + 6 + NUM_GPR_ARG_REGISTERS64;
00462   fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS64;
00463   fparg_count = 0;
00464   next_arg.ul = gpr_base.ul;
00465 
00466   /* Check that everything starts aligned properly.  */
00467   FFI_ASSERT (((unsigned long) (char *) stack & 0xF) == 0);
00468   FFI_ASSERT (((unsigned long) stacktop.c & 0xF) == 0);
00469   FFI_ASSERT ((bytes & 0xF) == 0);
00470 
00471   /* Deal with return values that are actually pass-by-reference.  */
00472   if (flags & FLAG_RETVAL_REFERENCE)
00473     *next_arg.ul++ = (unsigned long) (char *) ecif->rvalue;
00474 
00475   /* Now for the arguments.  */
00476   p_argv.v = ecif->avalue;
00477   for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs;
00478        i > 0;
00479        i--, ptr++, p_argv.v++)
00480     {
00481       switch ((*ptr)->type)
00482        {
00483        case FFI_TYPE_FLOAT:
00484          double_tmp = **p_argv.f;
00485          *next_arg.f = (float) double_tmp;
00486          if (++next_arg.ul == gpr_end.ul)
00487            next_arg.ul = rest.ul;
00488          if (fparg_count < NUM_FPR_ARG_REGISTERS64)
00489            *fpr_base.d++ = double_tmp;
00490          fparg_count++;
00491          FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
00492          break;
00493 
00494        case FFI_TYPE_DOUBLE:
00495          double_tmp = **p_argv.d;
00496          *next_arg.d = double_tmp;
00497          if (++next_arg.ul == gpr_end.ul)
00498            next_arg.ul = rest.ul;
00499          if (fparg_count < NUM_FPR_ARG_REGISTERS64)
00500            *fpr_base.d++ = double_tmp;
00501          fparg_count++;
00502          FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
00503          break;
00504 
00505 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
00506        case FFI_TYPE_LONGDOUBLE:
00507          double_tmp = (*p_argv.d)[0];
00508          *next_arg.d = double_tmp;
00509          if (++next_arg.ul == gpr_end.ul)
00510            next_arg.ul = rest.ul;
00511          if (fparg_count < NUM_FPR_ARG_REGISTERS64)
00512            *fpr_base.d++ = double_tmp;
00513          fparg_count++;
00514          double_tmp = (*p_argv.d)[1];
00515          *next_arg.d = double_tmp;
00516          if (++next_arg.ul == gpr_end.ul)
00517            next_arg.ul = rest.ul;
00518          if (fparg_count < NUM_FPR_ARG_REGISTERS64)
00519            *fpr_base.d++ = double_tmp;
00520          fparg_count++;
00521          FFI_ASSERT (__LDBL_MANT_DIG__ == 106);
00522          FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
00523          break;
00524 #endif
00525 
00526        case FFI_TYPE_STRUCT:
00527          words = ((*ptr)->size + 7) / 8;
00528          if (next_arg.ul >= gpr_base.ul && next_arg.ul + words > gpr_end.ul)
00529            {
00530              size_t first = gpr_end.c - next_arg.c;
00531              memcpy (next_arg.c, *p_argv.c, first);
00532              memcpy (rest.c, *p_argv.c + first, (*ptr)->size - first);
00533              next_arg.c = rest.c + words * 8 - first;
00534            }
00535          else
00536            {
00537              char *where = next_arg.c;
00538 
00539              /* Structures with size less than eight bytes are passed
00540                left-padded.  */
00541              if ((*ptr)->size < 8)
00542               where += 8 - (*ptr)->size;
00543 
00544              memcpy (where, *p_argv.c, (*ptr)->size);
00545              next_arg.ul += words;
00546              if (next_arg.ul == gpr_end.ul)
00547               next_arg.ul = rest.ul;
00548            }
00549          break;
00550 
00551        case FFI_TYPE_UINT8:
00552          gprvalue = **p_argv.uc;
00553          goto putgpr;
00554        case FFI_TYPE_SINT8:
00555          gprvalue = **p_argv.sc;
00556          goto putgpr;
00557        case FFI_TYPE_UINT16:
00558          gprvalue = **p_argv.us;
00559          goto putgpr;
00560        case FFI_TYPE_SINT16:
00561          gprvalue = **p_argv.ss;
00562          goto putgpr;
00563        case FFI_TYPE_UINT32:
00564          gprvalue = **p_argv.ui;
00565          goto putgpr;
00566        case FFI_TYPE_INT:
00567        case FFI_TYPE_SINT32:
00568          gprvalue = **p_argv.si;
00569          goto putgpr;
00570 
00571        case FFI_TYPE_UINT64:
00572        case FFI_TYPE_SINT64:
00573        case FFI_TYPE_POINTER:
00574          gprvalue = **p_argv.ul;
00575        putgpr:
00576          *next_arg.ul++ = gprvalue;
00577          if (next_arg.ul == gpr_end.ul)
00578            next_arg.ul = rest.ul;
00579          break;
00580        }
00581     }
00582 
00583   FFI_ASSERT (flags & FLAG_4_GPR_ARGUMENTS
00584              || (next_arg.ul >= gpr_base.ul
00585                 && next_arg.ul <= gpr_base.ul + 4));
00586 }
00587 
00588 
00589 
00590 /* Perform machine dependent cif processing */
00591 ffi_status
00592 ffi_prep_cif_machdep (ffi_cif *cif)
00593 {
00594   /* All this is for the SYSV and LINUX64 ABI.  */
00595   int i;
00596   ffi_type **ptr;
00597   unsigned bytes;
00598   int fparg_count = 0, intarg_count = 0;
00599   unsigned flags = 0;
00600   unsigned struct_copy_size = 0;
00601   unsigned type = cif->rtype->type;
00602   unsigned size = cif->rtype->size;
00603 
00604   if (cif->abi == FFI_LINUX_SOFT_FLOAT)
00605     NUM_FPR_ARG_REGISTERS = 0;
00606 
00607   if (cif->abi != FFI_LINUX64)
00608     {
00609       /* All the machine-independent calculation of cif->bytes will be wrong.
00610         Redo the calculation for SYSV.  */
00611 
00612       /* Space for the frame pointer, callee's LR, and the asm's temp regs.  */
00613       bytes = (2 + ASM_NEEDS_REGISTERS) * sizeof (int);
00614 
00615       /* Space for the GPR registers.  */
00616       bytes += NUM_GPR_ARG_REGISTERS * sizeof (int);
00617     }
00618   else
00619     {
00620       /* 64-bit ABI.  */
00621 
00622       /* Space for backchain, CR, LR, cc/ld doubleword, TOC and the asm's temp
00623         regs.  */
00624       bytes = (6 + ASM_NEEDS_REGISTERS64) * sizeof (long);
00625 
00626       /* Space for the mandatory parm save area and general registers.  */
00627       bytes += 2 * NUM_GPR_ARG_REGISTERS64 * sizeof (long);
00628     }
00629 
00630   /* Return value handling.  The rules for SYSV are as follows:
00631      - 32-bit (or less) integer values are returned in gpr3;
00632      - Structures of size <= 4 bytes also returned in gpr3;
00633      - 64-bit integer values and structures between 5 and 8 bytes are returned
00634      in gpr3 and gpr4;
00635      - Single/double FP values are returned in fpr1;
00636      - Larger structures are allocated space and a pointer is passed as
00637      the first argument.
00638      - long doubles (if not equivalent to double) are returned in
00639      fpr1,fpr2 for Linux and as for large structs for SysV.
00640      For LINUX64:
00641      - integer values in gpr3;
00642      - Structures/Unions by reference;
00643      - Single/double FP values in fpr1, long double in fpr1,fpr2.
00644      - soft-float float/doubles are treated as UINT32/UINT64 respectivley.
00645      - soft-float long doubles are returned in gpr3-gpr6.  */
00646   switch (type)
00647     {
00648 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
00649     case FFI_TYPE_LONGDOUBLE:
00650       if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64
00651        && cif->abi != FFI_LINUX_SOFT_FLOAT)
00652        goto byref;
00653       flags |= FLAG_RETURNS_128BITS;
00654       /* Fall through.  */
00655 #endif
00656     case FFI_TYPE_DOUBLE:
00657       flags |= FLAG_RETURNS_64BITS;
00658       /* Fall through.  */
00659     case FFI_TYPE_FLOAT:
00660       /* With FFI_LINUX_SOFT_FLOAT no fp registers are used.  */
00661       if (cif->abi != FFI_LINUX_SOFT_FLOAT)
00662        flags |= FLAG_RETURNS_FP;
00663       break;
00664 
00665     case FFI_TYPE_UINT64:
00666     case FFI_TYPE_SINT64:
00667       flags |= FLAG_RETURNS_64BITS;
00668       break;
00669 
00670     case FFI_TYPE_STRUCT:
00671       if (cif->abi == FFI_SYSV)
00672        {
00673          /* The final SYSV ABI says that structures smaller or equal 8 bytes
00674             are returned in r3/r4. The FFI_GCC_SYSV ABI instead returns them
00675             in memory.  */
00676 
00677          /* Treat structs with size <= 8 bytes.  */
00678          if (size <= 8)
00679            {
00680              flags |= FLAG_RETURNS_SMST;
00681              /* These structs are returned in r3. We pack the type and the
00682                precalculated shift value (needed in the sysv.S) into flags.
00683                The same applies for the structs returned in r3/r4.  */
00684              if (size <= 4)
00685               {
00686                 flags |= FLAG_SYSV_SMST_R3;
00687                 flags |= 8 * (4 - size) << 4;
00688                 break;
00689               }
00690              /* These structs are returned in r3 and r4. See above.   */
00691              if  (size <= 8)
00692               {
00693                 flags |= FLAG_SYSV_SMST_R4;
00694                 flags |= 8 * (8 - size) << 4;
00695                 break;
00696               }
00697            }
00698        }
00699 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
00700     byref:
00701 #endif
00702       intarg_count++;
00703       flags |= FLAG_RETVAL_REFERENCE;
00704       /* Fall through.  */
00705     case FFI_TYPE_VOID:
00706       flags |= FLAG_RETURNS_NOTHING;
00707       break;
00708 
00709     default:
00710       /* Returns 32-bit integer, or similar.  Nothing to do here.  */
00711       break;
00712     }
00713 
00714   if (cif->abi != FFI_LINUX64)
00715     /* The first NUM_GPR_ARG_REGISTERS words of integer arguments, and the
00716        first NUM_FPR_ARG_REGISTERS fp arguments, go in registers; the rest
00717        goes on the stack.  Structures and long doubles (if not equivalent
00718        to double) are passed as a pointer to a copy of the structure.
00719        Stuff on the stack needs to keep proper alignment.  */
00720     for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
00721       {
00722        switch ((*ptr)->type)
00723          {
00724          case FFI_TYPE_FLOAT:
00725            /* With FFI_LINUX_SOFT_FLOAT floats are handled like UINT32.  */
00726            if (cif->abi == FFI_LINUX_SOFT_FLOAT)
00727              goto soft_float_cif;
00728            fparg_count++;
00729            /* floating singles are not 8-aligned on stack */
00730            break;
00731 
00732 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
00733          case FFI_TYPE_LONGDOUBLE:
00734            if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX_SOFT_FLOAT)
00735              goto do_struct;
00736            if (cif->abi == FFI_LINUX_SOFT_FLOAT)
00737              {
00738               if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3
00739                 || intarg_count < NUM_GPR_ARG_REGISTERS)
00740                 /* A long double in FFI_LINUX_SOFT_FLOAT can use only
00741                    a set of four consecutive gprs. If we have not enough,
00742                    we have to adjust the intarg_count value.  */
00743                 intarg_count += NUM_GPR_ARG_REGISTERS - intarg_count;
00744               intarg_count += 4;
00745               break;
00746              }
00747            else
00748              fparg_count++;
00749            /* Fall thru */
00750 #endif
00751          case FFI_TYPE_DOUBLE:
00752            /* With FFI_LINUX_SOFT_FLOAT doubles are handled like UINT64.  */
00753            if (cif->abi == FFI_LINUX_SOFT_FLOAT)
00754              goto soft_double_cif;
00755            fparg_count++;
00756            /* If this FP arg is going on the stack, it must be
00757               8-byte-aligned.  */
00758            if (fparg_count > NUM_FPR_ARG_REGISTERS
00759               && intarg_count >= NUM_GPR_ARG_REGISTERS
00760               && intarg_count % 2 != 0)
00761              intarg_count++;
00762            break;
00763 
00764          case FFI_TYPE_UINT64:
00765          case FFI_TYPE_SINT64:
00766          soft_double_cif:
00767            /* 'long long' arguments are passed as two words, but
00768               either both words must fit in registers or both go
00769               on the stack.  If they go on the stack, they must
00770               be 8-byte-aligned.
00771 
00772               Also, only certain register pairs can be used for
00773               passing long long int -- specifically (r3,r4), (r5,r6),
00774               (r7,r8), (r9,r10).
00775            */
00776            if (intarg_count == NUM_GPR_ARG_REGISTERS-1
00777               || intarg_count % 2 != 0)
00778              intarg_count++;
00779            intarg_count += 2;
00780            break;
00781 
00782          case FFI_TYPE_STRUCT:
00783 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
00784          do_struct:
00785 #endif
00786            /* We must allocate space for a copy of these to enforce
00787               pass-by-value.  Pad the space up to a multiple of 16
00788               bytes (the maximum alignment required for anything under
00789               the SYSV ABI).  */
00790            struct_copy_size += ((*ptr)->size + 15) & ~0xF;
00791            /* Fall through (allocate space for the pointer).  */
00792 
00793          default:
00794          soft_float_cif:
00795            /* Everything else is passed as a 4-byte word in a GPR, either
00796               the object itself or a pointer to it.  */
00797            intarg_count++;
00798            break;
00799          }
00800       }
00801   else
00802     for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
00803       {
00804        switch ((*ptr)->type)
00805          {
00806 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
00807          case FFI_TYPE_LONGDOUBLE:
00808            if (cif->abi == FFI_LINUX_SOFT_FLOAT)
00809              intarg_count += 4;
00810            else
00811              {
00812               fparg_count += 2;
00813               intarg_count += 2;
00814              }
00815            break;
00816 #endif
00817          case FFI_TYPE_FLOAT:
00818          case FFI_TYPE_DOUBLE:
00819            fparg_count++;
00820            intarg_count++;
00821            break;
00822 
00823          case FFI_TYPE_STRUCT:
00824            intarg_count += ((*ptr)->size + 7) / 8;
00825            break;
00826 
00827          default:
00828            /* Everything else is passed as a 8-byte word in a GPR, either
00829               the object itself or a pointer to it.  */
00830            intarg_count++;
00831            break;
00832          }
00833       }
00834 
00835   if (fparg_count != 0)
00836     flags |= FLAG_FP_ARGUMENTS;
00837   if (intarg_count > 4)
00838     flags |= FLAG_4_GPR_ARGUMENTS;
00839   if (struct_copy_size != 0)
00840     flags |= FLAG_ARG_NEEDS_COPY;
00841 
00842   if (cif->abi != FFI_LINUX64)
00843     {
00844       /* Space for the FPR registers, if needed.  */
00845       if (fparg_count != 0)
00846        bytes += NUM_FPR_ARG_REGISTERS * sizeof (double);
00847 
00848       /* Stack space.  */
00849       if (intarg_count > NUM_GPR_ARG_REGISTERS)
00850        bytes += (intarg_count - NUM_GPR_ARG_REGISTERS) * sizeof (int);
00851       if (fparg_count > NUM_FPR_ARG_REGISTERS)
00852        bytes += (fparg_count - NUM_FPR_ARG_REGISTERS) * sizeof (double);
00853     }
00854   else
00855     {
00856       /* Space for the FPR registers, if needed.  */
00857       if (fparg_count != 0)
00858        bytes += NUM_FPR_ARG_REGISTERS64 * sizeof (double);
00859 
00860       /* Stack space.  */
00861       if (intarg_count > NUM_GPR_ARG_REGISTERS64)
00862        bytes += (intarg_count - NUM_GPR_ARG_REGISTERS64) * sizeof (long);
00863     }
00864 
00865   /* The stack space allocated needs to be a multiple of 16 bytes.  */
00866   bytes = (bytes + 15) & ~0xF;
00867 
00868   /* Add in the space for the copied structures.  */
00869   bytes += struct_copy_size;
00870 
00871   cif->flags = flags;
00872   cif->bytes = bytes;
00873 
00874   return FFI_OK;
00875 }
00876 
00877 extern void ffi_call_SYSV(extended_cif *, unsigned, unsigned, unsigned *,
00878                        void (*fn)());
00879 extern void FFI_HIDDEN ffi_call_LINUX64(extended_cif *, unsigned long,
00880                                    unsigned long, unsigned long *,
00881                                    void (*fn)());
00882 
00883 void
00884 ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
00885 {
00886   extended_cif ecif;
00887 
00888   ecif.cif = cif;
00889   ecif.avalue = avalue;
00890 
00891   /* If the return value is a struct and we don't have a return       */
00892   /* value address then we need to make one                     */
00893 
00894   if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT))
00895     {
00896       ecif.rvalue = alloca(cif->rtype->size);
00897     }
00898   else
00899     ecif.rvalue = rvalue;
00900 
00901 
00902   switch (cif->abi)
00903     {
00904 #ifndef POWERPC64
00905     case FFI_SYSV:
00906     case FFI_GCC_SYSV:
00907     case FFI_LINUX:
00908     case FFI_LINUX_SOFT_FLOAT:
00909       ffi_call_SYSV (&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn);
00910       break;
00911 #else
00912     case FFI_LINUX64:
00913       ffi_call_LINUX64 (&ecif, -(long) cif->bytes, cif->flags, ecif.rvalue, fn);
00914       break;
00915 #endif
00916     default:
00917       FFI_ASSERT (0);
00918       break;
00919     }
00920 }
00921 
00922 
00923 #ifndef POWERPC64
00924 #define MIN_CACHE_LINE_SIZE 8
00925 
00926 static void
00927 flush_icache (char *wraddr, char *xaddr, int size)
00928 {
00929   int i;
00930   for (i = 0; i < size; i += MIN_CACHE_LINE_SIZE)
00931     __asm__ volatile ("icbi 0,%0;" "dcbf 0,%1;"
00932                     : : "r" (xaddr + i), "r" (wraddr + i) : "memory");
00933   __asm__ volatile ("icbi 0,%0;" "dcbf 0,%1;" "sync;" "isync;"
00934                   : : "r"(xaddr + size - 1), "r"(wraddr + size - 1)
00935                   : "memory");
00936 }
00937 #endif
00938 
00939 ffi_status
00940 ffi_prep_closure_loc (ffi_closure *closure,
00941                     ffi_cif *cif,
00942                     void (*fun) (ffi_cif *, void *, void **, void *),
00943                     void *user_data,
00944                     void *codeloc)
00945 {
00946 #ifdef POWERPC64
00947   void **tramp = (void **) &closure->tramp[0];
00948 
00949   FFI_ASSERT (cif->abi == FFI_LINUX64);
00950   /* Copy function address and TOC from ffi_closure_LINUX64.  */
00951   memcpy (tramp, (char *) ffi_closure_LINUX64, 16);
00952   tramp[2] = codeloc;
00953 #else
00954   unsigned int *tramp;
00955 
00956   FFI_ASSERT (cif->abi == FFI_GCC_SYSV || cif->abi == FFI_SYSV);
00957 
00958   tramp = (unsigned int *) &closure->tramp[0];
00959   tramp[0] = 0x7c0802a6;  /*   mflr    r0 */
00960   tramp[1] = 0x4800000d;  /*   bl      10 <trampoline_initial+0x10> */
00961   tramp[4] = 0x7d6802a6;  /*   mflr    r11 */
00962   tramp[5] = 0x7c0803a6;  /*   mtlr    r0 */
00963   tramp[6] = 0x800b0000;  /*   lwz     r0,0(r11) */
00964   tramp[7] = 0x816b0004;  /*   lwz     r11,4(r11) */
00965   tramp[8] = 0x7c0903a6;  /*   mtctr   r0 */
00966   tramp[9] = 0x4e800420;  /*   bctr */
00967   *(void **) &tramp[2] = (void *) ffi_closure_SYSV; /* function */
00968   *(void **) &tramp[3] = codeloc;                   /* context */
00969 
00970   /* Flush the icache.  */
00971   flush_icache ((char *)tramp, (char *)codeloc, FFI_TRAMPOLINE_SIZE);
00972 #endif
00973 
00974   closure->cif = cif;
00975   closure->fun = fun;
00976   closure->user_data = user_data;
00977 
00978   return FFI_OK;
00979 }
00980 
00981 typedef union
00982 {
00983   float f;
00984   double d;
00985 } ffi_dblfl;
00986 
00987 int ffi_closure_helper_SYSV (ffi_closure *, void *, unsigned long *,
00988                           ffi_dblfl *, unsigned long *);
00989 
00990 /* Basically the trampoline invokes ffi_closure_SYSV, and on
00991  * entry, r11 holds the address of the closure.
00992  * After storing the registers that could possibly contain
00993  * parameters to be passed into the stack frame and setting
00994  * up space for a return value, ffi_closure_SYSV invokes the
00995  * following helper function to do most of the work
00996  */
00997 
00998 int
00999 ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
01000                       unsigned long *pgr, ffi_dblfl *pfr,
01001                       unsigned long *pst)
01002 {
01003   /* rvalue is the pointer to space for return value in closure assembly */
01004   /* pgr is the pointer to where r3-r10 are stored in ffi_closure_SYSV */
01005   /* pfr is the pointer to where f1-f8 are stored in ffi_closure_SYSV  */
01006   /* pst is the pointer to outgoing parameter stack in original caller */
01007 
01008   void **          avalue;
01009   ffi_type **      arg_types;
01010   long             i, avn;
01011   long             nf;   /* number of floating registers already used */
01012   long             ng;   /* number of general registers already used */
01013   ffi_cif *        cif;
01014   double           temp;
01015   unsigned         size;
01016 
01017   cif = closure->cif;
01018   avalue = alloca (cif->nargs * sizeof (void *));
01019   size = cif->rtype->size;
01020 
01021   nf = 0;
01022   ng = 0;
01023 
01024   /* Copy the caller's structure return value address so that the closure
01025      returns the data directly to the caller.
01026      For FFI_SYSV the result is passed in r3/r4 if the struct size is less
01027      or equal 8 bytes.  */
01028 
01029   if ((cif->rtype->type == FFI_TYPE_STRUCT
01030        && !((cif->abi == FFI_SYSV) && (size <= 8)))
01031 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
01032       || (cif->rtype->type == FFI_TYPE_LONGDOUBLE
01033          && cif->abi != FFI_LINUX && cif->abi != FFI_LINUX_SOFT_FLOAT)
01034 #endif
01035       )
01036     {
01037       rvalue = (void *) *pgr;
01038       ng++;
01039       pgr++;
01040     }
01041 
01042   i = 0;
01043   avn = cif->nargs;
01044   arg_types = cif->arg_types;
01045 
01046   /* Grab the addresses of the arguments from the stack frame.  */
01047   while (i < avn)
01048     {
01049       switch (arg_types[i]->type)
01050        {
01051        case FFI_TYPE_SINT8:
01052        case FFI_TYPE_UINT8:
01053          /* there are 8 gpr registers used to pass values */
01054          if (ng < 8)
01055            {
01056              avalue[i] = (char *) pgr + 3;
01057              ng++;
01058              pgr++;
01059            }
01060          else
01061            {
01062              avalue[i] = (char *) pst + 3;
01063              pst++;
01064            }
01065          break;
01066 
01067        case FFI_TYPE_SINT16:
01068        case FFI_TYPE_UINT16:
01069          /* there are 8 gpr registers used to pass values */
01070          if (ng < 8)
01071            {
01072              avalue[i] = (char *) pgr + 2;
01073              ng++;
01074              pgr++;
01075            }
01076          else
01077            {
01078              avalue[i] = (char *) pst + 2;
01079              pst++;
01080            }
01081          break;
01082 
01083        case FFI_TYPE_SINT32:
01084        case FFI_TYPE_UINT32:
01085        case FFI_TYPE_POINTER:
01086        soft_float_closure:
01087          /* there are 8 gpr registers used to pass values */
01088          if (ng < 8)
01089            {
01090              avalue[i] = pgr;
01091              ng++;
01092              pgr++;
01093            }
01094          else
01095            {
01096              avalue[i] = pst;
01097              pst++;
01098            }
01099          break;
01100 
01101        case FFI_TYPE_STRUCT:
01102 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
01103        do_struct:
01104 #endif
01105          /* Structs are passed by reference. The address will appear in a
01106             gpr if it is one of the first 8 arguments.  */
01107          if (ng < 8)
01108            {
01109              avalue[i] = (void *) *pgr;
01110              ng++;
01111              pgr++;
01112            }
01113          else
01114            {
01115              avalue[i] = (void *) *pst;
01116              pst++;
01117            }
01118          break;
01119 
01120        case FFI_TYPE_SINT64:
01121        case FFI_TYPE_UINT64:
01122        soft_double_closure:
01123          /* passing long long ints are complex, they must
01124           * be passed in suitable register pairs such as
01125           * (r3,r4) or (r5,r6) or (r6,r7), or (r7,r8) or (r9,r10)
01126           * and if the entire pair aren't available then the outgoing
01127           * parameter stack is used for both but an alignment of 8
01128           * must will be kept.  So we must either look in pgr
01129           * or pst to find the correct address for this type
01130           * of parameter.
01131           */
01132          if (ng < 7)
01133            {
01134              if (ng & 0x01)
01135               {
01136                 /* skip r4, r6, r8 as starting points */
01137                 ng++;
01138                 pgr++;
01139               }
01140              avalue[i] = pgr;
01141              ng += 2;
01142              pgr += 2;
01143            }
01144          else
01145            {
01146              if (((long) pst) & 4)
01147               pst++;
01148              avalue[i] = pst;
01149              pst += 2;
01150            }
01151          break;
01152 
01153        case FFI_TYPE_FLOAT:
01154          /* With FFI_LINUX_SOFT_FLOAT floats are handled like UINT32.  */
01155          if (cif->abi == FFI_LINUX_SOFT_FLOAT)
01156            goto soft_float_closure;
01157          /* unfortunately float values are stored as doubles
01158           * in the ffi_closure_SYSV code (since we don't check
01159           * the type in that routine).
01160           */
01161 
01162          /* there are 8 64bit floating point registers */
01163 
01164          if (nf < 8)
01165            {
01166              temp = pfr->d;
01167              pfr->f = (float) temp;
01168              avalue[i] = pfr;
01169              nf++;
01170              pfr++;
01171            }
01172          else
01173            {
01174              /* FIXME? here we are really changing the values
01175               * stored in the original calling routines outgoing
01176               * parameter stack.  This is probably a really
01177               * naughty thing to do but...
01178               */
01179              avalue[i] = pst;
01180              pst += 1;
01181            }
01182          break;
01183 
01184        case FFI_TYPE_DOUBLE:
01185          /* With FFI_LINUX_SOFT_FLOAT doubles are handled like UINT64.  */
01186          if (cif->abi == FFI_LINUX_SOFT_FLOAT)
01187            goto soft_double_closure;
01188          /* On the outgoing stack all values are aligned to 8 */
01189          /* there are 8 64bit floating point registers */
01190 
01191          if (nf < 8)
01192            {
01193              avalue[i] = pfr;
01194              nf++;
01195              pfr++;
01196            }
01197          else
01198            {
01199              if (((long) pst) & 4)
01200               pst++;
01201              avalue[i] = pst;
01202              pst += 2;
01203            }
01204          break;
01205 
01206 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
01207        case FFI_TYPE_LONGDOUBLE:
01208          if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX_SOFT_FLOAT)
01209            goto do_struct;
01210          if (cif->abi == FFI_LINUX_SOFT_FLOAT)
01211            { /* Test if for the whole long double, 4 gprs are available.
01212                otherwise the stuff ends up on the stack.  */
01213              if (ng < 5)
01214               {
01215                 avalue[i] = pgr;
01216                 pgr += 4;
01217                 ng += 4;
01218               }
01219              else
01220               {
01221                 avalue[i] = pst;
01222                 pst += 4;
01223               }
01224              break;
01225            }
01226          if (nf < 7)
01227            {
01228              avalue[i] = pfr;
01229              pfr += 2;
01230              nf += 2;
01231            }
01232          else
01233            {
01234              if (((long) pst) & 4)
01235               pst++;
01236              avalue[i] = pst;
01237              pst += 4;
01238              nf = 8;
01239            }
01240          break;
01241 #endif
01242 
01243        default:
01244          FFI_ASSERT (0);
01245        }
01246 
01247       i++;
01248     }
01249 
01250 
01251   (closure->fun) (cif, rvalue, avalue, closure->user_data);
01252 
01253   /* Tell ffi_closure_SYSV how to perform return type promotions.
01254      Because the FFI_SYSV ABI returns the structures <= 8 bytes in r3/r4
01255      we have to tell ffi_closure_SYSV how to treat them. We combine the base
01256      type FFI_SYSV_TYPE_SMALL_STRUCT - 1  with the size of the struct.
01257      So a one byte struct gets the return type 16. Return type 1 to 15 are
01258      already used and we never have a struct with size zero. That is the reason
01259      for the subtraction of 1. See the comment in ffitarget.h about ordering.
01260   */
01261   if (cif->abi == FFI_SYSV && cif->rtype->type == FFI_TYPE_STRUCT
01262       && size <= 8)
01263     return (FFI_SYSV_TYPE_SMALL_STRUCT - 1) + size;
01264 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
01265   else if (cif->rtype->type == FFI_TYPE_LONGDOUBLE
01266           && cif->abi != FFI_LINUX && cif->abi != FFI_LINUX_SOFT_FLOAT)
01267     return FFI_TYPE_STRUCT;
01268 #endif
01269   /* With FFI_LINUX_SOFT_FLOAT floats and doubles are handled like UINT32
01270      respectivley UINT64.  */
01271   if (cif->abi == FFI_LINUX_SOFT_FLOAT)
01272     {
01273       switch (cif->rtype->type)
01274        {
01275        case FFI_TYPE_FLOAT:
01276          return FFI_TYPE_UINT32;
01277          break;
01278        case FFI_TYPE_DOUBLE:
01279          return FFI_TYPE_UINT64;
01280          break;
01281 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
01282        case FFI_TYPE_LONGDOUBLE:
01283          return FFI_TYPE_UINT128;
01284          break;
01285 #endif
01286        default:
01287          return cif->rtype->type;
01288        }
01289     }
01290   else
01291     {
01292       return cif->rtype->type;
01293     }
01294 }
01295 
01296 int FFI_HIDDEN ffi_closure_helper_LINUX64 (ffi_closure *, void *,
01297                                       unsigned long *, ffi_dblfl *);
01298 
01299 int FFI_HIDDEN
01300 ffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue,
01301                          unsigned long *pst, ffi_dblfl *pfr)
01302 {
01303   /* rvalue is the pointer to space for return value in closure assembly */
01304   /* pst is the pointer to parameter save area
01305      (r3-r10 are stored into its first 8 slots by ffi_closure_LINUX64) */
01306   /* pfr is the pointer to where f1-f13 are stored in ffi_closure_LINUX64 */
01307 
01308   void **avalue;
01309   ffi_type **arg_types;
01310   long i, avn;
01311   ffi_cif *cif;
01312   ffi_dblfl *end_pfr = pfr + NUM_FPR_ARG_REGISTERS64;
01313 
01314   cif = closure->cif;
01315   avalue = alloca (cif->nargs * sizeof (void *));
01316 
01317   /* Copy the caller's structure return value address so that the closure
01318      returns the data directly to the caller.  */
01319   if (cif->rtype->type == FFI_TYPE_STRUCT)
01320     {
01321       rvalue = (void *) *pst;
01322       pst++;
01323     }
01324 
01325   i = 0;
01326   avn = cif->nargs;
01327   arg_types = cif->arg_types;
01328 
01329   /* Grab the addresses of the arguments from the stack frame.  */
01330   while (i < avn)
01331     {
01332       switch (arg_types[i]->type)
01333        {
01334        case FFI_TYPE_SINT8:
01335        case FFI_TYPE_UINT8:
01336          avalue[i] = (char *) pst + 7;
01337          pst++;
01338          break;
01339 
01340        case FFI_TYPE_SINT16:
01341        case FFI_TYPE_UINT16:
01342          avalue[i] = (char *) pst + 6;
01343          pst++;
01344          break;
01345 
01346        case FFI_TYPE_SINT32:
01347        case FFI_TYPE_UINT32:
01348          avalue[i] = (char *) pst + 4;
01349          pst++;
01350          break;
01351 
01352        case FFI_TYPE_SINT64:
01353        case FFI_TYPE_UINT64:
01354        case FFI_TYPE_POINTER:
01355          avalue[i] = pst;
01356          pst++;
01357          break;
01358 
01359        case FFI_TYPE_STRUCT:
01360          /* Structures with size less than eight bytes are passed
01361             left-padded.  */
01362          if (arg_types[i]->size < 8)
01363            avalue[i] = (char *) pst + 8 - arg_types[i]->size;
01364          else
01365            avalue[i] = pst;
01366          pst += (arg_types[i]->size + 7) / 8;
01367          break;
01368 
01369        case FFI_TYPE_FLOAT:
01370          /* unfortunately float values are stored as doubles
01371           * in the ffi_closure_LINUX64 code (since we don't check
01372           * the type in that routine).
01373           */
01374 
01375          /* there are 13 64bit floating point registers */
01376 
01377          if (pfr < end_pfr)
01378            {
01379              double temp = pfr->d;
01380              pfr->f = (float) temp;
01381              avalue[i] = pfr;
01382              pfr++;
01383            }
01384          else
01385            avalue[i] = pst;
01386          pst++;
01387          break;
01388 
01389        case FFI_TYPE_DOUBLE:
01390          /* On the outgoing stack all values are aligned to 8 */
01391          /* there are 13 64bit floating point registers */
01392 
01393          if (pfr < end_pfr)
01394            {
01395              avalue[i] = pfr;
01396              pfr++;
01397            }
01398          else
01399            avalue[i] = pst;
01400          pst++;
01401          break;
01402 
01403 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
01404        case FFI_TYPE_LONGDOUBLE:
01405          if (pfr + 1 < end_pfr)
01406            {
01407              avalue[i] = pfr;
01408              pfr += 2;
01409            }
01410          else
01411            {
01412              if (pfr < end_pfr)
01413               {
01414                 /* Passed partly in f13 and partly on the stack.
01415                    Move it all to the stack.  */
01416                 *pst = *(unsigned long *) pfr;
01417                 pfr++;
01418               }
01419              avalue[i] = pst;
01420            }
01421          pst += 2;
01422          break;
01423 #endif
01424 
01425        default:
01426          FFI_ASSERT (0);
01427        }
01428 
01429       i++;
01430     }
01431 
01432 
01433   (closure->fun) (cif, rvalue, avalue, closure->user_data);
01434 
01435   /* Tell ffi_closure_LINUX64 how to perform return type promotions.  */
01436   return cif->rtype->type;
01437 }