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