1 /* ----------------------------------------------------------------------- 2 ffi.c - Copyright (c) 2011 Timothy Wall 3 Copyright (c) 2011 Plausible Labs Cooperative, Inc. 4 Copyright (c) 2011 Anthony Green 5 Copyright (c) 2011 Free Software Foundation 6 Copyright (c) 1998, 2008, 2011 Red Hat, Inc. 7 8 ARM Foreign Function Interface 9 10 Permission is hereby granted, free of charge, to any person obtaining 11 a copy of this software and associated documentation files (the 12 ``Software''), to deal in the Software without restriction, including 13 without limitation the rights to use, copy, modify, merge, publish, 14 distribute, sublicense, and/or sell copies of the Software, and to 15 permit persons to whom the Software is furnished to do so, subject to 16 the following conditions: 17 18 The above copyright notice and this permission notice shall be included 19 in all copies or substantial portions of the Software. 20 21 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, 22 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 25 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 26 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 28 DEALINGS IN THE SOFTWARE. 29 ----------------------------------------------------------------------- */ 30 31 #include <ffi.h> 32 #include <ffi_common.h> 33 34 #include <stdlib.h> 35 36 /* Forward declares. */ 37 static int vfp_type_p (ffi_type *); 38 static void layout_vfp_args (ffi_cif *); 39 40 int ffi_prep_args_SYSV(char *stack, extended_cif *ecif, float *vfp_space); 41 int ffi_prep_args_VFP(char *stack, extended_cif *ecif, float *vfp_space); 42 43 static char* ffi_align(ffi_type **p_arg, char *argp) 44 { 45 /* Align if necessary */ 46 register size_t alignment = (*p_arg)->alignment; 47 if (alignment < 4) 48 { 49 alignment = 4; 50 } 51 #ifdef _WIN32_WCE 52 if (alignment > 4) 53 { 54 alignment = 4; 55 } 56 #endif 57 if ((alignment - 1) & (unsigned) argp) 58 { 59 argp = (char *) ALIGN(argp, alignment); 60 } 61 62 if ((*p_arg)->type == FFI_TYPE_STRUCT) 63 { 64 argp = (char *) ALIGN(argp, 4); 65 } 66 return argp; 67 } 68 69 static size_t ffi_put_arg(ffi_type **arg_type, void **arg, char *stack) 70 { 71 register char* argp = stack; 72 register ffi_type **p_arg = arg_type; 73 register void **p_argv = arg; 74 register size_t z = (*p_arg)->size; 75 if (z < sizeof(int)) 76 { 77 z = sizeof(int); 78 switch ((*p_arg)->type) 79 { 80 case FFI_TYPE_SINT8: 81 *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv); 82 break; 83 84 case FFI_TYPE_UINT8: 85 *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv); 86 break; 87 88 case FFI_TYPE_SINT16: 89 *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv); 90 break; 91 92 case FFI_TYPE_UINT16: 93 *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv); 94 break; 95 96 case FFI_TYPE_STRUCT: 97 memcpy(argp, *p_argv, (*p_arg)->size); 98 break; 99 100 default: 101 FFI_ASSERT(0); 102 } 103 } 104 else if (z == sizeof(int)) 105 { 106 if ((*p_arg)->type == FFI_TYPE_FLOAT) 107 *(float *) argp = *(float *)(* p_argv); 108 else 109 *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); 110 } 111 else if (z == sizeof(double) && (*p_arg)->type == FFI_TYPE_DOUBLE) 112 { 113 *(double *) argp = *(double *)(* p_argv); 114 } 115 else 116 { 117 memcpy(argp, *p_argv, z); 118 } 119 return z; 120 } 121 /* ffi_prep_args is called by the assembly routine once stack space 122 has been allocated for the function's arguments 123 124 The vfp_space parameter is the load area for VFP regs, the return 125 value is cif->vfp_used (word bitset of VFP regs used for passing 126 arguments). These are only used for the VFP hard-float ABI. 127 */ 128 int ffi_prep_args_SYSV(char *stack, extended_cif *ecif, float *vfp_space) 129 { 130 register unsigned int i; 131 register void **p_argv; 132 register char *argp; 133 register ffi_type **p_arg; 134 argp = stack; 135 136 137 if ( ecif->cif->flags == FFI_TYPE_STRUCT ) { 138 *(void **) argp = ecif->rvalue; 139 argp += 4; 140 } 141 142 p_argv = ecif->avalue; 143 144 for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; 145 (i != 0); 146 i--, p_arg++, p_argv++) 147 { 148 argp = ffi_align(p_arg, argp); 149 argp += ffi_put_arg(p_arg, p_argv, argp); 150 } 151 152 return 0; 153 } 154 155 int ffi_prep_args_VFP(char *stack, extended_cif *ecif, float *vfp_space) 156 { 157 register unsigned int i, vi = 0; 158 register void **p_argv; 159 register char *argp, *regp, *eo_regp; 160 register ffi_type **p_arg; 161 char stack_used = 0; 162 char done_with_regs = 0; 163 char is_vfp_type; 164 165 // make sure we are using FFI_VFP 166 FFI_ASSERT(ecif->cif->abi == FFI_VFP); 167 168 /* the first 4 words on the stack are used for values passed in core 169 * registers. */ 170 regp = stack; 171 eo_regp = argp = regp + 16; 172 173 174 /* if the function returns an FFI_TYPE_STRUCT in memory, that address is 175 * passed in r0 to the function */ 176 if ( ecif->cif->flags == FFI_TYPE_STRUCT ) { 177 *(void **) regp = ecif->rvalue; 178 regp += 4; 179 } 180 181 p_argv = ecif->avalue; 182 183 for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; 184 (i != 0); 185 i--, p_arg++, p_argv++) 186 { 187 is_vfp_type = vfp_type_p (*p_arg); 188 189 /* Allocated in VFP registers. */ 190 if(vi < ecif->cif->vfp_nargs && is_vfp_type) 191 { 192 char *vfp_slot = (char *)(vfp_space + ecif->cif->vfp_args[vi++]); 193 ffi_put_arg(p_arg, p_argv, vfp_slot); 194 continue; 195 } 196 /* Try allocating in core registers. */ 197 else if (!done_with_regs && !is_vfp_type) 198 { 199 char *tregp = ffi_align(p_arg, regp); 200 size_t size = (*p_arg)->size; 201 size = (size < 4)? 4 : size; // pad 202 /* Check if there is space left in the aligned register area to place 203 * the argument */ 204 if(tregp + size <= eo_regp) 205 { 206 regp = tregp + ffi_put_arg(p_arg, p_argv, tregp); 207 done_with_regs = (regp == argp); 208 // ensure we did not write into the stack area 209 FFI_ASSERT(regp <= argp); 210 continue; 211 } 212 /* In case there are no arguments in the stack area yet, 213 the argument is passed in the remaining core registers and on the 214 stack. */ 215 else if (!stack_used) 216 { 217 stack_used = 1; 218 done_with_regs = 1; 219 argp = tregp + ffi_put_arg(p_arg, p_argv, tregp); 220 FFI_ASSERT(eo_regp < argp); 221 continue; 222 } 223 } 224 /* Base case, arguments are passed on the stack */ 225 stack_used = 1; 226 argp = ffi_align(p_arg, argp); 227 argp += ffi_put_arg(p_arg, p_argv, argp); 228 } 229 /* Indicate the VFP registers used. */ 230 return ecif->cif->vfp_used; 231 } 232 233 /* Perform machine dependent cif processing */ 234 ffi_status ffi_prep_cif_machdep(ffi_cif *cif) 235 { 236 int type_code; 237 /* Round the stack up to a multiple of 8 bytes. This isn't needed 238 everywhere, but it is on some platforms, and it doesn't harm anything 239 when it isn't needed. */ 240 cif->bytes = (cif->bytes + 7) & ~7; 241 242 /* Set the return type flag */ 243 switch (cif->rtype->type) 244 { 245 case FFI_TYPE_VOID: 246 case FFI_TYPE_FLOAT: 247 case FFI_TYPE_DOUBLE: 248 cif->flags = (unsigned) cif->rtype->type; 249 break; 250 251 case FFI_TYPE_SINT64: 252 case FFI_TYPE_UINT64: 253 cif->flags = (unsigned) FFI_TYPE_SINT64; 254 break; 255 256 case FFI_TYPE_STRUCT: 257 if (cif->abi == FFI_VFP 258 && (type_code = vfp_type_p (cif->rtype)) != 0) 259 { 260 /* A Composite Type passed in VFP registers, either 261 FFI_TYPE_STRUCT_VFP_FLOAT or FFI_TYPE_STRUCT_VFP_DOUBLE. */ 262 cif->flags = (unsigned) type_code; 263 } 264 else if (cif->rtype->size <= 4) 265 /* A Composite Type not larger than 4 bytes is returned in r0. */ 266 cif->flags = (unsigned)FFI_TYPE_INT; 267 else 268 /* A Composite Type larger than 4 bytes, or whose size cannot 269 be determined statically ... is stored in memory at an 270 address passed [in r0]. */ 271 cif->flags = (unsigned)FFI_TYPE_STRUCT; 272 break; 273 274 default: 275 cif->flags = FFI_TYPE_INT; 276 break; 277 } 278 279 /* Map out the register placements of VFP register args. 280 The VFP hard-float calling conventions are slightly more sophisticated than 281 the base calling conventions, so we do it here instead of in ffi_prep_args(). */ 282 if (cif->abi == FFI_VFP) 283 layout_vfp_args (cif); 284 285 return FFI_OK; 286 } 287 288 /* Perform machine dependent cif processing for variadic calls */ 289 ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif, 290 unsigned int nfixedargs, 291 unsigned int ntotalargs) 292 { 293 /* VFP variadic calls actually use the SYSV ABI */ 294 if (cif->abi == FFI_VFP) 295 cif->abi = FFI_SYSV; 296 297 return ffi_prep_cif_machdep(cif); 298 } 299 300 /* Prototypes for assembly functions, in sysv.S */ 301 extern void ffi_call_SYSV (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *); 302 extern void ffi_call_VFP (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *); 303 304 void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) 305 { 306 extended_cif ecif; 307 308 int small_struct = (cif->flags == FFI_TYPE_INT 309 && cif->rtype->type == FFI_TYPE_STRUCT); 310 int vfp_struct = (cif->flags == FFI_TYPE_STRUCT_VFP_FLOAT 311 || cif->flags == FFI_TYPE_STRUCT_VFP_DOUBLE); 312 313 unsigned int temp; 314 315 ecif.cif = cif; 316 ecif.avalue = avalue; 317 318 /* If the return value is a struct and we don't have a return */ 319 /* value address then we need to make one */ 320 321 if ((rvalue == NULL) && 322 (cif->flags == FFI_TYPE_STRUCT)) 323 { 324 ecif.rvalue = alloca(cif->rtype->size); 325 } 326 else if (small_struct) 327 ecif.rvalue = &temp; 328 else if (vfp_struct) 329 { 330 /* Largest case is double x 4. */ 331 ecif.rvalue = alloca(32); 332 } 333 else 334 ecif.rvalue = rvalue; 335 336 switch (cif->abi) 337 { 338 case FFI_SYSV: 339 ffi_call_SYSV (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue); 340 break; 341 342 case FFI_VFP: 343 #ifdef __ARM_EABI__ 344 ffi_call_VFP (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue); 345 break; 346 #endif 347 348 default: 349 FFI_ASSERT(0); 350 break; 351 } 352 if (small_struct) 353 { 354 FFI_ASSERT(rvalue != NULL); 355 memcpy (rvalue, &temp, cif->rtype->size); 356 } 357 358 else if (vfp_struct) 359 { 360 FFI_ASSERT(rvalue != NULL); 361 memcpy (rvalue, ecif.rvalue, cif->rtype->size); 362 } 363 364 } 365 366 /** private members **/ 367 368 static void ffi_prep_incoming_args_SYSV (char *stack, void **ret, 369 void** args, ffi_cif* cif, float *vfp_stack); 370 371 static void ffi_prep_incoming_args_VFP (char *stack, void **ret, 372 void** args, ffi_cif* cif, float *vfp_stack); 373 374 void ffi_closure_SYSV (ffi_closure *); 375 376 void ffi_closure_VFP (ffi_closure *); 377 378 /* This function is jumped to by the trampoline */ 379 380 unsigned int FFI_HIDDEN 381 ffi_closure_inner (ffi_closure *closure, 382 void **respp, void *args, void *vfp_args) 383 { 384 // our various things... 385 ffi_cif *cif; 386 void **arg_area; 387 388 cif = closure->cif; 389 arg_area = (void**) alloca (cif->nargs * sizeof (void*)); 390 391 /* this call will initialize ARG_AREA, such that each 392 * element in that array points to the corresponding 393 * value on the stack; and if the function returns 394 * a structure, it will re-set RESP to point to the 395 * structure return address. */ 396 if (cif->abi == FFI_VFP) 397 ffi_prep_incoming_args_VFP(args, respp, arg_area, cif, vfp_args); 398 else 399 ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif, vfp_args); 400 401 (closure->fun) (cif, *respp, arg_area, closure->user_data); 402 403 return cif->flags; 404 } 405 406 /*@-exportheader@*/ 407 static void 408 ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, 409 void **avalue, ffi_cif *cif, 410 /* Used only under VFP hard-float ABI. */ 411 float *vfp_stack) 412 /*@=exportheader@*/ 413 { 414 register unsigned int i; 415 register void **p_argv; 416 register char *argp; 417 register ffi_type **p_arg; 418 419 argp = stack; 420 421 if ( cif->flags == FFI_TYPE_STRUCT ) { 422 *rvalue = *(void **) argp; 423 argp += 4; 424 } 425 426 p_argv = avalue; 427 428 for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) 429 { 430 size_t z; 431 432 argp = ffi_align(p_arg, argp); 433 434 z = (*p_arg)->size; 435 436 /* because we're little endian, this is what it turns into. */ 437 438 *p_argv = (void*) argp; 439 440 p_argv++; 441 argp += z; 442 } 443 444 return; 445 } 446 447 /*@-exportheader@*/ 448 static void 449 ffi_prep_incoming_args_VFP(char *stack, void **rvalue, 450 void **avalue, ffi_cif *cif, 451 /* Used only under VFP hard-float ABI. */ 452 float *vfp_stack) 453 /*@=exportheader@*/ 454 { 455 register unsigned int i, vi = 0; 456 register void **p_argv; 457 register char *argp, *regp, *eo_regp; 458 register ffi_type **p_arg; 459 char done_with_regs = 0; 460 char stack_used = 0; 461 char is_vfp_type; 462 463 FFI_ASSERT(cif->abi == FFI_VFP); 464 regp = stack; 465 eo_regp = argp = regp + 16; 466 467 if ( cif->flags == FFI_TYPE_STRUCT ) { 468 *rvalue = *(void **) regp; 469 regp += 4; 470 } 471 472 p_argv = avalue; 473 474 for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) 475 { 476 size_t z; 477 is_vfp_type = vfp_type_p (*p_arg); 478 479 if(vi < cif->vfp_nargs && is_vfp_type) 480 { 481 *p_argv++ = (void*)(vfp_stack + cif->vfp_args[vi++]); 482 continue; 483 } 484 else if (!done_with_regs && !is_vfp_type) 485 { 486 char* tregp = ffi_align(p_arg, regp); 487 488 z = (*p_arg)->size; 489 z = (z < 4)? 4 : z; // pad 490 491 /* if the arguments either fits into the registers or uses registers 492 * and stack, while we haven't read other things from the stack */ 493 if(tregp + z <= eo_regp || !stack_used) 494 { 495 /* because we're little endian, this is what it turns into. */ 496 *p_argv = (void*) tregp; 497 498 p_argv++; 499 regp = tregp + z; 500 // if we read past the last core register, make sure we have not read 501 // from the stack before and continue reading after regp 502 if(regp > eo_regp) 503 { 504 if(stack_used) 505 { 506 abort(); // we should never read past the end of the register 507 // are if the stack is already in use 508 } 509 argp = regp; 510 } 511 if(regp >= eo_regp) 512 { 513 done_with_regs = 1; 514 stack_used = 1; 515 } 516 continue; 517 } 518 } 519 stack_used = 1; 520 521 argp = ffi_align(p_arg, argp); 522 523 z = (*p_arg)->size; 524 525 /* because we're little endian, this is what it turns into. */ 526 527 *p_argv = (void*) argp; 528 529 p_argv++; 530 argp += z; 531 } 532 533 return; 534 } 535 536 /* How to make a trampoline. */ 537 538 extern unsigned int ffi_arm_trampoline[3]; 539 540 #if FFI_EXEC_TRAMPOLINE_TABLE 541 542 #include <mach/mach.h> 543 #include <pthread.h> 544 #include <stdio.h> 545 #include <stdlib.h> 546 547 extern void *ffi_closure_trampoline_table_page; 548 549 typedef struct ffi_trampoline_table ffi_trampoline_table; 550 typedef struct ffi_trampoline_table_entry ffi_trampoline_table_entry; 551 552 struct ffi_trampoline_table { 553 /* contiguous writable and executable pages */ 554 vm_address_t config_page; 555 vm_address_t trampoline_page; 556 557 /* free list tracking */ 558 uint16_t free_count; 559 ffi_trampoline_table_entry *free_list; 560 ffi_trampoline_table_entry *free_list_pool; 561 562 ffi_trampoline_table *prev; 563 ffi_trampoline_table *next; 564 }; 565 566 struct ffi_trampoline_table_entry { 567 void *(*trampoline)(); 568 ffi_trampoline_table_entry *next; 569 }; 570 571 /* Override the standard architecture trampoline size */ 572 // XXX TODO - Fix 573 #undef FFI_TRAMPOLINE_SIZE 574 #define FFI_TRAMPOLINE_SIZE 12 575 576 /* The trampoline configuration is placed at 4080 bytes prior to the trampoline's entry point */ 577 #define FFI_TRAMPOLINE_CODELOC_CONFIG(codeloc) ((void **) (((uint8_t *) codeloc) - 4080)); 578 579 /* The first 16 bytes of the config page are unused, as they are unaddressable from the trampoline page. */ 580 #define FFI_TRAMPOLINE_CONFIG_PAGE_OFFSET 16 581 582 /* Total number of trampolines that fit in one trampoline table */ 583 #define FFI_TRAMPOLINE_COUNT ((PAGE_SIZE - FFI_TRAMPOLINE_CONFIG_PAGE_OFFSET) / FFI_TRAMPOLINE_SIZE) 584 585 static pthread_mutex_t ffi_trampoline_lock = PTHREAD_MUTEX_INITIALIZER; 586 static ffi_trampoline_table *ffi_trampoline_tables = NULL; 587 588 static ffi_trampoline_table * 589 ffi_trampoline_table_alloc () 590 { 591 ffi_trampoline_table *table = NULL; 592 593 /* Loop until we can allocate two contiguous pages */ 594 while (table == NULL) { 595 vm_address_t config_page = 0x0; 596 kern_return_t kt; 597 598 /* Try to allocate two pages */ 599 kt = vm_allocate (mach_task_self (), &config_page, PAGE_SIZE*2, VM_FLAGS_ANYWHERE); 600 if (kt != KERN_SUCCESS) { 601 fprintf(stderr, "vm_allocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__); 602 break; 603 } 604 605 /* Now drop the second half of the allocation to make room for the trampoline table */ 606 vm_address_t trampoline_page = config_page+PAGE_SIZE; 607 kt = vm_deallocate (mach_task_self (), trampoline_page, PAGE_SIZE); 608 if (kt != KERN_SUCCESS) { 609 fprintf(stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__); 610 break; 611 } 612 613 /* Remap the trampoline table to directly follow the config page */ 614 vm_prot_t cur_prot; 615 vm_prot_t max_prot; 616 617 kt = vm_remap (mach_task_self (), &trampoline_page, PAGE_SIZE, 0x0, FALSE, mach_task_self (), (vm_address_t) &ffi_closure_trampoline_table_page, FALSE, &cur_prot, &max_prot, VM_INHERIT_SHARE); 618 619 /* If we lost access to the destination trampoline page, drop our config allocation mapping and retry */ 620 if (kt != KERN_SUCCESS) { 621 /* Log unexpected failures */ 622 if (kt != KERN_NO_SPACE) { 623 fprintf(stderr, "vm_remap() failure: %d at %s:%d\n", kt, __FILE__, __LINE__); 624 } 625 626 vm_deallocate (mach_task_self (), config_page, PAGE_SIZE); 627 continue; 628 } 629 630 /* We have valid trampoline and config pages */ 631 table = calloc (1, sizeof(ffi_trampoline_table)); 632 table->free_count = FFI_TRAMPOLINE_COUNT; 633 table->config_page = config_page; 634 table->trampoline_page = trampoline_page; 635 636 /* Create and initialize the free list */ 637 table->free_list_pool = calloc(FFI_TRAMPOLINE_COUNT, sizeof(ffi_trampoline_table_entry)); 638 639 uint16_t i; 640 for (i = 0; i < table->free_count; i++) { 641 ffi_trampoline_table_entry *entry = &table->free_list_pool[i]; 642 entry->trampoline = (void *) (table->trampoline_page + (i * FFI_TRAMPOLINE_SIZE)); 643 644 if (i < table->free_count - 1) 645 entry->next = &table->free_list_pool[i+1]; 646 } 647 648 table->free_list = table->free_list_pool; 649 } 650 651 return table; 652 } 653 654 void * 655 ffi_closure_alloc (size_t size, void **code) 656 { 657 /* Create the closure */ 658 ffi_closure *closure = malloc(size); 659 if (closure == NULL) 660 return NULL; 661 662 pthread_mutex_lock(&ffi_trampoline_lock); 663 664 /* Check for an active trampoline table with available entries. */ 665 ffi_trampoline_table *table = ffi_trampoline_tables; 666 if (table == NULL || table->free_list == NULL) { 667 table = ffi_trampoline_table_alloc (); 668 if (table == NULL) { 669 free(closure); 670 return NULL; 671 } 672 673 /* Insert the new table at the top of the list */ 674 table->next = ffi_trampoline_tables; 675 if (table->next != NULL) 676 table->next->prev = table; 677 678 ffi_trampoline_tables = table; 679 } 680 681 /* Claim the free entry */ 682 ffi_trampoline_table_entry *entry = ffi_trampoline_tables->free_list; 683 ffi_trampoline_tables->free_list = entry->next; 684 ffi_trampoline_tables->free_count--; 685 entry->next = NULL; 686 687 pthread_mutex_unlock(&ffi_trampoline_lock); 688 689 /* Initialize the return values */ 690 *code = entry->trampoline; 691 closure->trampoline_table = table; 692 closure->trampoline_table_entry = entry; 693 694 return closure; 695 } 696 697 void 698 ffi_closure_free (void *ptr) 699 { 700 ffi_closure *closure = ptr; 701 702 pthread_mutex_lock(&ffi_trampoline_lock); 703 704 /* Fetch the table and entry references */ 705 ffi_trampoline_table *table = closure->trampoline_table; 706 ffi_trampoline_table_entry *entry = closure->trampoline_table_entry; 707 708 /* Return the entry to the free list */ 709 entry->next = table->free_list; 710 table->free_list = entry; 711 table->free_count++; 712 713 /* If all trampolines within this table are free, and at least one other table exists, deallocate 714 * the table */ 715 if (table->free_count == FFI_TRAMPOLINE_COUNT && ffi_trampoline_tables != table) { 716 /* Remove from the list */ 717 if (table->prev != NULL) 718 table->prev->next = table->next; 719 720 if (table->next != NULL) 721 table->next->prev = table->prev; 722 723 /* Deallocate pages */ 724 kern_return_t kt; 725 kt = vm_deallocate (mach_task_self (), table->config_page, PAGE_SIZE); 726 if (kt != KERN_SUCCESS) 727 fprintf(stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__); 728 729 kt = vm_deallocate (mach_task_self (), table->trampoline_page, PAGE_SIZE); 730 if (kt != KERN_SUCCESS) 731 fprintf(stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__); 732 733 /* Deallocate free list */ 734 free (table->free_list_pool); 735 free (table); 736 } else if (ffi_trampoline_tables != table) { 737 /* Otherwise, bump this table to the top of the list */ 738 table->prev = NULL; 739 table->next = ffi_trampoline_tables; 740 if (ffi_trampoline_tables != NULL) 741 ffi_trampoline_tables->prev = table; 742 743 ffi_trampoline_tables = table; 744 } 745 746 pthread_mutex_unlock (&ffi_trampoline_lock); 747 748 /* Free the closure */ 749 free (closure); 750 } 751 752 #else 753 754 #define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \ 755 ({ unsigned char *__tramp = (unsigned char*)(TRAMP); \ 756 unsigned int __fun = (unsigned int)(FUN); \ 757 unsigned int __ctx = (unsigned int)(CTX); \ 758 unsigned char *insns = (unsigned char *)(CTX); \ 759 memcpy (__tramp, ffi_arm_trampoline, sizeof ffi_arm_trampoline); \ 760 *(unsigned int*) &__tramp[12] = __ctx; \ 761 *(unsigned int*) &__tramp[16] = __fun; \ 762 __clear_cache((&__tramp[0]), (&__tramp[19])); /* Clear data mapping. */ \ 763 __clear_cache(insns, insns + 3 * sizeof (unsigned int)); \ 764 /* Clear instruction \ 765 mapping. */ \ 766 }) 767 768 #endif 769 770 /* the cif must already be prep'ed */ 771 772 ffi_status 773 ffi_prep_closure_loc (ffi_closure* closure, 774 ffi_cif* cif, 775 void (*fun)(ffi_cif*,void*,void**,void*), 776 void *user_data, 777 void *codeloc) 778 { 779 void (*closure_func)(ffi_closure*) = NULL; 780 781 if (cif->abi == FFI_SYSV) 782 closure_func = &ffi_closure_SYSV; 783 #ifdef __ARM_EABI__ 784 else if (cif->abi == FFI_VFP) 785 closure_func = &ffi_closure_VFP; 786 #endif 787 else 788 return FFI_BAD_ABI; 789 790 #if FFI_EXEC_TRAMPOLINE_TABLE 791 void **config = FFI_TRAMPOLINE_CODELOC_CONFIG(codeloc); 792 config[0] = closure; 793 config[1] = closure_func; 794 #else 795 FFI_INIT_TRAMPOLINE (&closure->tramp[0], \ 796 closure_func, \ 797 codeloc); 798 #endif 799 800 closure->cif = cif; 801 closure->user_data = user_data; 802 closure->fun = fun; 803 804 return FFI_OK; 805 } 806 807 /* Below are routines for VFP hard-float support. */ 808 809 static int rec_vfp_type_p (ffi_type *t, int *elt, int *elnum) 810 { 811 switch (t->type) 812 { 813 case FFI_TYPE_FLOAT: 814 case FFI_TYPE_DOUBLE: 815 *elt = (int) t->type; 816 *elnum = 1; 817 return 1; 818 819 case FFI_TYPE_STRUCT_VFP_FLOAT: 820 *elt = FFI_TYPE_FLOAT; 821 *elnum = t->size / sizeof (float); 822 return 1; 823 824 case FFI_TYPE_STRUCT_VFP_DOUBLE: 825 *elt = FFI_TYPE_DOUBLE; 826 *elnum = t->size / sizeof (double); 827 return 1; 828 829 case FFI_TYPE_STRUCT:; 830 { 831 int base_elt = 0, total_elnum = 0; 832 ffi_type **el = t->elements; 833 while (*el) 834 { 835 int el_elt = 0, el_elnum = 0; 836 if (! rec_vfp_type_p (*el, &el_elt, &el_elnum) 837 || (base_elt && base_elt != el_elt) 838 || total_elnum + el_elnum > 4) 839 return 0; 840 base_elt = el_elt; 841 total_elnum += el_elnum; 842 el++; 843 } 844 *elnum = total_elnum; 845 *elt = base_elt; 846 return 1; 847 } 848 default: ; 849 } 850 return 0; 851 } 852 853 static int vfp_type_p (ffi_type *t) 854 { 855 int elt, elnum; 856 if (rec_vfp_type_p (t, &elt, &elnum)) 857 { 858 if (t->type == FFI_TYPE_STRUCT) 859 { 860 if (elnum == 1) 861 t->type = elt; 862 else 863 t->type = (elt == FFI_TYPE_FLOAT 864 ? FFI_TYPE_STRUCT_VFP_FLOAT 865 : FFI_TYPE_STRUCT_VFP_DOUBLE); 866 } 867 return (int) t->type; 868 } 869 return 0; 870 } 871 872 static int place_vfp_arg (ffi_cif *cif, ffi_type *t) 873 { 874 short reg = cif->vfp_reg_free; 875 int nregs = t->size / sizeof (float); 876 int align = ((t->type == FFI_TYPE_STRUCT_VFP_FLOAT 877 || t->type == FFI_TYPE_FLOAT) ? 1 : 2); 878 /* Align register number. */ 879 if ((reg & 1) && align == 2) 880 reg++; 881 while (reg + nregs <= 16) 882 { 883 int s, new_used = 0; 884 for (s = reg; s < reg + nregs; s++) 885 { 886 new_used |= (1 << s); 887 if (cif->vfp_used & (1 << s)) 888 { 889 reg += align; 890 goto next_reg; 891 } 892 } 893 /* Found regs to allocate. */ 894 cif->vfp_used |= new_used; 895 cif->vfp_args[cif->vfp_nargs++] = reg; 896 897 /* Update vfp_reg_free. */ 898 if (cif->vfp_used & (1 << cif->vfp_reg_free)) 899 { 900 reg += nregs; 901 while (cif->vfp_used & (1 << reg)) 902 reg += 1; 903 cif->vfp_reg_free = reg; 904 } 905 return 0; 906 next_reg: ; 907 } 908 // done, mark all regs as used 909 cif->vfp_reg_free = 16; 910 cif->vfp_used = 0xFFFF; 911 return 1; 912 } 913 914 static void layout_vfp_args (ffi_cif *cif) 915 { 916 int i; 917 /* Init VFP fields */ 918 cif->vfp_used = 0; 919 cif->vfp_nargs = 0; 920 cif->vfp_reg_free = 0; 921 memset (cif->vfp_args, -1, 16); /* Init to -1. */ 922 923 for (i = 0; i < cif->nargs; i++) 924 { 925 ffi_type *t = cif->arg_types[i]; 926 if (vfp_type_p (t) && place_vfp_arg (cif, t) == 1) 927 { 928 break; 929 } 930 } 931 } 932