Back to index

plt-scheme  4.2.1
ffi.c
Go to the documentation of this file.
00001 /* -----------------------------------------------------------------------
00002    ffi.c - (c) 2003-2004 Randolph Chung <tausq@debian.org>
00003 
00004    HPPA Foreign Function Interface
00005    HP-UX PA ABI support (c) 2006 Free Software Foundation, Inc.
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 CYGNUS SOLUTIONS 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 #define ROUND_UP(v, a)  (((size_t)(v) + (a) - 1) & ~((a) - 1))
00034 
00035 #define MIN_STACK_SIZE  64
00036 #define FIRST_ARG_SLOT  9
00037 #define DEBUG_LEVEL   0
00038 
00039 #define fldw(addr, fpreg) \
00040   __asm__ volatile ("fldw 0(%0), %%" #fpreg "L" : : "r"(addr) : #fpreg)
00041 #define fstw(fpreg, addr) \
00042   __asm__ volatile ("fstw %%" #fpreg "L, 0(%0)" : : "r"(addr))
00043 #define fldd(addr, fpreg) \
00044   __asm__ volatile ("fldd 0(%0), %%" #fpreg : : "r"(addr) : #fpreg)
00045 #define fstd(fpreg, addr) \
00046   __asm__ volatile ("fstd %%" #fpreg "L, 0(%0)" : : "r"(addr))
00047 
00048 #define debug(lvl, x...) do { if (lvl <= DEBUG_LEVEL) { printf(x); } } while (0)
00049 
00050 static inline int ffi_struct_type(ffi_type *t)
00051 {
00052   size_t sz = t->size;
00053 
00054   /* Small structure results are passed in registers,
00055      larger ones are passed by pointer.  Note that
00056      small structures of size 2, 4 and 8 differ from
00057      the corresponding integer types in that they have
00058      different alignment requirements.  */
00059 
00060   if (sz <= 1)
00061     return FFI_TYPE_UINT8;
00062   else if (sz == 2)
00063     return FFI_TYPE_SMALL_STRUCT2;
00064   else if (sz == 3)
00065     return FFI_TYPE_SMALL_STRUCT3;
00066   else if (sz == 4)
00067     return FFI_TYPE_SMALL_STRUCT4;
00068   else if (sz == 5)
00069     return FFI_TYPE_SMALL_STRUCT5;
00070   else if (sz == 6)
00071     return FFI_TYPE_SMALL_STRUCT6;
00072   else if (sz == 7)
00073     return FFI_TYPE_SMALL_STRUCT7;
00074   else if (sz <= 8)
00075     return FFI_TYPE_SMALL_STRUCT8;
00076   else
00077     return FFI_TYPE_STRUCT; /* else, we pass it by pointer.  */
00078 }
00079 
00080 /* PA has a downward growing stack, which looks like this:
00081 
00082    Offset
00083        [ Variable args ]
00084    SP = (4*(n+9))       arg word N
00085    ...
00086    SP-52                arg word 4
00087        [ Fixed args ]
00088    SP-48                arg word 3
00089    SP-44                arg word 2
00090    SP-40                arg word 1
00091    SP-36                arg word 0
00092        [ Frame marker ]
00093    ...
00094    SP-20                RP
00095    SP-4                 previous SP
00096 
00097    The first four argument words on the stack are reserved for use by
00098    the callee.  Instead, the general and floating registers replace
00099    the first four argument slots.  Non FP arguments are passed solely
00100    in the general registers.  FP arguments are passed in both general
00101    and floating registers when using libffi.
00102 
00103    Non-FP 32-bit args are passed in gr26, gr25, gr24 and gr23.
00104    Non-FP 64-bit args are passed in register pairs, starting
00105    on an odd numbered register (i.e. r25+r26 and r23+r24).
00106    FP 32-bit arguments are passed in fr4L, fr5L, fr6L and fr7L.
00107    FP 64-bit arguments are passed in fr5 and fr7.
00108 
00109    The registers are allocated in the same manner as stack slots.
00110    This allows the callee to save its arguments on the stack if
00111    necessary:
00112 
00113    arg word 3 -> gr23 or fr7L
00114    arg word 2 -> gr24 or fr6L or fr7R
00115    arg word 1 -> gr25 or fr5L
00116    arg word 0 -> gr26 or fr4L or fr5R
00117 
00118    Note that fr4R and fr6R are never used for arguments (i.e.,
00119    doubles are not passed in fr4 or fr6).
00120 
00121    The rest of the arguments are passed on the stack starting at SP-52,
00122    but 64-bit arguments need to be aligned to an 8-byte boundary
00123 
00124    This means we can have holes either in the register allocation,
00125    or in the stack.  */
00126 
00127 /* ffi_prep_args is called by the assembly routine once stack space
00128    has been allocated for the function's arguments
00129 
00130    The following code will put everything into the stack frame
00131    (which was allocated by the asm routine), and on return
00132    the asm routine will load the arguments that should be
00133    passed by register into the appropriate registers
00134 
00135    NOTE: We load floating point args in this function... that means we
00136    assume gcc will not mess with fp regs in here.  */
00137 
00138 void ffi_prep_args_pa32(UINT32 *stack, extended_cif *ecif, unsigned bytes)
00139 {
00140   register unsigned int i;
00141   register ffi_type **p_arg;
00142   register void **p_argv;
00143   unsigned int slot = FIRST_ARG_SLOT;
00144   char *dest_cpy;
00145   size_t len;
00146 
00147   debug(1, "%s: stack = %p, ecif = %p, bytes = %u\n", __FUNCTION__, stack,
00148        ecif, bytes);
00149 
00150   p_arg = ecif->cif->arg_types;
00151   p_argv = ecif->avalue;
00152 
00153   for (i = 0; i < ecif->cif->nargs; i++)
00154     {
00155       int type = (*p_arg)->type;
00156 
00157       switch (type)
00158        {
00159        case FFI_TYPE_SINT8:
00160          *(SINT32 *)(stack - slot) = *(SINT8 *)(*p_argv);
00161          break;
00162 
00163        case FFI_TYPE_UINT8:
00164          *(UINT32 *)(stack - slot) = *(UINT8 *)(*p_argv);
00165          break;
00166 
00167        case FFI_TYPE_SINT16:
00168          *(SINT32 *)(stack - slot) = *(SINT16 *)(*p_argv);
00169          break;
00170 
00171        case FFI_TYPE_UINT16:
00172          *(UINT32 *)(stack - slot) = *(UINT16 *)(*p_argv);
00173          break;
00174 
00175        case FFI_TYPE_UINT32:
00176        case FFI_TYPE_SINT32:
00177        case FFI_TYPE_POINTER:
00178          debug(3, "Storing UINT32 %u in slot %u\n", *(UINT32 *)(*p_argv),
00179               slot);
00180          *(UINT32 *)(stack - slot) = *(UINT32 *)(*p_argv);
00181          break;
00182 
00183        case FFI_TYPE_UINT64:
00184        case FFI_TYPE_SINT64:
00185          /* Align slot for 64-bit type.  */
00186          slot += (slot & 1) ? 1 : 2;
00187          *(UINT64 *)(stack - slot) = *(UINT64 *)(*p_argv);
00188          break;
00189 
00190        case FFI_TYPE_FLOAT:
00191          /* First 4 args go in fr4L - fr7L.  */
00192          debug(3, "Storing UINT32(float) in slot %u\n", slot);
00193          *(UINT32 *)(stack - slot) = *(UINT32 *)(*p_argv);
00194          switch (slot - FIRST_ARG_SLOT)
00195            {
00196            /* First 4 args go in fr4L - fr7L.  */
00197            case 0: fldw(stack - slot, fr4); break;
00198            case 1: fldw(stack - slot, fr5); break;
00199            case 2: fldw(stack - slot, fr6); break;
00200            case 3: fldw(stack - slot, fr7); break;
00201            }
00202          break;
00203 
00204        case FFI_TYPE_DOUBLE:
00205          /* Align slot for 64-bit type.  */
00206          slot += (slot & 1) ? 1 : 2;
00207          debug(3, "Storing UINT64(double) at slot %u\n", slot);
00208          *(UINT64 *)(stack - slot) = *(UINT64 *)(*p_argv);
00209          switch (slot - FIRST_ARG_SLOT)
00210            {
00211              /* First 2 args go in fr5, fr7.  */
00212              case 1: fldd(stack - slot, fr5); break;
00213              case 3: fldd(stack - slot, fr7); break;
00214            }
00215          break;
00216 
00217 #ifdef PA_HPUX
00218        case FFI_TYPE_LONGDOUBLE:
00219          /* Long doubles are passed in the same manner as structures
00220             larger than 8 bytes.  */
00221          *(UINT32 *)(stack - slot) = (UINT32)(*p_argv);
00222          break;
00223 #endif
00224 
00225        case FFI_TYPE_STRUCT:
00226 
00227          /* Structs smaller or equal than 4 bytes are passed in one
00228             register. Structs smaller or equal 8 bytes are passed in two
00229             registers. Larger structures are passed by pointer.  */
00230 
00231          len = (*p_arg)->size;
00232          if (len <= 4)
00233            {
00234              dest_cpy = (char *)(stack - slot) + 4 - len;
00235              memcpy(dest_cpy, (char *)*p_argv, len);
00236            }
00237          else if (len <= 8)
00238            {
00239              slot += (slot & 1) ? 1 : 2;
00240              dest_cpy = (char *)(stack - slot) + 8 - len;
00241              memcpy(dest_cpy, (char *)*p_argv, len);
00242            }
00243          else
00244            *(UINT32 *)(stack - slot) = (UINT32)(*p_argv);
00245          break;
00246 
00247        default:
00248          FFI_ASSERT(0);
00249        }
00250 
00251       slot++;
00252       p_arg++;
00253       p_argv++;
00254     }
00255 
00256   /* Make sure we didn't mess up and scribble on the stack.  */
00257   {
00258     unsigned int n;
00259 
00260     debug(5, "Stack setup:\n");
00261     for (n = 0; n < (bytes + 3) / 4; n++)
00262       {
00263        if ((n%4) == 0) { debug(5, "\n%08x: ", (unsigned int)(stack - n)); }
00264        debug(5, "%08x ", *(stack - n));
00265       }
00266     debug(5, "\n");
00267   }
00268 
00269   FFI_ASSERT(slot * 4 <= bytes);
00270 
00271   return;
00272 }
00273 
00274 static void ffi_size_stack_pa32(ffi_cif *cif)
00275 {
00276   ffi_type **ptr;
00277   int i;
00278   int z = 0; /* # stack slots */
00279 
00280   for (ptr = cif->arg_types, i = 0; i < cif->nargs; ptr++, i++)
00281     {
00282       int type = (*ptr)->type;
00283 
00284       switch (type)
00285        {
00286        case FFI_TYPE_DOUBLE:
00287        case FFI_TYPE_UINT64:
00288        case FFI_TYPE_SINT64:
00289          z += 2 + (z & 1); /* must start on even regs, so we may waste one */
00290          break;
00291 
00292 #ifdef PA_HPUX
00293        case FFI_TYPE_LONGDOUBLE:
00294 #endif
00295        case FFI_TYPE_STRUCT:
00296          z += 1; /* pass by ptr, callee will copy */
00297          break;
00298 
00299        default: /* <= 32-bit values */
00300          z++;
00301        }
00302     }
00303 
00304   /* We can fit up to 6 args in the default 64-byte stack frame,
00305      if we need more, we need more stack.  */
00306   if (z <= 6)
00307     cif->bytes = MIN_STACK_SIZE; /* min stack size */
00308   else
00309     cif->bytes = 64 + ROUND_UP((z - 6) * sizeof(UINT32), MIN_STACK_SIZE);
00310 
00311   debug(3, "Calculated stack size is %u bytes\n", cif->bytes);
00312 }
00313 
00314 /* Perform machine dependent cif processing.  */
00315 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
00316 {
00317   /* Set the return type flag */
00318   switch (cif->rtype->type)
00319     {
00320     case FFI_TYPE_VOID:
00321     case FFI_TYPE_FLOAT:
00322     case FFI_TYPE_DOUBLE:
00323       cif->flags = (unsigned) cif->rtype->type;
00324       break;
00325 
00326 #ifdef PA_HPUX
00327     case FFI_TYPE_LONGDOUBLE:
00328       /* Long doubles are treated like a structure.  */
00329       cif->flags = FFI_TYPE_STRUCT;
00330       break;
00331 #endif
00332 
00333     case FFI_TYPE_STRUCT:
00334       /* For the return type we have to check the size of the structures.
00335         If the size is smaller or equal 4 bytes, the result is given back
00336         in one register. If the size is smaller or equal 8 bytes than we
00337         return the result in two registers. But if the size is bigger than
00338         8 bytes, we work with pointers.  */
00339       cif->flags = ffi_struct_type(cif->rtype);
00340       break;
00341 
00342     case FFI_TYPE_UINT64:
00343     case FFI_TYPE_SINT64:
00344       cif->flags = FFI_TYPE_UINT64;
00345       break;
00346 
00347     default:
00348       cif->flags = FFI_TYPE_INT;
00349       break;
00350     }
00351 
00352   /* Lucky us, because of the unique PA ABI we get to do our
00353      own stack sizing.  */
00354   switch (cif->abi)
00355     {
00356     case FFI_PA32:
00357       ffi_size_stack_pa32(cif);
00358       break;
00359 
00360     default:
00361       FFI_ASSERT(0);
00362       break;
00363     }
00364 
00365   return FFI_OK;
00366 }
00367 
00368 extern void ffi_call_pa32(void (*)(UINT32 *, extended_cif *, unsigned),
00369                        extended_cif *, unsigned, unsigned, unsigned *,
00370                        void (*fn)());
00371 
00372 void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
00373 {
00374   extended_cif ecif;
00375 
00376   ecif.cif = cif;
00377   ecif.avalue = avalue;
00378 
00379   /* If the return value is a struct and we don't have a return
00380      value address then we need to make one.  */
00381 
00382   if (rvalue == NULL
00383 #ifdef PA_HPUX
00384       && (cif->rtype->type == FFI_TYPE_STRUCT
00385          || cif->rtype->type == FFI_TYPE_LONGDOUBLE))
00386 #else
00387       && cif->rtype->type == FFI_TYPE_STRUCT)
00388 #endif
00389     {
00390       ecif.rvalue = alloca(cif->rtype->size);
00391     }
00392   else
00393     ecif.rvalue = rvalue;
00394 
00395 
00396   switch (cif->abi)
00397     {
00398     case FFI_PA32:
00399       debug(3, "Calling ffi_call_pa32: ecif=%p, bytes=%u, flags=%u, rvalue=%p, fn=%p\n", &ecif, cif->bytes, cif->flags, ecif.rvalue, (void *)fn);
00400       ffi_call_pa32(ffi_prep_args_pa32, &ecif, cif->bytes,
00401                    cif->flags, ecif.rvalue, fn);
00402       break;
00403 
00404     default:
00405       FFI_ASSERT(0);
00406       break;
00407     }
00408 }
00409 
00410 #if FFI_CLOSURES
00411 /* This is more-or-less an inverse of ffi_call -- we have arguments on
00412    the stack, and we need to fill them into a cif structure and invoke
00413    the user function. This really ought to be in asm to make sure
00414    the compiler doesn't do things we don't expect.  */
00415 ffi_status ffi_closure_inner_pa32(ffi_closure *closure, UINT32 *stack)
00416 {
00417   ffi_cif *cif;
00418   void **avalue;
00419   void *rvalue;
00420   UINT32 ret[2]; /* function can return up to 64-bits in registers */
00421   ffi_type **p_arg;
00422   char *tmp;
00423   int i, avn;
00424   unsigned int slot = FIRST_ARG_SLOT;
00425   register UINT32 r28 asm("r28");
00426 
00427   cif = closure->cif;
00428 
00429   /* If returning via structure, callee will write to our pointer.  */
00430   if (cif->flags == FFI_TYPE_STRUCT)
00431     rvalue = (void *)r28;
00432   else
00433     rvalue = &ret[0];
00434 
00435   avalue = (void **)alloca(cif->nargs * FFI_SIZEOF_ARG);
00436   avn = cif->nargs;
00437   p_arg = cif->arg_types;
00438 
00439   for (i = 0; i < avn; i++)
00440     {
00441       int type = (*p_arg)->type;
00442 
00443       switch (type)
00444        {
00445        case FFI_TYPE_SINT8:
00446        case FFI_TYPE_UINT8:
00447        case FFI_TYPE_SINT16:
00448        case FFI_TYPE_UINT16:
00449        case FFI_TYPE_SINT32:
00450        case FFI_TYPE_UINT32:
00451        case FFI_TYPE_POINTER:
00452          avalue[i] = (char *)(stack - slot) + sizeof(UINT32) - (*p_arg)->size;
00453          break;
00454 
00455        case FFI_TYPE_SINT64:
00456        case FFI_TYPE_UINT64:
00457          slot += (slot & 1) ? 1 : 2;
00458          avalue[i] = (void *)(stack - slot);
00459          break;
00460 
00461        case FFI_TYPE_FLOAT:
00462 #ifdef PA_LINUX
00463          /* The closure call is indirect.  In Linux, floating point
00464             arguments in indirect calls with a prototype are passed
00465             in the floating point registers instead of the general
00466             registers.  So, we need to replace what was previously
00467             stored in the current slot with the value in the
00468             corresponding floating point register.  */
00469          switch (slot - FIRST_ARG_SLOT)
00470            {
00471            case 0: fstw(fr4, (void *)(stack - slot)); break;
00472            case 1: fstw(fr5, (void *)(stack - slot)); break;
00473            case 2: fstw(fr6, (void *)(stack - slot)); break;
00474            case 3: fstw(fr7, (void *)(stack - slot)); break;
00475            }
00476 #endif
00477          avalue[i] = (void *)(stack - slot);
00478          break;
00479 
00480        case FFI_TYPE_DOUBLE:
00481          slot += (slot & 1) ? 1 : 2;
00482 #ifdef PA_LINUX
00483          /* See previous comment for FFI_TYPE_FLOAT.  */
00484          switch (slot - FIRST_ARG_SLOT)
00485            {
00486            case 1: fstd(fr5, (void *)(stack - slot)); break;
00487            case 3: fstd(fr7, (void *)(stack - slot)); break;
00488            }
00489 #endif
00490          avalue[i] = (void *)(stack - slot);
00491          break;
00492 
00493        case FFI_TYPE_STRUCT:
00494          /* Structs smaller or equal than 4 bytes are passed in one
00495             register. Structs smaller or equal 8 bytes are passed in two
00496             registers. Larger structures are passed by pointer.  */
00497          if((*p_arg)->size <= 4)
00498            {
00499              avalue[i] = (void *)(stack - slot) + sizeof(UINT32) -
00500               (*p_arg)->size;
00501            }
00502          else if ((*p_arg)->size <= 8)
00503            {
00504              slot += (slot & 1) ? 1 : 2;
00505              avalue[i] = (void *)(stack - slot) + sizeof(UINT64) -
00506               (*p_arg)->size;
00507            }
00508          else
00509            avalue[i] = (void *) *(stack - slot);
00510          break;
00511 
00512        default:
00513          FFI_ASSERT(0);
00514        }
00515 
00516       slot++;
00517       p_arg++;
00518     }
00519 
00520   /* Invoke the closure.  */
00521   (closure->fun) (cif, rvalue, avalue, closure->user_data);
00522 
00523   debug(3, "after calling function, ret[0] = %08x, ret[1] = %08x\n", ret[0],
00524        ret[1]);
00525 
00526   /* Store the result using the lower 2 bytes of the flags.  */
00527   switch (cif->flags)
00528     {
00529     case FFI_TYPE_UINT8:
00530       *(stack - FIRST_ARG_SLOT) = (UINT8)(ret[0] >> 24);
00531       break;
00532     case FFI_TYPE_SINT8:
00533       *(stack - FIRST_ARG_SLOT) = (SINT8)(ret[0] >> 24);
00534       break;
00535     case FFI_TYPE_UINT16:
00536       *(stack - FIRST_ARG_SLOT) = (UINT16)(ret[0] >> 16);
00537       break;
00538     case FFI_TYPE_SINT16:
00539       *(stack - FIRST_ARG_SLOT) = (SINT16)(ret[0] >> 16);
00540       break;
00541     case FFI_TYPE_INT:
00542     case FFI_TYPE_SINT32:
00543     case FFI_TYPE_UINT32:
00544       *(stack - FIRST_ARG_SLOT) = ret[0];
00545       break;
00546     case FFI_TYPE_SINT64:
00547     case FFI_TYPE_UINT64:
00548       *(stack - FIRST_ARG_SLOT) = ret[0];
00549       *(stack - FIRST_ARG_SLOT - 1) = ret[1];
00550       break;
00551 
00552     case FFI_TYPE_DOUBLE:
00553       fldd(rvalue, fr4);
00554       break;
00555 
00556     case FFI_TYPE_FLOAT:
00557       fldw(rvalue, fr4);
00558       break;
00559 
00560     case FFI_TYPE_STRUCT:
00561       /* Don't need a return value, done by caller.  */
00562       break;
00563 
00564     case FFI_TYPE_SMALL_STRUCT2:
00565     case FFI_TYPE_SMALL_STRUCT3:
00566     case FFI_TYPE_SMALL_STRUCT4:
00567       tmp = (void*)(stack -  FIRST_ARG_SLOT);
00568       tmp += 4 - cif->rtype->size;
00569       memcpy((void*)tmp, &ret[0], cif->rtype->size);
00570       break;
00571 
00572     case FFI_TYPE_SMALL_STRUCT5:
00573     case FFI_TYPE_SMALL_STRUCT6:
00574     case FFI_TYPE_SMALL_STRUCT7:
00575     case FFI_TYPE_SMALL_STRUCT8:
00576       {
00577        unsigned int ret2[2];
00578        int off;
00579 
00580        /* Right justify ret[0] and ret[1] */
00581        switch (cif->flags)
00582          {
00583            case FFI_TYPE_SMALL_STRUCT5: off = 3; break;
00584            case FFI_TYPE_SMALL_STRUCT6: off = 2; break;
00585            case FFI_TYPE_SMALL_STRUCT7: off = 1; break;
00586            default: off = 0; break;
00587          }
00588 
00589        memset (ret2, 0, sizeof (ret2));
00590        memcpy ((char *)ret2 + off, ret, 8 - off);
00591 
00592        *(stack - FIRST_ARG_SLOT) = ret2[0];
00593        *(stack - FIRST_ARG_SLOT - 1) = ret2[1];
00594       }
00595       break;
00596 
00597     case FFI_TYPE_POINTER:
00598     case FFI_TYPE_VOID:
00599       break;
00600 
00601     default:
00602       debug(0, "assert with cif->flags: %d\n",cif->flags);
00603       FFI_ASSERT(0);
00604       break;
00605     }
00606   return FFI_OK;
00607 }
00608 
00609 /* Fill in a closure to refer to the specified fun and user_data.
00610    cif specifies the argument and result types for fun.
00611    The cif must already be prep'ed.  */
00612 
00613 extern void ffi_closure_pa32(void);
00614 
00615 ffi_status
00616 ffi_prep_closure_loc (ffi_closure* closure,
00617                     ffi_cif* cif,
00618                     void (*fun)(ffi_cif*,void*,void**,void*),
00619                     void *user_data,
00620                     void *codeloc)
00621 {
00622   UINT32 *tramp = (UINT32 *)(closure->tramp);
00623 #ifdef PA_HPUX
00624   UINT32 *tmp;
00625 #endif
00626 
00627   FFI_ASSERT (cif->abi == FFI_PA32);
00628 
00629   /* Make a small trampoline that will branch to our
00630      handler function. Use PC-relative addressing.  */
00631 
00632 #ifdef PA_LINUX
00633   tramp[0] = 0xeaa00000; /* b,l .+8,%r21        ; %r21 <- pc+8 */
00634   tramp[1] = 0xd6a01c1e; /* depi 0,31,2,%r21    ; mask priv bits */
00635   tramp[2] = 0x4aa10028; /* ldw 20(%r21),%r1    ; load plabel */
00636   tramp[3] = 0x36b53ff1; /* ldo -8(%r21),%r21   ; get closure addr */
00637   tramp[4] = 0x0c201096; /* ldw 0(%r1),%r22     ; address of handler */
00638   tramp[5] = 0xeac0c000; /* bv%r0(%r22)         ; branch to handler */
00639   tramp[6] = 0x0c281093; /* ldw 4(%r1),%r19     ; GP of handler */
00640   tramp[7] = ((UINT32)(ffi_closure_pa32) & ~2);
00641 
00642   /* Flush d/icache -- have to flush up 2 two lines because of
00643      alignment.  */
00644   __asm__ volatile(
00645                  "fdc 0(%0)\n\t"
00646                  "fdc %1(%0)\n\t"
00647                  "fic 0(%%sr4, %0)\n\t"
00648                  "fic %1(%%sr4, %0)\n\t"
00649                  "sync\n\t"
00650                  "nop\n\t"
00651                  "nop\n\t"
00652                  "nop\n\t"
00653                  "nop\n\t"
00654                  "nop\n\t"
00655                  "nop\n\t"
00656                  "nop\n"
00657                  :
00658                  : "r"((unsigned long)tramp & ~31),
00659                    "r"(32 /* stride */)
00660                  : "memory");
00661 #endif
00662 
00663 #ifdef PA_HPUX
00664   tramp[0] = 0xeaa00000; /* b,l .+8,%r21        ; %r21 <- pc+8  */
00665   tramp[1] = 0xd6a01c1e; /* depi 0,31,2,%r21    ; mask priv bits  */
00666   tramp[2] = 0x4aa10038; /* ldw 28(%r21),%r1    ; load plabel  */
00667   tramp[3] = 0x36b53ff1; /* ldo -8(%r21),%r21   ; get closure addr  */
00668   tramp[4] = 0x0c201096; /* ldw 0(%r1),%r22     ; address of handler  */
00669   tramp[5] = 0x02c010b4; /* ldsid (%r22),%r20   ; load space id  */
00670   tramp[6] = 0x00141820; /* mtsp %r20,%sr0      ; into %sr0  */
00671   tramp[7] = 0xe2c00000; /* be 0(%sr0,%r22)     ; branch to handler  */
00672   tramp[8] = 0x0c281093; /* ldw 4(%r1),%r19     ; GP of handler  */
00673   tramp[9] = ((UINT32)(ffi_closure_pa32) & ~2);
00674 
00675   /* Flush d/icache -- have to flush three lines because of alignment.  */
00676   __asm__ volatile(
00677                  "copy %1,%0\n\t"
00678                  "fdc,m %2(%0)\n\t"
00679                  "fdc,m %2(%0)\n\t"
00680                  "fdc,m %2(%0)\n\t"
00681                  "ldsid (%1),%0\n\t"
00682                  "mtsp %0,%%sr0\n\t"
00683                  "copy %1,%0\n\t"
00684                  "fic,m %2(%%sr0,%0)\n\t"
00685                  "fic,m %2(%%sr0,%0)\n\t"
00686                  "fic,m %2(%%sr0,%0)\n\t"
00687                  "sync\n\t"
00688                  "nop\n\t"
00689                  "nop\n\t"
00690                  "nop\n\t"
00691                  "nop\n\t"
00692                  "nop\n\t"
00693                  "nop\n\t"
00694                  "nop\n"
00695                  : "=&r" ((unsigned long)tmp)
00696                  : "r" ((unsigned long)tramp & ~31),
00697                    "r" (32/* stride */)
00698                  : "memory");
00699 #endif
00700 
00701   closure->cif  = cif;
00702   closure->user_data = user_data;
00703   closure->fun  = fun;
00704 
00705   return FFI_OK;
00706 }
00707 #endif