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