1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_bridges.hxx"
30 
31 // This is an implementation of the x86-64 ABI as described in 'System V
32 // Application Binary Interface, AMD64 Architecture Processor Supplement'
33 // (http://www.x86-64.org/documentation/abi-0.95.pdf)
34 //
35 // The code in this file is a modification of src/x86/ffi64.c from libffi
36 // (http://sources.redhat.com/libffi/) which is under the following license:
37 
38 /* -----------------------------------------------------------------------
39    ffi.c - Copyright (c) 2002  Bo Thorsen <bo@suse.de>
40 
41    x86-64 Foreign Function Interface
42 
43    Permission is hereby granted, free of charge, to any person obtaining
44    a copy of this software and associated documentation files (the
45    ``Software''), to deal in the Software without restriction, including
46    without limitation the rights to use, copy, modify, merge, publish,
47    distribute, sublicense, and/or sell copies of the Software, and to
48    permit persons to whom the Software is furnished to do so, subject to
49    the following conditions:
50 
51    The above copyright notice and this permission notice shall be included
52    in all copies or substantial portions of the Software.
53 
54    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
55    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
56    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
57    IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
58    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
59    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
60    OTHER DEALINGS IN THE SOFTWARE.
61    ----------------------------------------------------------------------- */
62 
63 #include <abi.hxx>
64 
65 #include <rtl/ustring.hxx>
66 
67 using namespace x86_64;
68 
69 typedef struct
70 {
71     /* Registers for argument passing.  */
72     long gpr[MAX_GPR_REGS];
73     __int128_t sse[MAX_SSE_REGS];
74 
75     /* Stack space for arguments.  */
76     char argspace[0];
77 } stackLayout;
78 
79 /* Register class used for passing given 64bit part of the argument.
80    These represent classes as documented by the PS ABI, with the exception
81    of SSESF, SSEDF classes, that are basically SSE class, just gcc will
82    use SF or DFmode move instead of DImode to avoid reformating penalties.
83 
84    Similary we play games with INTEGERSI_CLASS to use cheaper SImode moves
85    whenever possible (upper half does contain padding).
86  */
87 enum x86_64_reg_class
88 {
89     X86_64_NO_CLASS,
90     X86_64_INTEGER_CLASS,
91     X86_64_INTEGERSI_CLASS,
92     X86_64_SSE_CLASS,
93     X86_64_SSESF_CLASS,
94     X86_64_SSEDF_CLASS,
95     X86_64_SSEUP_CLASS,
96     X86_64_X87_CLASS,
97     X86_64_X87UP_CLASS,
98     X86_64_MEMORY_CLASS
99 };
100 
101 #define MAX_CLASSES 4
102 
103 #define ALIGN(v, a) (((((size_t) (v))-1) | ((a)-1))+1)
104 
105 /* x86-64 register passing implementation.  See x86-64 ABI for details.  Goal
106    of this code is to classify each 8bytes of incoming argument by the register
107    class and assign registers accordingly.  */
108 
109 /* Return the union class of CLASS1 and CLASS2.
110    See the x86-64 PS ABI for details.  */
111 
112 static enum x86_64_reg_class
113 merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2)
114 {
115     /* Rule #1: If both classes are equal, this is the resulting class.  */
116     if (class1 == class2)
117         return class1;
118 
119     /* Rule #2: If one of the classes is NO_CLASS, the resulting class is
120        the other class.  */
121     if (class1 == X86_64_NO_CLASS)
122         return class2;
123     if (class2 == X86_64_NO_CLASS)
124         return class1;
125 
126     /* Rule #3: If one of the classes is MEMORY, the result is MEMORY.  */
127     if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS)
128         return X86_64_MEMORY_CLASS;
129 
130     /* Rule #4: If one of the classes is INTEGER, the result is INTEGER.  */
131     if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS)
132             || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS))
133         return X86_64_INTEGERSI_CLASS;
134     if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS
135             || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS)
136         return X86_64_INTEGER_CLASS;
137 
138     /* Rule #5: If one of the classes is X87 or X87UP class, MEMORY is used.  */
139     if (class1 == X86_64_X87_CLASS || class1 == X86_64_X87UP_CLASS
140             || class2 == X86_64_X87_CLASS || class2 == X86_64_X87UP_CLASS)
141         return X86_64_MEMORY_CLASS;
142 
143     /* Rule #6: Otherwise class SSE is used.  */
144     return X86_64_SSE_CLASS;
145 }
146 
147 /* Classify the argument of type TYPE and mode MODE.
148    CLASSES will be filled by the register class used to pass each word
149    of the operand.  The number of words is returned.  In case the parameter
150    should be passed in memory, 0 is returned. As a special case for zero
151    sized containers, classes[0] will be NO_CLASS and 1 is returned.
152 
153    See the x86-64 PS ABI for details.
154 */
155 static int
156 classify_argument( typelib_TypeDescriptionReference *pTypeRef, enum x86_64_reg_class classes[], int &rByteOffset )
157 {
158     /* First, align to the right place.  */
159     rByteOffset = ALIGN( rByteOffset, pTypeRef->pType->nAlignment );
160 
161     switch ( pTypeRef->eTypeClass )
162     {
163         case typelib_TypeClass_VOID:
164             classes[0] = X86_64_NO_CLASS;
165             return 1;
166         case typelib_TypeClass_CHAR:
167         case typelib_TypeClass_BOOLEAN:
168         case typelib_TypeClass_BYTE:
169         case typelib_TypeClass_SHORT:
170         case typelib_TypeClass_UNSIGNED_SHORT:
171         case typelib_TypeClass_LONG:
172         case typelib_TypeClass_UNSIGNED_LONG:
173         case typelib_TypeClass_HYPER:
174         case typelib_TypeClass_UNSIGNED_HYPER:
175         case typelib_TypeClass_ENUM:
176             if ( ( rByteOffset % 8 + pTypeRef->pType->nSize ) <= 4 )
177                 classes[0] = X86_64_INTEGERSI_CLASS;
178             else
179                 classes[0] = X86_64_INTEGER_CLASS;
180             return 1;
181         case typelib_TypeClass_FLOAT:
182             if ( ( rByteOffset % 8 ) == 0 )
183                 classes[0] = X86_64_SSESF_CLASS;
184             else
185                 classes[0] = X86_64_SSE_CLASS;
186             return 1;
187         case typelib_TypeClass_DOUBLE:
188             classes[0] = X86_64_SSEDF_CLASS;
189             return 1;
190         /*case LONGDOUBLE:
191             classes[0] = X86_64_X87_CLASS;
192             classes[1] = X86_64_X87UP_CLASS;
193             return 2;*/
194         case typelib_TypeClass_STRING:
195         case typelib_TypeClass_TYPE:
196         case typelib_TypeClass_ANY:
197         case typelib_TypeClass_TYPEDEF:
198         case typelib_TypeClass_UNION:
199         case typelib_TypeClass_SEQUENCE:
200         case typelib_TypeClass_ARRAY:
201         case typelib_TypeClass_INTERFACE:
202             return 0;
203         case typelib_TypeClass_STRUCT:
204         case typelib_TypeClass_EXCEPTION:
205             {
206                 typelib_TypeDescription * pTypeDescr = 0;
207                 TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
208 
209                 const int UNITS_PER_WORD = 8;
210                 int words = ( pTypeDescr->nSize + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD;
211                 enum x86_64_reg_class subclasses[MAX_CLASSES];
212 
213                 /* If the struct is larger than 16 bytes, pass it on the stack.  */
214                 if ( pTypeDescr->nSize > 16 )
215                 {
216                     TYPELIB_DANGER_RELEASE( pTypeDescr );
217                     return 0;
218                 }
219 
220                 for ( int i = 0; i < words; i++ )
221                     classes[i] = X86_64_NO_CLASS;
222 
223                 const typelib_CompoundTypeDescription *pStruct = reinterpret_cast<const typelib_CompoundTypeDescription*>( pTypeDescr );
224 
225                 /* Merge the fields of structure.  */
226                 for ( sal_Int32 nMember = 0; nMember < pStruct->nMembers; ++nMember )
227                 {
228                     typelib_TypeDescriptionReference *pTypeInStruct = pStruct->ppTypeRefs[ nMember ];
229 
230                     int num = classify_argument( pTypeInStruct, subclasses, rByteOffset );
231 
232                     if ( num == 0 )
233                     {
234                         TYPELIB_DANGER_RELEASE( pTypeDescr );
235                         return 0;
236                     }
237 
238                     for ( int i = 0; i < num; i++ )
239                     {
240                         int pos = rByteOffset / 8;
241                         classes[i + pos] = merge_classes( subclasses[i], classes[i + pos] );
242                     }
243 
244                     if ( pTypeInStruct->eTypeClass != typelib_TypeClass_STRUCT )
245                         rByteOffset = pStruct->pMemberOffsets[ nMember ];
246                 }
247 
248                 TYPELIB_DANGER_RELEASE( pTypeDescr );
249 
250                 /* Final merger cleanup.  */
251                 for ( int i = 0; i < words; i++ )
252                 {
253                     /* If one class is MEMORY, everything should be passed in
254                        memory.  */
255                     if ( classes[i] == X86_64_MEMORY_CLASS )
256                         return 0;
257 
258                     /* The X86_64_SSEUP_CLASS should be always preceded by
259                        X86_64_SSE_CLASS.  */
260                     if ( classes[i] == X86_64_SSEUP_CLASS
261                             && ( i == 0 || classes[i - 1] != X86_64_SSE_CLASS ) )
262                         classes[i] = X86_64_SSE_CLASS;
263 
264                     /*  X86_64_X87UP_CLASS should be preceded by X86_64_X87_CLASS.  */
265                     if ( classes[i] == X86_64_X87UP_CLASS
266                             && ( i == 0 || classes[i - 1] != X86_64_X87_CLASS ) )
267                         classes[i] = X86_64_SSE_CLASS;
268                 }
269                 return words;
270             }
271 
272         default:
273 #if OSL_DEBUG_LEVEL > 1
274             OSL_TRACE( "Unhandled case: pType->eTypeClass == %d\n", pTypeRef->eTypeClass );
275 #endif
276             OSL_ASSERT(0);
277     }
278     return 0; /* Never reached.  */
279 }
280 
281 /* Examine the argument and return set number of register required in each
282    class.  Return 0 iff parameter should be passed in memory.  */
283 bool x86_64::examine_argument( typelib_TypeDescriptionReference *pTypeRef, bool bInReturn, int &nUsedGPR, int &nUsedSSE )
284 {
285     enum x86_64_reg_class classes[MAX_CLASSES];
286     int offset = 0;
287     int n;
288 
289     n = classify_argument( pTypeRef, classes, offset );
290 
291     if ( n == 0 )
292         return false;
293 
294     nUsedGPR = 0;
295     nUsedSSE = 0;
296     for ( n--; n >= 0; n-- )
297         switch ( classes[n] )
298         {
299             case X86_64_INTEGER_CLASS:
300             case X86_64_INTEGERSI_CLASS:
301                 nUsedGPR++;
302                 break;
303             case X86_64_SSE_CLASS:
304             case X86_64_SSESF_CLASS:
305             case X86_64_SSEDF_CLASS:
306                 nUsedSSE++;
307                 break;
308             case X86_64_NO_CLASS:
309             case X86_64_SSEUP_CLASS:
310                 break;
311             case X86_64_X87_CLASS:
312             case X86_64_X87UP_CLASS:
313                 if ( !bInReturn )
314                     return false;
315                 break;
316             default:
317 #if OSL_DEBUG_LEVEL > 1
318             OSL_TRACE( "Unhandled case: classes[n] == %d\n", classes[n] );
319 #endif
320             OSL_ASSERT(0);
321         }
322     return true;
323 }
324 
325 bool x86_64::return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef )
326 {
327     int g, s;
328 
329     return examine_argument( pTypeRef, true, g, s ) == 0;
330 }
331 
332 void x86_64::fill_struct( typelib_TypeDescriptionReference *pTypeRef, void * const *pGPR, void * const *pSSE, void *pStruct )
333 {
334     enum x86_64_reg_class classes[MAX_CLASSES];
335     int offset = 0;
336     int n;
337 
338     n = classify_argument( pTypeRef, classes, offset );
339 
340     sal_uInt64 *pStructAlign = reinterpret_cast<sal_uInt64 *>( pStruct );
341     for ( n--; n >= 0; n-- )
342         switch ( classes[n] )
343         {
344             case X86_64_INTEGER_CLASS:
345             case X86_64_INTEGERSI_CLASS:
346                 *pStructAlign++ = *reinterpret_cast<sal_uInt64 *>( *pGPR++ );
347                 break;
348             case X86_64_SSE_CLASS:
349             case X86_64_SSESF_CLASS:
350             case X86_64_SSEDF_CLASS:
351                 *pStructAlign++ = *reinterpret_cast<sal_uInt64 *>( *pSSE++ );
352                 break;
353         }
354 }
355 
356 #if 0
357 
358 /* Functions to load floats and double to an SSE register placeholder.  */
359 extern void float2sse (float, __int128_t *);
360 extern void double2sse (double, __int128_t *);
361 extern void floatfloat2sse (void *, __int128_t *);
362 
363 /* Functions to put the floats and doubles back.  */
364 extern float sse2float (__int128_t *);
365 extern double sse2double (__int128_t *);
366 extern void sse2floatfloat(__int128_t *, void *);
367 
368 /*@-exportheader@*/
369 void
370 ffi_prep_args (stackLayout *stack, extended_cif *ecif)
371 /*@=exportheader@*/
372 {
373   int gprcount, ssecount, i, g, s;
374   void **p_argv;
375   void *argp = &stack->argspace;
376   ffi_type **p_arg;
377 
378   /* First check if the return value should be passed in memory. If so,
379      pass the pointer as the first argument.  */
380   gprcount = ssecount = 0;
381   if (ecif->cif->rtype->type != FFI_TYPE_VOID
382       && examine_argument (ecif->cif->rtype, 1, &g, &s) == 0)
383     (void *)stack->gpr[gprcount++] = ecif->rvalue;
384 
385   for (i=ecif->cif->nargs, p_arg=ecif->cif->arg_types, p_argv = ecif->avalue;
386        i!=0; i--, p_arg++, p_argv++)
387     {
388       int in_register = 0;
389 
390       switch ((*p_arg)->type)
391 	{
392 	case FFI_TYPE_SINT8:
393 	case FFI_TYPE_SINT16:
394 	case FFI_TYPE_SINT32:
395 	case FFI_TYPE_SINT64:
396 	case FFI_TYPE_UINT8:
397 	case FFI_TYPE_UINT16:
398 	case FFI_TYPE_UINT32:
399 	case FFI_TYPE_UINT64:
400 	case FFI_TYPE_POINTER:
401 	  if (gprcount < MAX_GPR_REGS)
402 	    {
403 	      stack->gpr[gprcount] = 0;
404 	      stack->gpr[gprcount++] = *(long long *)(*p_argv);
405 	      in_register = 1;
406 	    }
407 	  break;
408 
409 	case FFI_TYPE_FLOAT:
410 	  if (ssecount < MAX_SSE_REGS)
411 	    {
412 	      float2sse (*(float *)(*p_argv), &stack->sse[ssecount++]);
413 	      in_register = 1;
414 	    }
415 	  break;
416 
417 	case FFI_TYPE_DOUBLE:
418 	  if (ssecount < MAX_SSE_REGS)
419 	    {
420 	      double2sse (*(double *)(*p_argv), &stack->sse[ssecount++]);
421 	      in_register = 1;
422 	    }
423 	  break;
424 	}
425 
426       if (in_register)
427 	continue;
428 
429       /* Either all places in registers where filled, or this is a
430 	 type that potentially goes into a memory slot.  */
431       if (examine_argument (*p_arg, 0, &g, &s) == 0
432 	  || gprcount + g > MAX_GPR_REGS || ssecount + s > MAX_SSE_REGS)
433 	{
434 	  /* Pass this argument in memory.  */
435 	  argp = (void *)ALIGN(argp, (*p_arg)->alignment);
436 	  memcpy (argp, *p_argv, (*p_arg)->size);
437 	  argp += (*p_arg)->size;
438 	}
439       else
440 	{
441 	  /* All easy cases are eliminated. Now fire the big guns.  */
442 
443 	  enum x86_64_reg_class classes[MAX_CLASSES];
444 	  int offset = 0, j, num;
445 	  void *a;
446 
447 	  num = classify_argument (*p_arg, classes, &offset);
448 	  for (j=0, a=*p_argv; j<num; j++, a+=8)
449 	    {
450 	      switch (classes[j])
451 		{
452 		case X86_64_INTEGER_CLASS:
453 		case X86_64_INTEGERSI_CLASS:
454 		  stack->gpr[gprcount++] = *(long long *)a;
455 		  break;
456 		case X86_64_SSE_CLASS:
457 		  floatfloat2sse (a, &stack->sse[ssecount++]);
458 		  break;
459 		case X86_64_SSESF_CLASS:
460 		  float2sse (*(float *)a, &stack->sse[ssecount++]);
461 		  break;
462 		case X86_64_SSEDF_CLASS:
463 		  double2sse (*(double *)a, &stack->sse[ssecount++]);
464 		  break;
465 		default:
466 		  abort();
467 		}
468 	    }
469 	}
470     }
471 }
472 
473 /* Perform machine dependent cif processing.  */
474 ffi_status
475 ffi_prep_cif_machdep (ffi_cif *cif)
476 {
477   int gprcount, ssecount, i, g, s;
478 
479   gprcount = ssecount = 0;
480 
481   /* Reset the byte count. We handle this size estimation here.  */
482   cif->bytes = 0;
483 
484   /* If the return value should be passed in memory, pass the pointer
485      as the first argument. The actual memory isn't allocated here.  */
486   if (cif->rtype->type != FFI_TYPE_VOID
487       && examine_argument (cif->rtype, 1, &g, &s) == 0)
488     gprcount = 1;
489 
490   /* Go over all arguments and determine the way they should be passed.
491      If it's in a register and there is space for it, let that be so. If
492      not, add it's size to the stack byte count.  */
493   for (i=0; i<cif->nargs; i++)
494     {
495       if (examine_argument (cif->arg_types[i], 0, &g, &s) == 0
496 	  || gprcount + g > MAX_GPR_REGS || ssecount + s > MAX_SSE_REGS)
497 	{
498 	  /* This is passed in memory. First align to the basic type.  */
499 	  cif->bytes = ALIGN(cif->bytes, cif->arg_types[i]->alignment);
500 
501 	  /* Stack arguments are *always* at least 8 byte aligned.  */
502 	  cif->bytes = ALIGN(cif->bytes, 8);
503 
504 	  /* Now add the size of this argument.  */
505 	  cif->bytes += cif->arg_types[i]->size;
506 	}
507       else
508 	{
509 	  gprcount += g;
510 	  ssecount += s;
511 	}
512     }
513 
514   /* Set the flag for the closures return.  */
515     switch (cif->rtype->type)
516     {
517     case FFI_TYPE_VOID:
518     case FFI_TYPE_STRUCT:
519     case FFI_TYPE_SINT64:
520     case FFI_TYPE_FLOAT:
521     case FFI_TYPE_DOUBLE:
522     case FFI_TYPE_LONGDOUBLE:
523       cif->flags = (unsigned) cif->rtype->type;
524       break;
525 
526     case FFI_TYPE_UINT64:
527       cif->flags = FFI_TYPE_SINT64;
528       break;
529 
530     default:
531       cif->flags = FFI_TYPE_INT;
532       break;
533     }
534 
535   return FFI_OK;
536 }
537 
538 typedef struct
539 {
540   long gpr[2];
541   __int128_t sse[2];
542   long double st0;
543 } return_value;
544 
545 //#endif
546 
547 void
548 ffi_fill_return_value (return_value *rv, extended_cif *ecif)
549 {
550     enum x86_64_reg_class classes[MAX_CLASSES];
551     int i = 0, num;
552     long *gpr = rv->gpr;
553     __int128_t *sse = rv->sse;
554     signed char sc;
555     signed short ss;
556 
557     /* This is needed because of the way x86-64 handles signed short
558        integers.  */
559     switch (ecif->cif->rtype->type)
560     {
561         case FFI_TYPE_SINT8:
562             sc = *(signed char *)gpr;
563             *(long long *)ecif->rvalue = (long long)sc;
564             return;
565         case FFI_TYPE_SINT16:
566             ss = *(signed short *)gpr;
567             *(long long *)ecif->rvalue = (long long)ss;
568             return;
569         default:
570             /* Just continue.  */
571             ;
572     }
573 
574     num = classify_argument (ecif->cif->rtype, classes, &i);
575 
576     if (num == 0)
577         /* Return in memory.  */
578         ecif->rvalue = (void *) rv->gpr[0];
579     else if (num == 2 && classes[0] == X86_64_X87_CLASS &&
580             classes[1] == X86_64_X87UP_CLASS)
581         /* This is a long double (this is easiest to handle this way instead
582            of an eightbyte at a time as in the loop below.  */
583         *((long double *)ecif->rvalue) = rv->st0;
584     else
585     {
586         void *a;
587 
588         for (i=0, a=ecif->rvalue; i<num; i++, a+=8)
589         {
590             switch (classes[i])
591             {
592                 case X86_64_INTEGER_CLASS:
593                 case X86_64_INTEGERSI_CLASS:
594                     *(long long *)a = *gpr;
595                     gpr++;
596                     break;
597                 case X86_64_SSE_CLASS:
598                     sse2floatfloat (sse++, a);
599                     break;
600                 case X86_64_SSESF_CLASS:
601                     *(float *)a = sse2float (sse++);
602                     break;
603                 case X86_64_SSEDF_CLASS:
604                     *(double *)a = sse2double (sse++);
605                     break;
606                 default:
607                     abort();
608             }
609         }
610     }
611 }
612 
613 //#if 0
614 
615 /*@-declundef@*/
616 /*@-exportheader@*/
617 extern void ffi_call_UNIX64(void (*)(stackLayout *, extended_cif *),
618 			    void (*) (return_value *, extended_cif *),
619 			    /*@out@*/ extended_cif *,
620 			    unsigned, /*@out@*/ unsigned *, void (*fn)());
621 /*@=declundef@*/
622 /*@=exportheader@*/
623 
624 void ffi_call(/*@dependent@*/ ffi_cif *cif,
625 	      void (*fn)(),
626 	      /*@out@*/ void *rvalue,
627 	      /*@dependent@*/ void **avalue)
628 {
629   extended_cif ecif;
630   int dummy;
631 
632   ecif.cif = cif;
633   ecif.avalue = avalue;
634 
635   /* If the return value is a struct and we don't have a return	*/
636   /* value address then we need to make one		        */
637 
638   if ((rvalue == NULL) &&
639       (examine_argument (cif->rtype, 1, &dummy, &dummy) == 0))
640     {
641       /*@-sysunrecog@*/
642       ecif.rvalue = alloca(cif->rtype->size);
643       /*@=sysunrecog@*/
644     }
645   else
646     ecif.rvalue = rvalue;
647 
648   /* Stack must always be 16byte aligned. Make it so.  */
649   cif->bytes = ALIGN(cif->bytes, 16);
650 
651   switch (cif->abi)
652     {
653     case FFI_SYSV:
654       /* Calling 32bit code from 64bit is not possible  */
655       FFI_ASSERT(0);
656       break;
657 
658     case FFI_UNIX64:
659       /*@-usedef@*/
660       ffi_call_UNIX64 (ffi_prep_args, ffi_fill_return_value, &ecif,
661 		       cif->bytes, ecif.rvalue, fn);
662       /*@=usedef@*/
663       break;
664 
665     default:
666       FFI_ASSERT(0);
667       break;
668     }
669 }
670 
671 extern void ffi_closure_UNIX64(void);
672 
673 ffi_status
674 ffi_prep_closure (ffi_closure* closure,
675 		  ffi_cif* cif,
676 		  void (*fun)(ffi_cif*, void*, void**, void*),
677 		  void *user_data)
678 {
679   volatile unsigned short *tramp;
680 
681   /* FFI_ASSERT (cif->abi == FFI_OSF);  */
682 
683   tramp = (volatile unsigned short *) &closure->tramp[0];
684   tramp[0] = 0xbb49;		/* mov <code>, %r11	*/
685   tramp[5] = 0xba49;		/* mov <data>, %r10	*/
686   tramp[10] = 0xff49;		/* jmp *%r11	*/
687   tramp[11] = 0x00e3;
688   *(void * volatile *) &tramp[1] = ffi_closure_UNIX64;
689   *(void * volatile *) &tramp[6] = closure;
690 
691   closure->cif = cif;
692   closure->fun = fun;
693   closure->user_data = user_data;
694 
695   return FFI_OK;
696 }
697 
698 int
699 ffi_closure_UNIX64_inner(ffi_closure *closure, va_list l, void *rp)
700 {
701   ffi_cif *cif;
702   void **avalue;
703   ffi_type **arg_types;
704   long i, avn, argn;
705 
706   cif = closure->cif;
707   avalue = alloca(cif->nargs * sizeof(void *));
708 
709   argn = 0;
710 
711   i = 0;
712   avn = cif->nargs;
713   arg_types = cif->arg_types;
714 
715   /* Grab the addresses of the arguments from the stack frame.  */
716   while (i < avn)
717     {
718       switch (arg_types[i]->type)
719 	{
720 	case FFI_TYPE_SINT8:
721 	case FFI_TYPE_UINT8:
722 	case FFI_TYPE_SINT16:
723 	case FFI_TYPE_UINT16:
724 	case FFI_TYPE_SINT32:
725 	case FFI_TYPE_UINT32:
726 	case FFI_TYPE_SINT64:
727 	case FFI_TYPE_UINT64:
728 	case FFI_TYPE_POINTER:
729 	  {
730 	    if (l->gp_offset > 48-8)
731 	      {
732 		avalue[i] = l->overflow_arg_area;
733 		l->overflow_arg_area = (char *)l->overflow_arg_area + 8;
734 	      }
735 	    else
736 	      {
737 		avalue[i] = (char *)l->reg_save_area + l->gp_offset;
738 		l->gp_offset += 8;
739 	      }
740 	  }
741 	  break;
742 
743 	case FFI_TYPE_STRUCT:
744 	  /* FIXME  */
745 	  FFI_ASSERT(0);
746 	  break;
747 
748 	case FFI_TYPE_DOUBLE:
749 	  {
750 	    if (l->fp_offset > 176-16)
751 	      {
752 		avalue[i] = l->overflow_arg_area;
753 		l->overflow_arg_area = (char *)l->overflow_arg_area + 8;
754 	      }
755 	    else
756 	      {
757 		avalue[i] = (char *)l->reg_save_area + l->fp_offset;
758 		l->fp_offset += 16;
759 	      }
760 	  }
761 #if DEBUG_FFI
762 	  fprintf (stderr, "double arg %d = %g\n", i, *(double *)avalue[i]);
763 #endif
764 	  break;
765 
766 	case FFI_TYPE_FLOAT:
767 	  {
768 	    if (l->fp_offset > 176-16)
769 	      {
770 		avalue[i] = l->overflow_arg_area;
771 		l->overflow_arg_area = (char *)l->overflow_arg_area + 8;
772 	      }
773 	    else
774 	      {
775 		avalue[i] = (char *)l->reg_save_area + l->fp_offset;
776 		l->fp_offset += 16;
777 	      }
778 	  }
779 #if DEBUG_FFI
780 	  fprintf (stderr, "float arg %d = %g\n", i, *(float *)avalue[i]);
781 #endif
782 	  break;
783 
784 	default:
785 	  FFI_ASSERT(0);
786 	}
787 
788       argn += ALIGN(arg_types[i]->size, SIZEOF_ARG) / SIZEOF_ARG;
789       i++;
790     }
791 
792   /* Invoke the closure.  */
793   (closure->fun) (cif, rp, avalue, closure->user_data);
794 
795   /* FIXME: Structs not supported.  */
796   FFI_ASSERT(cif->rtype->type != FFI_TYPE_STRUCT);
797 
798   /* Tell ffi_closure_UNIX64 how to perform return type promotions.  */
799 
800   return cif->rtype->type;
801 }
802 
803 #endif
804