Back to index

plt-scheme  4.2.1
ffi.c
Go to the documentation of this file.
00001 /* -----------------------------------------------------------------------
00002    ffi.c - Copyright (c) 2000, 2007 Software AG
00003  
00004    S390 Foreign Function Interface
00005  
00006    Permission is hereby granted, free of charge, to any person obtaining
00007    a copy of this software and associated documentation files (the
00008    ``Software''), to deal in the Software without restriction, including
00009    without limitation the rights to use, copy, modify, merge, publish,
00010    distribute, sublicense, and/or sell copies of the Software, and to
00011    permit persons to whom the Software is furnished to do so, subject to
00012    the following conditions:
00013  
00014    The above copyright notice and this permission notice shall be included
00015    in all copies or substantial portions of the Software.
00016  
00017    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
00018    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00019    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00020    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
00021    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00022    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00023    OTHER DEALINGS IN THE SOFTWARE.
00024    ----------------------------------------------------------------------- */
00025 /*====================================================================*/
00026 /*                          Includes                                  */
00027 /*                          --------                                  */
00028 /*====================================================================*/
00029  
00030 #include <ffi.h>
00031 #include <ffi_common.h>
00032  
00033 #include <stdlib.h>
00034 #include <stdio.h>
00035  
00036 /*====================== End of Includes =============================*/
00037  
00038 /*====================================================================*/
00039 /*                           Defines                                  */
00040 /*                           -------                                  */
00041 /*====================================================================*/
00042 
00043 /* Maximum number of GPRs available for argument passing.  */ 
00044 #define MAX_GPRARGS 5
00045 
00046 /* Maximum number of FPRs available for argument passing.  */ 
00047 #ifdef __s390x__
00048 #define MAX_FPRARGS 4
00049 #else
00050 #define MAX_FPRARGS 2
00051 #endif
00052 
00053 /* Round to multiple of 16.  */
00054 #define ROUND_SIZE(size) (((size) + 15) & ~15)
00055 
00056 /* If these values change, sysv.S must be adapted!  */
00057 #define FFI390_RET_VOID            0
00058 #define FFI390_RET_STRUCT   1
00059 #define FFI390_RET_FLOAT    2
00060 #define FFI390_RET_DOUBLE   3
00061 #define FFI390_RET_INT32    4
00062 #define FFI390_RET_INT64    5
00063 
00064 /*===================== End of Defines ===============================*/
00065  
00066 /*====================================================================*/
00067 /*                          Prototypes                                */
00068 /*                          ----------                                */
00069 /*====================================================================*/
00070  
00071 static void ffi_prep_args (unsigned char *, extended_cif *);
00072 void
00073 #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
00074 __attribute__ ((visibility ("hidden")))
00075 #endif
00076 ffi_closure_helper_SYSV (ffi_closure *, unsigned long *, 
00077                       unsigned long long *, unsigned long *);
00078 
00079 /*====================== End of Prototypes ===========================*/
00080  
00081 /*====================================================================*/
00082 /*                          Externals                                 */
00083 /*                          ---------                                 */
00084 /*====================================================================*/
00085  
00086 extern void ffi_call_SYSV(unsigned,
00087                        extended_cif *,
00088                        void (*)(unsigned char *, extended_cif *),
00089                        unsigned,
00090                        void *,
00091                        void (*fn)());
00092 
00093 extern void ffi_closure_SYSV(void);
00094  
00095 /*====================== End of Externals ============================*/
00096  
00097 /*====================================================================*/
00098 /*                                                                    */
00099 /* Name     - ffi_check_struct_type.                                  */
00100 /*                                                                    */
00101 /* Function - Determine if a structure can be passed within a         */
00102 /*            general purpose or floating point register.             */
00103 /*                                                                    */
00104 /*====================================================================*/
00105  
00106 static int
00107 ffi_check_struct_type (ffi_type *arg)
00108 {
00109   size_t size = arg->size;
00110 
00111   /* If the struct has just one element, look at that element
00112      to find out whether to consider the struct as floating point.  */
00113   while (arg->type == FFI_TYPE_STRUCT 
00114          && arg->elements[0] && !arg->elements[1])
00115     arg = arg->elements[0];
00116 
00117   /* Structs of size 1, 2, 4, and 8 are passed in registers,
00118      just like the corresponding int/float types.  */
00119   switch (size)
00120     {
00121       case 1:
00122         return FFI_TYPE_UINT8;
00123 
00124       case 2:
00125         return FFI_TYPE_UINT16;
00126 
00127       case 4:
00128        if (arg->type == FFI_TYPE_FLOAT)
00129           return FFI_TYPE_FLOAT;
00130        else
00131          return FFI_TYPE_UINT32;
00132 
00133       case 8:
00134        if (arg->type == FFI_TYPE_DOUBLE)
00135           return FFI_TYPE_DOUBLE;
00136        else
00137          return FFI_TYPE_UINT64;
00138 
00139       default:
00140        break;
00141     }
00142 
00143   /* Other structs are passed via a pointer to the data.  */
00144   return FFI_TYPE_POINTER;
00145 }
00146  
00147 /*======================== End of Routine ============================*/
00148  
00149 /*====================================================================*/
00150 /*                                                                    */
00151 /* Name     - ffi_prep_args.                                          */
00152 /*                                                                    */
00153 /* Function - Prepare parameters for call to function.                */
00154 /*                                                                    */
00155 /* ffi_prep_args is called by the assembly routine once stack space   */
00156 /* has been allocated for the function's arguments.                   */
00157 /*                                                                    */
00158 /*====================================================================*/
00159  
00160 static void
00161 ffi_prep_args (unsigned char *stack, extended_cif *ecif)
00162 {
00163   /* The stack space will be filled with those areas:
00164 
00165        FPR argument register save area     (highest addresses)
00166        GPR argument register save area
00167        temporary struct copies
00168        overflow argument area              (lowest addresses)
00169 
00170      We set up the following pointers:
00171 
00172         p_fpr: bottom of the FPR area (growing upwards)
00173        p_gpr: bottom of the GPR area (growing upwards)
00174        p_ov: bottom of the overflow area (growing upwards)
00175        p_struct: top of the struct copy area (growing downwards)
00176 
00177      All areas are kept aligned to twice the word size.  */
00178 
00179   int gpr_off = ecif->cif->bytes;
00180   int fpr_off = gpr_off + ROUND_SIZE (MAX_GPRARGS * sizeof (long));
00181 
00182   unsigned long long *p_fpr = (unsigned long long *)(stack + fpr_off);
00183   unsigned long *p_gpr = (unsigned long *)(stack + gpr_off);
00184   unsigned char *p_struct = (unsigned char *)p_gpr;
00185   unsigned long *p_ov = (unsigned long *)stack;
00186 
00187   int n_fpr = 0;
00188   int n_gpr = 0;
00189   int n_ov = 0;
00190 
00191   ffi_type **ptr;
00192   void **p_argv = ecif->avalue;
00193   int i;
00194  
00195   /* If we returning a structure then we set the first parameter register
00196      to the address of where we are returning this structure.  */
00197 
00198   if (ecif->cif->flags == FFI390_RET_STRUCT)
00199     p_gpr[n_gpr++] = (unsigned long) ecif->rvalue;
00200 
00201   /* Now for the arguments.  */
00202  
00203   for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs;
00204        i > 0;
00205        i--, ptr++, p_argv++)
00206     {
00207       void *arg = *p_argv;
00208       int type = (*ptr)->type;
00209 
00210 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
00211       /* 16-byte long double is passed like a struct.  */
00212       if (type == FFI_TYPE_LONGDOUBLE)
00213        type = FFI_TYPE_STRUCT;
00214 #endif
00215 
00216       /* Check how a structure type is passed.  */
00217       if (type == FFI_TYPE_STRUCT)
00218        {
00219          type = ffi_check_struct_type (*ptr);
00220 
00221          /* If we pass the struct via pointer, copy the data.  */
00222          if (type == FFI_TYPE_POINTER)
00223            {
00224              p_struct -= ROUND_SIZE ((*ptr)->size);
00225              memcpy (p_struct, (char *)arg, (*ptr)->size);
00226              arg = &p_struct;
00227            }
00228        }
00229 
00230       /* Now handle all primitive int/pointer/float data types.  */
00231       switch (type) 
00232        {
00233          case FFI_TYPE_DOUBLE:
00234            if (n_fpr < MAX_FPRARGS)
00235              p_fpr[n_fpr++] = *(unsigned long long *) arg;
00236            else
00237 #ifdef __s390x__
00238              p_ov[n_ov++] = *(unsigned long *) arg;
00239 #else
00240              p_ov[n_ov++] = ((unsigned long *) arg)[0],
00241              p_ov[n_ov++] = ((unsigned long *) arg)[1];
00242 #endif
00243            break;
00244        
00245          case FFI_TYPE_FLOAT:
00246            if (n_fpr < MAX_FPRARGS)
00247              p_fpr[n_fpr++] = (long long) *(unsigned int *) arg << 32;
00248            else
00249              p_ov[n_ov++] = *(unsigned int *) arg;
00250            break;
00251 
00252          case FFI_TYPE_POINTER:
00253            if (n_gpr < MAX_GPRARGS)
00254              p_gpr[n_gpr++] = (unsigned long)*(unsigned char **) arg;
00255            else
00256              p_ov[n_ov++] = (unsigned long)*(unsigned char **) arg;
00257            break;
00258  
00259          case FFI_TYPE_UINT64:
00260          case FFI_TYPE_SINT64:
00261 #ifdef __s390x__
00262            if (n_gpr < MAX_GPRARGS)
00263              p_gpr[n_gpr++] = *(unsigned long *) arg;
00264            else
00265              p_ov[n_ov++] = *(unsigned long *) arg;
00266 #else
00267            if (n_gpr == MAX_GPRARGS-1)
00268              n_gpr = MAX_GPRARGS;
00269            if (n_gpr < MAX_GPRARGS)
00270              p_gpr[n_gpr++] = ((unsigned long *) arg)[0],
00271              p_gpr[n_gpr++] = ((unsigned long *) arg)[1];
00272            else
00273              p_ov[n_ov++] = ((unsigned long *) arg)[0],
00274              p_ov[n_ov++] = ((unsigned long *) arg)[1];
00275 #endif
00276            break;
00277  
00278          case FFI_TYPE_UINT32:
00279            if (n_gpr < MAX_GPRARGS)
00280              p_gpr[n_gpr++] = *(unsigned int *) arg;
00281            else
00282              p_ov[n_ov++] = *(unsigned int *) arg;
00283            break;
00284  
00285          case FFI_TYPE_INT:
00286          case FFI_TYPE_SINT32:
00287            if (n_gpr < MAX_GPRARGS)
00288              p_gpr[n_gpr++] = *(signed int *) arg;
00289            else
00290              p_ov[n_ov++] = *(signed int *) arg;
00291            break;
00292  
00293          case FFI_TYPE_UINT16:
00294            if (n_gpr < MAX_GPRARGS)
00295              p_gpr[n_gpr++] = *(unsigned short *) arg;
00296            else
00297              p_ov[n_ov++] = *(unsigned short *) arg;
00298            break;
00299  
00300          case FFI_TYPE_SINT16:
00301            if (n_gpr < MAX_GPRARGS)
00302              p_gpr[n_gpr++] = *(signed short *) arg;
00303            else
00304              p_ov[n_ov++] = *(signed short *) arg;
00305            break;
00306 
00307          case FFI_TYPE_UINT8:
00308            if (n_gpr < MAX_GPRARGS)
00309              p_gpr[n_gpr++] = *(unsigned char *) arg;
00310            else
00311              p_ov[n_ov++] = *(unsigned char *) arg;
00312            break;
00313  
00314          case FFI_TYPE_SINT8:
00315            if (n_gpr < MAX_GPRARGS)
00316              p_gpr[n_gpr++] = *(signed char *) arg;
00317            else
00318              p_ov[n_ov++] = *(signed char *) arg;
00319            break;
00320  
00321          default:
00322            FFI_ASSERT (0);
00323            break;
00324         }
00325     }
00326 }
00327 
00328 /*======================== End of Routine ============================*/
00329  
00330 /*====================================================================*/
00331 /*                                                                    */
00332 /* Name     - ffi_prep_cif_machdep.                                   */
00333 /*                                                                    */
00334 /* Function - Perform machine dependent CIF processing.               */
00335 /*                                                                    */
00336 /*====================================================================*/
00337  
00338 ffi_status
00339 ffi_prep_cif_machdep(ffi_cif *cif)
00340 {
00341   size_t struct_size = 0;
00342   int n_gpr = 0;
00343   int n_fpr = 0;
00344   int n_ov = 0;
00345 
00346   ffi_type **ptr;
00347   int i;
00348 
00349   /* Determine return value handling.  */ 
00350 
00351   switch (cif->rtype->type)
00352     {
00353       /* Void is easy.  */
00354       case FFI_TYPE_VOID:
00355        cif->flags = FFI390_RET_VOID;
00356        break;
00357 
00358       /* Structures are returned via a hidden pointer.  */
00359       case FFI_TYPE_STRUCT:
00360        cif->flags = FFI390_RET_STRUCT;
00361        n_gpr++;  /* We need one GPR to pass the pointer.  */
00362        break; 
00363 
00364       /* Floating point values are returned in fpr 0.  */
00365       case FFI_TYPE_FLOAT:
00366        cif->flags = FFI390_RET_FLOAT;
00367        break;
00368 
00369       case FFI_TYPE_DOUBLE:
00370        cif->flags = FFI390_RET_DOUBLE;
00371        break;
00372 
00373 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
00374       case FFI_TYPE_LONGDOUBLE:
00375        cif->flags = FFI390_RET_STRUCT;
00376        n_gpr++;
00377        break;
00378 #endif
00379       /* Integer values are returned in gpr 2 (and gpr 3
00380         for 64-bit values on 31-bit machines).  */
00381       case FFI_TYPE_UINT64:
00382       case FFI_TYPE_SINT64:
00383        cif->flags = FFI390_RET_INT64;
00384        break;
00385 
00386       case FFI_TYPE_POINTER:
00387       case FFI_TYPE_INT:
00388       case FFI_TYPE_UINT32:
00389       case FFI_TYPE_SINT32:
00390       case FFI_TYPE_UINT16:
00391       case FFI_TYPE_SINT16:
00392       case FFI_TYPE_UINT8:
00393       case FFI_TYPE_SINT8:
00394        /* These are to be extended to word size.  */
00395 #ifdef __s390x__
00396        cif->flags = FFI390_RET_INT64;
00397 #else
00398        cif->flags = FFI390_RET_INT32;
00399 #endif
00400        break;
00401  
00402       default:
00403         FFI_ASSERT (0);
00404         break;
00405     }
00406 
00407   /* Now for the arguments.  */
00408  
00409   for (ptr = cif->arg_types, i = cif->nargs;
00410        i > 0;
00411        i--, ptr++)
00412     {
00413       int type = (*ptr)->type;
00414 
00415 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
00416       /* 16-byte long double is passed like a struct.  */
00417       if (type == FFI_TYPE_LONGDOUBLE)
00418        type = FFI_TYPE_STRUCT;
00419 #endif
00420 
00421       /* Check how a structure type is passed.  */
00422       if (type == FFI_TYPE_STRUCT)
00423        {
00424          type = ffi_check_struct_type (*ptr);
00425 
00426          /* If we pass the struct via pointer, we must reserve space
00427             to copy its data for proper call-by-value semantics.  */
00428          if (type == FFI_TYPE_POINTER)
00429            struct_size += ROUND_SIZE ((*ptr)->size);
00430        }
00431 
00432       /* Now handle all primitive int/float data types.  */
00433       switch (type) 
00434        {
00435          /* The first MAX_FPRARGS floating point arguments
00436             go in FPRs, the rest overflow to the stack.  */
00437 
00438          case FFI_TYPE_DOUBLE:
00439            if (n_fpr < MAX_FPRARGS)
00440              n_fpr++;
00441            else
00442              n_ov += sizeof (double) / sizeof (long);
00443            break;
00444        
00445          case FFI_TYPE_FLOAT:
00446            if (n_fpr < MAX_FPRARGS)
00447              n_fpr++;
00448            else
00449              n_ov++;
00450            break;
00451 
00452          /* On 31-bit machines, 64-bit integers are passed in GPR pairs,
00453             if one is still available, or else on the stack.  If only one
00454             register is free, skip the register (it won't be used for any 
00455             subsequent argument either).  */
00456              
00457 #ifndef __s390x__
00458          case FFI_TYPE_UINT64:
00459          case FFI_TYPE_SINT64:
00460            if (n_gpr == MAX_GPRARGS-1)
00461              n_gpr = MAX_GPRARGS;
00462            if (n_gpr < MAX_GPRARGS)
00463              n_gpr += 2;
00464            else
00465              n_ov += 2;
00466            break;
00467 #endif
00468 
00469          /* Everything else is passed in GPRs (until MAX_GPRARGS
00470             have been used) or overflows to the stack.  */
00471 
00472          default: 
00473            if (n_gpr < MAX_GPRARGS)
00474              n_gpr++;
00475            else
00476              n_ov++;
00477            break;
00478         }
00479     }
00480 
00481   /* Total stack space as required for overflow arguments
00482      and temporary structure copies.  */
00483 
00484   cif->bytes = ROUND_SIZE (n_ov * sizeof (long)) + struct_size;
00485  
00486   return FFI_OK;
00487 }
00488  
00489 /*======================== End of Routine ============================*/
00490  
00491 /*====================================================================*/
00492 /*                                                                    */
00493 /* Name     - ffi_call.                                               */
00494 /*                                                                    */
00495 /* Function - Call the FFI routine.                                   */
00496 /*                                                                    */
00497 /*====================================================================*/
00498  
00499 void
00500 ffi_call(ffi_cif *cif,
00501         void (*fn)(),
00502         void *rvalue,
00503         void **avalue)
00504 {
00505   int ret_type = cif->flags;
00506   extended_cif ecif;
00507  
00508   ecif.cif    = cif;
00509   ecif.avalue = avalue;
00510   ecif.rvalue = rvalue;
00511 
00512   /* If we don't have a return value, we need to fake one.  */
00513   if (rvalue == NULL)
00514     {
00515       if (ret_type == FFI390_RET_STRUCT)
00516        ecif.rvalue = alloca (cif->rtype->size);
00517       else
00518        ret_type = FFI390_RET_VOID;
00519     } 
00520 
00521   switch (cif->abi)
00522     {
00523       case FFI_SYSV:
00524         ffi_call_SYSV (cif->bytes, &ecif, ffi_prep_args,
00525                      ret_type, ecif.rvalue, fn);
00526         break;
00527  
00528       default:
00529         FFI_ASSERT (0);
00530         break;
00531     }
00532 }
00533  
00534 /*======================== End of Routine ============================*/
00535 
00536 /*====================================================================*/
00537 /*                                                                    */
00538 /* Name     - ffi_closure_helper_SYSV.                                */
00539 /*                                                                    */
00540 /* Function - Call a FFI closure target function.                     */
00541 /*                                                                    */
00542 /*====================================================================*/
00543  
00544 void
00545 ffi_closure_helper_SYSV (ffi_closure *closure,
00546                       unsigned long *p_gpr,
00547                       unsigned long long *p_fpr,
00548                       unsigned long *p_ov)
00549 {
00550   unsigned long long ret_buffer;
00551 
00552   void *rvalue = &ret_buffer;
00553   void **avalue;
00554   void **p_arg;
00555 
00556   int n_gpr = 0;
00557   int n_fpr = 0;
00558   int n_ov = 0;
00559 
00560   ffi_type **ptr;
00561   int i;
00562 
00563   /* Allocate buffer for argument list pointers.  */
00564 
00565   p_arg = avalue = alloca (closure->cif->nargs * sizeof (void *));
00566 
00567   /* If we returning a structure, pass the structure address 
00568      directly to the target function.  Otherwise, have the target 
00569      function store the return value to the GPR save area.  */
00570 
00571   if (closure->cif->flags == FFI390_RET_STRUCT)
00572     rvalue = (void *) p_gpr[n_gpr++];
00573 
00574   /* Now for the arguments.  */
00575 
00576   for (ptr = closure->cif->arg_types, i = closure->cif->nargs;
00577        i > 0;
00578        i--, p_arg++, ptr++)
00579     {
00580       int deref_struct_pointer = 0;
00581       int type = (*ptr)->type;
00582 
00583 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
00584       /* 16-byte long double is passed like a struct.  */
00585       if (type == FFI_TYPE_LONGDOUBLE)
00586        type = FFI_TYPE_STRUCT;
00587 #endif
00588 
00589       /* Check how a structure type is passed.  */
00590       if (type == FFI_TYPE_STRUCT)
00591        {
00592          type = ffi_check_struct_type (*ptr);
00593 
00594          /* If we pass the struct via pointer, remember to 
00595             retrieve the pointer later.  */
00596          if (type == FFI_TYPE_POINTER)
00597            deref_struct_pointer = 1;
00598        }
00599 
00600       /* Pointers are passed like UINTs of the same size.  */
00601       if (type == FFI_TYPE_POINTER)
00602 #ifdef __s390x__
00603        type = FFI_TYPE_UINT64;
00604 #else
00605        type = FFI_TYPE_UINT32;
00606 #endif
00607 
00608       /* Now handle all primitive int/float data types.  */
00609       switch (type) 
00610        {
00611          case FFI_TYPE_DOUBLE:
00612            if (n_fpr < MAX_FPRARGS)
00613              *p_arg = &p_fpr[n_fpr++];
00614            else
00615              *p_arg = &p_ov[n_ov], 
00616              n_ov += sizeof (double) / sizeof (long);
00617            break;
00618        
00619          case FFI_TYPE_FLOAT:
00620            if (n_fpr < MAX_FPRARGS)
00621              *p_arg = &p_fpr[n_fpr++];
00622            else
00623              *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 4;
00624            break;
00625  
00626          case FFI_TYPE_UINT64:
00627          case FFI_TYPE_SINT64:
00628 #ifdef __s390x__
00629            if (n_gpr < MAX_GPRARGS)
00630              *p_arg = &p_gpr[n_gpr++];
00631            else
00632              *p_arg = &p_ov[n_ov++];
00633 #else
00634            if (n_gpr == MAX_GPRARGS-1)
00635              n_gpr = MAX_GPRARGS;
00636            if (n_gpr < MAX_GPRARGS)
00637              *p_arg = &p_gpr[n_gpr], n_gpr += 2;
00638            else
00639              *p_arg = &p_ov[n_ov], n_ov += 2;
00640 #endif
00641            break;
00642  
00643          case FFI_TYPE_INT:
00644          case FFI_TYPE_UINT32:
00645          case FFI_TYPE_SINT32:
00646            if (n_gpr < MAX_GPRARGS)
00647              *p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 4;
00648            else
00649              *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 4;
00650            break;
00651  
00652          case FFI_TYPE_UINT16:
00653          case FFI_TYPE_SINT16:
00654            if (n_gpr < MAX_GPRARGS)
00655              *p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 2;
00656            else
00657              *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 2;
00658            break;
00659 
00660          case FFI_TYPE_UINT8:
00661          case FFI_TYPE_SINT8:
00662            if (n_gpr < MAX_GPRARGS)
00663              *p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 1;
00664            else
00665              *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 1;
00666            break;
00667  
00668          default:
00669            FFI_ASSERT (0);
00670            break;
00671         }
00672 
00673       /* If this is a struct passed via pointer, we need to
00674         actually retrieve that pointer.  */
00675       if (deref_struct_pointer)
00676        *p_arg = *(void **)*p_arg;
00677     }
00678 
00679 
00680   /* Call the target function.  */
00681   (closure->fun) (closure->cif, rvalue, avalue, closure->user_data);
00682 
00683   /* Convert the return value.  */
00684   switch (closure->cif->rtype->type)
00685     {
00686       /* Void is easy, and so is struct.  */
00687       case FFI_TYPE_VOID:
00688       case FFI_TYPE_STRUCT:
00689 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
00690       case FFI_TYPE_LONGDOUBLE:
00691 #endif
00692        break;
00693 
00694       /* Floating point values are returned in fpr 0.  */
00695       case FFI_TYPE_FLOAT:
00696        p_fpr[0] = (long long) *(unsigned int *) rvalue << 32;
00697        break;
00698 
00699       case FFI_TYPE_DOUBLE:
00700        p_fpr[0] = *(unsigned long long *) rvalue;
00701        break;
00702 
00703       /* Integer values are returned in gpr 2 (and gpr 3
00704         for 64-bit values on 31-bit machines).  */
00705       case FFI_TYPE_UINT64:
00706       case FFI_TYPE_SINT64:
00707 #ifdef __s390x__
00708        p_gpr[0] = *(unsigned long *) rvalue;
00709 #else
00710        p_gpr[0] = ((unsigned long *) rvalue)[0],
00711        p_gpr[1] = ((unsigned long *) rvalue)[1];
00712 #endif
00713        break;
00714 
00715       case FFI_TYPE_POINTER:
00716       case FFI_TYPE_UINT32:
00717       case FFI_TYPE_UINT16:
00718       case FFI_TYPE_UINT8:
00719        p_gpr[0] = *(unsigned long *) rvalue;
00720        break;
00721 
00722       case FFI_TYPE_INT:
00723       case FFI_TYPE_SINT32:
00724       case FFI_TYPE_SINT16:
00725       case FFI_TYPE_SINT8:
00726        p_gpr[0] = *(signed long *) rvalue;
00727        break;
00728 
00729       default:
00730         FFI_ASSERT (0);
00731         break;
00732     }
00733 }
00734  
00735 /*======================== End of Routine ============================*/
00736 
00737 /*====================================================================*/
00738 /*                                                                    */
00739 /* Name     - ffi_prep_closure_loc.                                   */
00740 /*                                                                    */
00741 /* Function - Prepare a FFI closure.                                  */
00742 /*                                                                    */
00743 /*====================================================================*/
00744  
00745 ffi_status
00746 ffi_prep_closure_loc (ffi_closure *closure,
00747                     ffi_cif *cif,
00748                     void (*fun) (ffi_cif *, void *, void **, void *),
00749                     void *user_data,
00750                     void *codeloc)
00751 {
00752   FFI_ASSERT (cif->abi == FFI_SYSV);
00753 
00754 #ifndef __s390x__
00755   *(short *)&closure->tramp [0] = 0x0d10;   /* basr %r1,0 */
00756   *(short *)&closure->tramp [2] = 0x9801;   /* lm %r0,%r1,6(%r1) */
00757   *(short *)&closure->tramp [4] = 0x1006;
00758   *(short *)&closure->tramp [6] = 0x07f1;   /* br %r1 */
00759   *(long  *)&closure->tramp [8] = (long)codeloc;
00760   *(long  *)&closure->tramp[12] = (long)&ffi_closure_SYSV;
00761 #else
00762   *(short *)&closure->tramp [0] = 0x0d10;   /* basr %r1,0 */
00763   *(short *)&closure->tramp [2] = 0xeb01;   /* lmg %r0,%r1,14(%r1) */
00764   *(short *)&closure->tramp [4] = 0x100e;
00765   *(short *)&closure->tramp [6] = 0x0004;
00766   *(short *)&closure->tramp [8] = 0x07f1;   /* br %r1 */
00767   *(long  *)&closure->tramp[16] = (long)codeloc;
00768   *(long  *)&closure->tramp[24] = (long)&ffi_closure_SYSV;
00769 #endif 
00770  
00771   closure->cif = cif;
00772   closure->user_data = user_data;
00773   closure->fun = fun;
00774  
00775   return FFI_OK;
00776 }
00777 
00778 /*======================== End of Routine ============================*/
00779