• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ffi_align(ffi_type ** p_arg,char * argp)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 
ffi_put_arg(ffi_type ** arg_type,void ** arg,char * stack)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 */
ffi_prep_args_SYSV(char * stack,extended_cif * ecif,float * vfp_space)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 
ffi_prep_args_VFP(char * stack,extended_cif * ecif,float * vfp_space)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 */
ffi_prep_cif_machdep(ffi_cif * cif)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 */
ffi_prep_cif_machdep_var(ffi_cif * cif,unsigned int nfixedargs,unsigned int ntotalargs)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 
ffi_call(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue)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
ffi_closure_inner(ffi_closure * closure,void ** respp,void * args,void * vfp_args)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
ffi_prep_incoming_args_SYSV(char * stack,void ** rvalue,void ** avalue,ffi_cif * cif,float * vfp_stack)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
ffi_prep_incoming_args_VFP(char * stack,void ** rvalue,void ** avalue,ffi_cif * cif,float * vfp_stack)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 *
ffi_trampoline_table_alloc()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 *
ffi_closure_alloc(size_t size,void ** code)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
ffi_closure_free(void * ptr)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
ffi_prep_closure_loc(ffi_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * codeloc)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 
rec_vfp_type_p(ffi_type * t,int * elt,int * elnum)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 
vfp_type_p(ffi_type * t)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 
place_vfp_arg(ffi_cif * cif,ffi_type * t)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 
layout_vfp_args(ffi_cif * cif)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