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 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 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. */ 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 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 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