Ruby  2.7.0p0(2019-12-25revision647ee6f091eafcce70ffb75ddf7e121e192ab217)
ffi_linux64.c
Go to the documentation of this file.
1 /* -----------------------------------------------------------------------
2  ffi_linux64.c - Copyright (C) 2013 IBM
3  Copyright (C) 2011 Anthony Green
4  Copyright (C) 2011 Kyle Moffett
5  Copyright (C) 2008 Red Hat, Inc
6  Copyright (C) 2007, 2008 Free Software Foundation, Inc
7  Copyright (c) 1998 Geoffrey Keating
8 
9  PowerPC Foreign Function Interface
10 
11  Permission is hereby granted, free of charge, to any person obtaining
12  a copy of this software and associated documentation files (the
13  ``Software''), to deal in the Software without restriction, including
14  without limitation the rights to use, copy, modify, merge, publish,
15  distribute, sublicense, and/or sell copies of the Software, and to
16  permit persons to whom the Software is furnished to do so, subject to
17  the following conditions:
18 
19  The above copyright notice and this permission notice shall be included
20  in all copies or substantial portions of the Software.
21 
22  THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
23  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
26  OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
27  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28  OTHER DEALINGS IN THE SOFTWARE.
29  ----------------------------------------------------------------------- */
30 
31 #include "ffi.h"
32 
33 #ifdef POWERPC64
34 #include "ffi_common.h"
35 #include "ffi_powerpc.h"
36 
37 
38 /* About the LINUX64 ABI. */
39 enum {
40  NUM_GPR_ARG_REGISTERS64 = 8,
41  NUM_FPR_ARG_REGISTERS64 = 13
42 };
43 enum { ASM_NEEDS_REGISTERS64 = 4 };
44 
45 
46 #if HAVE_LONG_DOUBLE_VARIANT && FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
47 /* Adjust size of ffi_type_longdouble. */
48 void FFI_HIDDEN
50 {
51  if ((abi & (FFI_LINUX | FFI_LINUX_LONG_DOUBLE_128)) == FFI_LINUX)
52  {
53  ffi_type_longdouble.size = 8;
54  ffi_type_longdouble.alignment = 8;
55  }
56  else
57  {
58  ffi_type_longdouble.size = 16;
59  ffi_type_longdouble.alignment = 16;
60  }
61 }
62 #endif
63 
64 
65 #if _CALL_ELF == 2
66 static unsigned int
67 discover_homogeneous_aggregate (const ffi_type *t, unsigned int *elnum)
68 {
69  switch (t->type)
70  {
71  case FFI_TYPE_FLOAT:
72  case FFI_TYPE_DOUBLE:
73  *elnum = 1;
74  return (int) t->type;
75 
76  case FFI_TYPE_STRUCT:;
77  {
78  unsigned int base_elt = 0, total_elnum = 0;
79  ffi_type **el = t->elements;
80  while (*el)
81  {
82  unsigned int el_elt, el_elnum = 0;
83  el_elt = discover_homogeneous_aggregate (*el, &el_elnum);
84  if (el_elt == 0
85  || (base_elt && base_elt != el_elt))
86  return 0;
87  base_elt = el_elt;
88  total_elnum += el_elnum;
89  if (total_elnum > 8)
90  return 0;
91  el++;
92  }
93  *elnum = total_elnum;
94  return base_elt;
95  }
96 
97  default:
98  return 0;
99  }
100 }
101 #endif
102 
103 
104 /* Perform machine dependent cif processing */
105 static ffi_status
106 ffi_prep_cif_linux64_core (ffi_cif *cif)
107 {
108  ffi_type **ptr;
109  unsigned bytes;
110  unsigned i, fparg_count = 0, intarg_count = 0;
111  unsigned flags = cif->flags;
112 #if _CALL_ELF == 2
113  unsigned int elt, elnum;
114 #endif
115 
116 #if FFI_TYPE_LONGDOUBLE == FFI_TYPE_DOUBLE
117  /* If compiled without long double support.. */
118  if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
119  return FFI_BAD_ABI;
120 #endif
121 
122  /* The machine-independent calculation of cif->bytes doesn't work
123  for us. Redo the calculation. */
124 #if _CALL_ELF == 2
125  /* Space for backchain, CR, LR, TOC and the asm's temp regs. */
126  bytes = (4 + ASM_NEEDS_REGISTERS64) * sizeof (long);
127 
128  /* Space for the general registers. */
129  bytes += NUM_GPR_ARG_REGISTERS64 * sizeof (long);
130 #else
131  /* Space for backchain, CR, LR, cc/ld doubleword, TOC and the asm's temp
132  regs. */
133  bytes = (6 + ASM_NEEDS_REGISTERS64) * sizeof (long);
134 
135  /* Space for the mandatory parm save area and general registers. */
136  bytes += 2 * NUM_GPR_ARG_REGISTERS64 * sizeof (long);
137 #endif
138 
139  /* Return value handling. */
140  switch (cif->rtype->type)
141  {
142 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
143  case FFI_TYPE_LONGDOUBLE:
144  if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
145  flags |= FLAG_RETURNS_128BITS;
146  /* Fall through. */
147 #endif
148  case FFI_TYPE_DOUBLE:
149  flags |= FLAG_RETURNS_64BITS;
150  /* Fall through. */
151  case FFI_TYPE_FLOAT:
152  flags |= FLAG_RETURNS_FP;
153  break;
154 
155  case FFI_TYPE_UINT128:
156  flags |= FLAG_RETURNS_128BITS;
157  /* Fall through. */
158  case FFI_TYPE_UINT64:
159  case FFI_TYPE_SINT64:
160  flags |= FLAG_RETURNS_64BITS;
161  break;
162 
163  case FFI_TYPE_STRUCT:
164 #if _CALL_ELF == 2
165  elt = discover_homogeneous_aggregate (cif->rtype, &elnum);
166  if (elt)
167  {
168  if (elt == FFI_TYPE_DOUBLE)
169  flags |= FLAG_RETURNS_64BITS;
171  break;
172  }
173  if (cif->rtype->size <= 16)
174  {
175  flags |= FLAG_RETURNS_SMST;
176  break;
177  }
178 #endif
179  intarg_count++;
180  flags |= FLAG_RETVAL_REFERENCE;
181  /* Fall through. */
182  case FFI_TYPE_VOID:
183  flags |= FLAG_RETURNS_NOTHING;
184  break;
185 
186  default:
187  /* Returns 32-bit integer, or similar. Nothing to do here. */
188  break;
189  }
190 
191  for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
192  {
193  unsigned int align;
194 
195  switch ((*ptr)->type)
196  {
197 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
198  case FFI_TYPE_LONGDOUBLE:
199  if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
200  {
201  fparg_count++;
202  intarg_count++;
203  }
204  /* Fall through. */
205 #endif
206  case FFI_TYPE_DOUBLE:
207  case FFI_TYPE_FLOAT:
208  fparg_count++;
209  intarg_count++;
210  if (fparg_count > NUM_FPR_ARG_REGISTERS64)
211  flags |= FLAG_ARG_NEEDS_PSAVE;
212  break;
213 
214  case FFI_TYPE_STRUCT:
215  if ((cif->abi & FFI_LINUX_STRUCT_ALIGN) != 0)
216  {
217  align = (*ptr)->alignment;
218  if (align > 16)
219  align = 16;
220  align = align / 8;
221  if (align > 1)
222  intarg_count = ALIGN (intarg_count, align);
223  }
224  intarg_count += ((*ptr)->size + 7) / 8;
225 #if _CALL_ELF == 2
226  elt = discover_homogeneous_aggregate (*ptr, &elnum);
227  if (elt)
228  {
229  fparg_count += elnum;
230  if (fparg_count > NUM_FPR_ARG_REGISTERS64)
231  flags |= FLAG_ARG_NEEDS_PSAVE;
232  }
233  else
234 #endif
235  {
236  if (intarg_count > NUM_GPR_ARG_REGISTERS64)
237  flags |= FLAG_ARG_NEEDS_PSAVE;
238  }
239  break;
240 
241  case FFI_TYPE_POINTER:
242  case FFI_TYPE_UINT64:
243  case FFI_TYPE_SINT64:
244  case FFI_TYPE_INT:
245  case FFI_TYPE_UINT32:
246  case FFI_TYPE_SINT32:
247  case FFI_TYPE_UINT16:
248  case FFI_TYPE_SINT16:
249  case FFI_TYPE_UINT8:
250  case FFI_TYPE_SINT8:
251  /* Everything else is passed as a 8-byte word in a GPR, either
252  the object itself or a pointer to it. */
253  intarg_count++;
254  if (intarg_count > NUM_GPR_ARG_REGISTERS64)
255  flags |= FLAG_ARG_NEEDS_PSAVE;
256  break;
257  default:
258  FFI_ASSERT (0);
259  }
260  }
261 
262  if (fparg_count != 0)
263  flags |= FLAG_FP_ARGUMENTS;
264  if (intarg_count > 4)
265  flags |= FLAG_4_GPR_ARGUMENTS;
266 
267  /* Space for the FPR registers, if needed. */
268  if (fparg_count != 0)
269  bytes += NUM_FPR_ARG_REGISTERS64 * sizeof (double);
270 
271  /* Stack space. */
272 #if _CALL_ELF == 2
273  if ((flags & FLAG_ARG_NEEDS_PSAVE) != 0)
274  bytes += intarg_count * sizeof (long);
275 #else
276  if (intarg_count > NUM_GPR_ARG_REGISTERS64)
277  bytes += (intarg_count - NUM_GPR_ARG_REGISTERS64) * sizeof (long);
278 #endif
279 
280  /* The stack space allocated needs to be a multiple of 16 bytes. */
281  bytes = (bytes + 15) & ~0xF;
282 
283  cif->flags = flags;
284  cif->bytes = bytes;
285 
286  return FFI_OK;
287 }
288 
289 ffi_status FFI_HIDDEN
290 ffi_prep_cif_linux64 (ffi_cif *cif)
291 {
292  if ((cif->abi & FFI_LINUX) != 0)
293  cif->nfixedargs = cif->nargs;
294 #if _CALL_ELF != 2
295  else if (cif->abi == FFI_COMPAT_LINUX64)
296  {
297  /* This call is from old code. Don't touch cif->nfixedargs
298  since old code will be using a smaller cif. */
299  cif->flags |= FLAG_COMPAT;
300  /* Translate to new abi value. */
301  cif->abi = FFI_LINUX | FFI_LINUX_LONG_DOUBLE_128;
302  }
303 #endif
304  else
305  return FFI_BAD_ABI;
306  return ffi_prep_cif_linux64_core (cif);
307 }
308 
309 ffi_status FFI_HIDDEN
310 ffi_prep_cif_linux64_var (ffi_cif *cif,
311  unsigned int nfixedargs,
312  unsigned int ntotalargs MAYBE_UNUSED)
313 {
314  if ((cif->abi & FFI_LINUX) != 0)
315  cif->nfixedargs = nfixedargs;
316 #if _CALL_ELF != 2
317  else if (cif->abi == FFI_COMPAT_LINUX64)
318  {
319  /* This call is from old code. Don't touch cif->nfixedargs
320  since old code will be using a smaller cif. */
321  cif->flags |= FLAG_COMPAT;
322  /* Translate to new abi value. */
323  cif->abi = FFI_LINUX | FFI_LINUX_LONG_DOUBLE_128;
324  }
325 #endif
326  else
327  return FFI_BAD_ABI;
328 #if _CALL_ELF == 2
329  cif->flags |= FLAG_ARG_NEEDS_PSAVE;
330 #endif
331  return ffi_prep_cif_linux64_core (cif);
332 }
333 
334 
335 /* ffi_prep_args64 is called by the assembly routine once stack space
336  has been allocated for the function's arguments.
337 
338  The stack layout we want looks like this:
339 
340  | Ret addr from ffi_call_LINUX64 8bytes | higher addresses
341  |--------------------------------------------|
342  | CR save area 8bytes |
343  |--------------------------------------------|
344  | Previous backchain pointer 8 | stack pointer here
345  |--------------------------------------------|<+ <<< on entry to
346  | Saved r28-r31 4*8 | | ffi_call_LINUX64
347  |--------------------------------------------| |
348  | GPR registers r3-r10 8*8 | |
349  |--------------------------------------------| |
350  | FPR registers f1-f13 (optional) 13*8 | |
351  |--------------------------------------------| |
352  | Parameter save area | |
353  |--------------------------------------------| |
354  | TOC save area 8 | |
355  |--------------------------------------------| | stack |
356  | Linker doubleword 8 | | grows |
357  |--------------------------------------------| | down V
358  | Compiler doubleword 8 | |
359  |--------------------------------------------| | lower addresses
360  | Space for callee's LR 8 | |
361  |--------------------------------------------| |
362  | CR save area 8 | |
363  |--------------------------------------------| | stack pointer here
364  | Current backchain pointer 8 |-/ during
365  |--------------------------------------------| <<< ffi_call_LINUX64
366 
367 */
368 
369 void FFI_HIDDEN
370 ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
371 {
372  const unsigned long bytes = ecif->cif->bytes;
373  const unsigned long flags = ecif->cif->flags;
374 
375  typedef union
376  {
377  char *c;
378  unsigned long *ul;
379  float *f;
380  double *d;
381  size_t p;
382  } valp;
383 
384  /* 'stacktop' points at the previous backchain pointer. */
385  valp stacktop;
386 
387  /* 'next_arg' points at the space for gpr3, and grows upwards as
388  we use GPR registers, then continues at rest. */
389  valp gpr_base;
390  valp gpr_end;
391  valp rest;
392  valp next_arg;
393 
394  /* 'fpr_base' points at the space for fpr3, and grows upwards as
395  we use FPR registers. */
396  valp fpr_base;
397  unsigned int fparg_count;
398 
399  unsigned int i, words, nargs, nfixedargs;
400  ffi_type **ptr;
401  double double_tmp;
402  union
403  {
404  void **v;
405  char **c;
406  signed char **sc;
407  unsigned char **uc;
408  signed short **ss;
409  unsigned short **us;
410  signed int **si;
411  unsigned int **ui;
412  unsigned long **ul;
413  float **f;
414  double **d;
415  } p_argv;
416  unsigned long gprvalue;
417  unsigned long align;
418 
419  stacktop.c = (char *) stack + bytes;
420  gpr_base.ul = stacktop.ul - ASM_NEEDS_REGISTERS64 - NUM_GPR_ARG_REGISTERS64;
421  gpr_end.ul = gpr_base.ul + NUM_GPR_ARG_REGISTERS64;
422 #if _CALL_ELF == 2
423  rest.ul = stack + 4 + NUM_GPR_ARG_REGISTERS64;
424 #else
425  rest.ul = stack + 6 + NUM_GPR_ARG_REGISTERS64;
426 #endif
427  fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS64;
428  fparg_count = 0;
429  next_arg.ul = gpr_base.ul;
430 
431  /* Check that everything starts aligned properly. */
432  FFI_ASSERT (((unsigned long) (char *) stack & 0xF) == 0);
433  FFI_ASSERT (((unsigned long) stacktop.c & 0xF) == 0);
434  FFI_ASSERT ((bytes & 0xF) == 0);
435 
436  /* Deal with return values that are actually pass-by-reference. */
437  if (flags & FLAG_RETVAL_REFERENCE)
438  *next_arg.ul++ = (unsigned long) (char *) ecif->rvalue;
439 
440  /* Now for the arguments. */
441  p_argv.v = ecif->avalue;
442  nargs = ecif->cif->nargs;
443 #if _CALL_ELF != 2
444  nfixedargs = (unsigned) -1;
445  if ((flags & FLAG_COMPAT) == 0)
446 #endif
447  nfixedargs = ecif->cif->nfixedargs;
448  for (ptr = ecif->cif->arg_types, i = 0;
449  i < nargs;
450  i++, ptr++, p_argv.v++)
451  {
452 #if _CALL_ELF == 2
453  unsigned int elt, elnum;
454 #endif
455 
456  switch ((*ptr)->type)
457  {
458 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
459  case FFI_TYPE_LONGDOUBLE:
460  if ((ecif->cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
461  {
462  double_tmp = (*p_argv.d)[0];
463  if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
464  {
465  *fpr_base.d++ = double_tmp;
466 # if _CALL_ELF != 2
467  if ((flags & FLAG_COMPAT) != 0)
468  *next_arg.d = double_tmp;
469 # endif
470  }
471  else
472  *next_arg.d = double_tmp;
473  if (++next_arg.ul == gpr_end.ul)
474  next_arg.ul = rest.ul;
475  fparg_count++;
476  double_tmp = (*p_argv.d)[1];
477  if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
478  {
479  *fpr_base.d++ = double_tmp;
480 # if _CALL_ELF != 2
481  if ((flags & FLAG_COMPAT) != 0)
482  *next_arg.d = double_tmp;
483 # endif
484  }
485  else
486  *next_arg.d = double_tmp;
487  if (++next_arg.ul == gpr_end.ul)
488  next_arg.ul = rest.ul;
489  fparg_count++;
490  FFI_ASSERT (__LDBL_MANT_DIG__ == 106);
491  FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
492  break;
493  }
494  /* Fall through. */
495 #endif
496  case FFI_TYPE_DOUBLE:
497  double_tmp = **p_argv.d;
498  if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
499  {
500  *fpr_base.d++ = double_tmp;
501 #if _CALL_ELF != 2
502  if ((flags & FLAG_COMPAT) != 0)
503  *next_arg.d = double_tmp;
504 #endif
505  }
506  else
507  *next_arg.d = double_tmp;
508  if (++next_arg.ul == gpr_end.ul)
509  next_arg.ul = rest.ul;
510  fparg_count++;
511  FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
512  break;
513 
514  case FFI_TYPE_FLOAT:
515  double_tmp = **p_argv.f;
516  if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
517  {
518  *fpr_base.d++ = double_tmp;
519 #if _CALL_ELF != 2
520  if ((flags & FLAG_COMPAT) != 0)
521  *next_arg.f = (float) double_tmp;
522 #endif
523  }
524  else
525  *next_arg.f = (float) double_tmp;
526  if (++next_arg.ul == gpr_end.ul)
527  next_arg.ul = rest.ul;
528  fparg_count++;
529  FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
530  break;
531 
532  case FFI_TYPE_STRUCT:
533  if ((ecif->cif->abi & FFI_LINUX_STRUCT_ALIGN) != 0)
534  {
535  align = (*ptr)->alignment;
536  if (align > 16)
537  align = 16;
538  if (align > 1)
539  next_arg.p = ALIGN (next_arg.p, align);
540  }
541 #if _CALL_ELF == 2
542  elt = discover_homogeneous_aggregate (*ptr, &elnum);
543  if (elt)
544  {
545  union {
546  void *v;
547  float *f;
548  double *d;
549  } arg;
550 
551  arg.v = *p_argv.v;
552  if (elt == FFI_TYPE_FLOAT)
553  {
554  do
555  {
556  double_tmp = *arg.f++;
557  if (fparg_count < NUM_FPR_ARG_REGISTERS64
558  && i < nfixedargs)
559  *fpr_base.d++ = double_tmp;
560  else
561  *next_arg.f = (float) double_tmp;
562  if (++next_arg.f == gpr_end.f)
563  next_arg.f = rest.f;
564  fparg_count++;
565  }
566  while (--elnum != 0);
567  if ((next_arg.p & 3) != 0)
568  {
569  if (++next_arg.f == gpr_end.f)
570  next_arg.f = rest.f;
571  }
572  }
573  else
574  do
575  {
576  double_tmp = *arg.d++;
577  if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
578  *fpr_base.d++ = double_tmp;
579  else
580  *next_arg.d = double_tmp;
581  if (++next_arg.d == gpr_end.d)
582  next_arg.d = rest.d;
583  fparg_count++;
584  }
585  while (--elnum != 0);
586  }
587  else
588 #endif
589  {
590  words = ((*ptr)->size + 7) / 8;
591  if (next_arg.ul >= gpr_base.ul && next_arg.ul + words > gpr_end.ul)
592  {
593  size_t first = gpr_end.c - next_arg.c;
594  memcpy (next_arg.c, *p_argv.c, first);
595  memcpy (rest.c, *p_argv.c + first, (*ptr)->size - first);
596  next_arg.c = rest.c + words * 8 - first;
597  }
598  else
599  {
600  char *where = next_arg.c;
601 
602 #ifndef __LITTLE_ENDIAN__
603  /* Structures with size less than eight bytes are passed
604  left-padded. */
605  if ((*ptr)->size < 8)
606  where += 8 - (*ptr)->size;
607 #endif
608  memcpy (where, *p_argv.c, (*ptr)->size);
609  next_arg.ul += words;
610  if (next_arg.ul == gpr_end.ul)
611  next_arg.ul = rest.ul;
612  }
613  }
614  break;
615 
616  case FFI_TYPE_UINT8:
617  gprvalue = **p_argv.uc;
618  goto putgpr;
619  case FFI_TYPE_SINT8:
620  gprvalue = **p_argv.sc;
621  goto putgpr;
622  case FFI_TYPE_UINT16:
623  gprvalue = **p_argv.us;
624  goto putgpr;
625  case FFI_TYPE_SINT16:
626  gprvalue = **p_argv.ss;
627  goto putgpr;
628  case FFI_TYPE_UINT32:
629  gprvalue = **p_argv.ui;
630  goto putgpr;
631  case FFI_TYPE_INT:
632  case FFI_TYPE_SINT32:
633  gprvalue = **p_argv.si;
634  goto putgpr;
635 
636  case FFI_TYPE_UINT64:
637  case FFI_TYPE_SINT64:
638  case FFI_TYPE_POINTER:
639  gprvalue = **p_argv.ul;
640  putgpr:
641  *next_arg.ul++ = gprvalue;
642  if (next_arg.ul == gpr_end.ul)
643  next_arg.ul = rest.ul;
644  break;
645  }
646  }
647 
649  || (next_arg.ul >= gpr_base.ul
650  && next_arg.ul <= gpr_base.ul + 4));
651 }
652 
653 
654 #if _CALL_ELF == 2
655 #define MIN_CACHE_LINE_SIZE 8
656 
657 static void
658 flush_icache (char *wraddr, char *xaddr, int size)
659 {
660  int i;
661  for (i = 0; i < size; i += MIN_CACHE_LINE_SIZE)
662  __asm__ volatile ("icbi 0,%0;" "dcbf 0,%1;"
663  : : "r" (xaddr + i), "r" (wraddr + i) : "memory");
664  __asm__ volatile ("icbi 0,%0;" "dcbf 0,%1;" "sync;" "isync;"
665  : : "r"(xaddr + size - 1), "r"(wraddr + size - 1)
666  : "memory");
667 }
668 #endif
669 
670 ffi_status
671 ffi_prep_closure_loc_linux64 (ffi_closure *closure,
672  ffi_cif *cif,
673  void (*fun) (ffi_cif *, void *, void **, void *),
674  void *user_data,
675  void *codeloc)
676 {
677 #if _CALL_ELF == 2
678  unsigned int *tramp = (unsigned int *) &closure->tramp[0];
679 
680  if (cif->abi < FFI_LINUX || cif->abi >= FFI_LAST_ABI)
681  return FFI_BAD_ABI;
682 
683  tramp[0] = 0xe96c0018; /* 0: ld 11,2f-0b(12) */
684  tramp[1] = 0xe98c0010; /* ld 12,1f-0b(12) */
685  tramp[2] = 0x7d8903a6; /* mtctr 12 */
686  tramp[3] = 0x4e800420; /* bctr */
687  /* 1: .quad function_addr */
688  /* 2: .quad context */
689  *(void **) &tramp[4] = (void *) ffi_closure_LINUX64;
690  *(void **) &tramp[6] = codeloc;
691  flush_icache ((char *)tramp, (char *)codeloc, FFI_TRAMPOLINE_SIZE);
692 #else
693  void **tramp = (void **) &closure->tramp[0];
694 
695  if (cif->abi < FFI_LINUX || cif->abi >= FFI_LAST_ABI)
696  return FFI_BAD_ABI;
697 
698  /* Copy function address and TOC from ffi_closure_LINUX64. */
699  memcpy (tramp, (char *) ffi_closure_LINUX64, 16);
700  tramp[2] = tramp[1];
701  tramp[1] = codeloc;
702 #endif
703 
704  closure->cif = cif;
705  closure->fun = fun;
706  closure->user_data = user_data;
707 
708  return FFI_OK;
709 }
710 
711 
712 int FFI_HIDDEN
713 ffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue,
714  unsigned long *pst, ffi_dblfl *pfr)
715 {
716  /* rvalue is the pointer to space for return value in closure assembly */
717  /* pst is the pointer to parameter save area
718  (r3-r10 are stored into its first 8 slots by ffi_closure_LINUX64) */
719  /* pfr is the pointer to where f1-f13 are stored in ffi_closure_LINUX64 */
720 
721  void **avalue;
722  ffi_type **arg_types;
723  unsigned long i, avn, nfixedargs;
724  ffi_cif *cif;
725  ffi_dblfl *end_pfr = pfr + NUM_FPR_ARG_REGISTERS64;
726  unsigned long align;
727 
728  cif = closure->cif;
729  avalue = alloca (cif->nargs * sizeof (void *));
730 
731  /* Copy the caller's structure return value address so that the
732  closure returns the data directly to the caller. */
733  if (cif->rtype->type == FFI_TYPE_STRUCT
734  && (cif->flags & FLAG_RETURNS_SMST) == 0)
735  {
736  rvalue = (void *) *pst;
737  pst++;
738  }
739 
740  i = 0;
741  avn = cif->nargs;
742 #if _CALL_ELF != 2
743  nfixedargs = (unsigned) -1;
744  if ((cif->flags & FLAG_COMPAT) == 0)
745 #endif
746  nfixedargs = cif->nfixedargs;
747  arg_types = cif->arg_types;
748 
749  /* Grab the addresses of the arguments from the stack frame. */
750  while (i < avn)
751  {
752  unsigned int elt, elnum;
753 
754  switch (arg_types[i]->type)
755  {
756  case FFI_TYPE_SINT8:
757  case FFI_TYPE_UINT8:
758 #ifndef __LITTLE_ENDIAN__
759  avalue[i] = (char *) pst + 7;
760  pst++;
761  break;
762 #endif
763 
764  case FFI_TYPE_SINT16:
765  case FFI_TYPE_UINT16:
766 #ifndef __LITTLE_ENDIAN__
767  avalue[i] = (char *) pst + 6;
768  pst++;
769  break;
770 #endif
771 
772  case FFI_TYPE_SINT32:
773  case FFI_TYPE_UINT32:
774 #ifndef __LITTLE_ENDIAN__
775  avalue[i] = (char *) pst + 4;
776  pst++;
777  break;
778 #endif
779 
780  case FFI_TYPE_SINT64:
781  case FFI_TYPE_UINT64:
782  case FFI_TYPE_POINTER:
783  avalue[i] = pst;
784  pst++;
785  break;
786 
787  case FFI_TYPE_STRUCT:
788  if ((cif->abi & FFI_LINUX_STRUCT_ALIGN) != 0)
789  {
790  align = arg_types[i]->alignment;
791  if (align > 16)
792  align = 16;
793  if (align > 1)
794  pst = (unsigned long *) ALIGN ((size_t) pst, align);
795  }
796  elt = 0;
797 #if _CALL_ELF == 2
798  elt = discover_homogeneous_aggregate (arg_types[i], &elnum);
799 #endif
800  if (elt)
801  {
802  union {
803  void *v;
804  unsigned long *ul;
805  float *f;
806  double *d;
807  size_t p;
808  } to, from;
809 
810  /* Repackage the aggregate from its parts. The
811  aggregate size is not greater than the space taken by
812  the registers so store back to the register/parameter
813  save arrays. */
814  if (pfr + elnum <= end_pfr)
815  to.v = pfr;
816  else
817  to.v = pst;
818 
819  avalue[i] = to.v;
820  from.ul = pst;
821  if (elt == FFI_TYPE_FLOAT)
822  {
823  do
824  {
825  if (pfr < end_pfr && i < nfixedargs)
826  {
827  *to.f = (float) pfr->d;
828  pfr++;
829  }
830  else
831  *to.f = *from.f;
832  to.f++;
833  from.f++;
834  }
835  while (--elnum != 0);
836  }
837  else
838  {
839  do
840  {
841  if (pfr < end_pfr && i < nfixedargs)
842  {
843  *to.d = pfr->d;
844  pfr++;
845  }
846  else
847  *to.d = *from.d;
848  to.d++;
849  from.d++;
850  }
851  while (--elnum != 0);
852  }
853  }
854  else
855  {
856 #ifndef __LITTLE_ENDIAN__
857  /* Structures with size less than eight bytes are passed
858  left-padded. */
859  if (arg_types[i]->size < 8)
860  avalue[i] = (char *) pst + 8 - arg_types[i]->size;
861  else
862 #endif
863  avalue[i] = pst;
864  }
865  pst += (arg_types[i]->size + 7) / 8;
866  break;
867 
868 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
869  case FFI_TYPE_LONGDOUBLE:
870  if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
871  {
872  if (pfr + 1 < end_pfr && i + 1 < nfixedargs)
873  {
874  avalue[i] = pfr;
875  pfr += 2;
876  }
877  else
878  {
879  if (pfr < end_pfr && i < nfixedargs)
880  {
881  /* Passed partly in f13 and partly on the stack.
882  Move it all to the stack. */
883  *pst = *(unsigned long *) pfr;
884  pfr++;
885  }
886  avalue[i] = pst;
887  }
888  pst += 2;
889  break;
890  }
891  /* Fall through. */
892 #endif
893  case FFI_TYPE_DOUBLE:
894  /* On the outgoing stack all values are aligned to 8 */
895  /* there are 13 64bit floating point registers */
896 
897  if (pfr < end_pfr && i < nfixedargs)
898  {
899  avalue[i] = pfr;
900  pfr++;
901  }
902  else
903  avalue[i] = pst;
904  pst++;
905  break;
906 
907  case FFI_TYPE_FLOAT:
908  if (pfr < end_pfr && i < nfixedargs)
909  {
910  /* Float values are stored as doubles in the
911  ffi_closure_LINUX64 code. Fix them here. */
912  pfr->f = (float) pfr->d;
913  avalue[i] = pfr;
914  pfr++;
915  }
916  else
917  avalue[i] = pst;
918  pst++;
919  break;
920 
921  default:
922  FFI_ASSERT (0);
923  }
924 
925  i++;
926  }
927 
928 
929  (closure->fun) (cif, rvalue, avalue, closure->user_data);
930 
931  /* Tell ffi_closure_LINUX64 how to perform return type promotions. */
932  if ((cif->flags & FLAG_RETURNS_SMST) != 0)
933  {
934  if ((cif->flags & FLAG_RETURNS_FP) == 0)
935  return FFI_V2_TYPE_SMALL_STRUCT + cif->rtype->size - 1;
936  else if ((cif->flags & FLAG_RETURNS_64BITS) != 0)
938  else
940  }
941  return cif->rtype->type;
942 }
943 #endif
MIN_CACHE_LINE_SIZE
#define MIN_CACHE_LINE_SIZE
Definition: ffi_sysv.c:629
FFI_ASSERT
#define FFI_ASSERT(x)
Definition: ffi_common.h:72
FFI_TYPE_UINT128
#define FFI_TYPE_UINT128
Definition: ffitarget.h:149
ffi_closure_helper_LINUX64
int FFI_HIDDEN ffi_closure_helper_LINUX64(ffi_closure *, void *, unsigned long *, ffi_dblfl *)
ffi_dblfl::d
double d
Definition: ffi_darwin.c:1104
FFI_TYPE_LONGDOUBLE
#define FFI_TYPE_LONGDOUBLE
Definition: ffi.c:40
ffi_abi
ffi_abi
Definition: ffitarget.h:33
extended_cif::rvalue
void * rvalue
Definition: ffi_common.h:89
ffi_common.h
FFI_HIDDEN
const UINT64 ffi_template_tramp_tile[] FFI_HIDDEN
FFI_TRAMPOLINE_SIZE
#define FFI_TRAMPOLINE_SIZE
Definition: ffitarget.h:45
ffi_prep_cif_linux64_var
ffi_status FFI_HIDDEN ffi_prep_cif_linux64_var(ffi_cif *, unsigned int, unsigned int)
FLAG_4_GPR_ARGUMENTS
@ FLAG_4_GPR_ARGUMENTS
Definition: ffi_darwin.c:52
ptr
struct RIMemo * ptr
Definition: debug.c:74
ALIGN
#define ALIGN(v, a)
Definition: ffi_common.h:77
ffi_dblfl::f
float f
Definition: ffi_darwin.c:1103
v
int VALUE v
Definition: rb_mjit_min_header-2.7.0.h:12332
FLAG_COMPAT
@ FLAG_COMPAT
Definition: ffi_powerpc.h:42
if
if((ID)(DISPID) nameid !=nameid)
Definition: win32ole.c:357
memcpy
void * memcpy(void *__restrict, const void *__restrict, size_t)
FFI_COMPAT_LINUX64
@ FFI_COMPAT_LINUX64
Definition: ffitarget.h:81
double
double
Definition: rb_mjit_min_header-2.7.0.h:5923
FLAG_RETURNS_64BITS
@ FLAG_RETURNS_64BITS
Definition: ffi_darwin.c:46
i
uint32_t i
Definition: rb_mjit_min_header-2.7.0.h:5464
FLAG_RETVAL_REFERENCE
@ FLAG_RETVAL_REFERENCE
Definition: ffi_darwin.c:53
long
#define long
Definition: rb_mjit_min_header-2.7.0.h:2880
alloca
#define alloca(size)
Definition: rb_mjit_min_header-2.7.0.h:2487
FFI_LAST_ABI
@ FFI_LAST_ABI
Definition: ffitarget.h:37
size
int size
Definition: encoding.c:58
extended_cif
Definition: ffi_common.h:86
ffi_closure_LINUX64
void FFI_HIDDEN ffi_closure_LINUX64(void)
FFI_V2_TYPE_SMALL_STRUCT
#define FFI_V2_TYPE_SMALL_STRUCT
Definition: ffitarget.h:157
FFI_V2_TYPE_FLOAT_HOMOG
#define FFI_V2_TYPE_FLOAT_HOMOG
Definition: ffitarget.h:155
ffi_powerpc.h
arg
VALUE arg
Definition: rb_mjit_min_header-2.7.0.h:5601
f
#define f
extended_cif::avalue
void ** avalue
Definition: ffi_common.h:90
FLAG_RETURNS_NOTHING
@ FLAG_RETURNS_NOTHING
Definition: ffi_darwin.c:44
__asm__
#define __asm__
Definition: Context.c:12
FLAG_ARG_NEEDS_PSAVE
@ FLAG_ARG_NEEDS_PSAVE
Definition: ffi_powerpc.h:46
ffi_dblfl
Definition: ffi_darwin.c:1101
FFI_V2_TYPE_DOUBLE_HOMOG
#define FFI_V2_TYPE_DOUBLE_HOMOG
Definition: ffitarget.h:156
FLAG_RETURNS_SMST
@ FLAG_RETURNS_SMST
Definition: ffi_powerpc.h:34
ffi_prep_cif_linux64
ffi_status FFI_HIDDEN ffi_prep_cif_linux64(ffi_cif *)
ffi_prep_types_linux64
void FFI_HIDDEN ffi_prep_types_linux64(ffi_abi)
FLAG_RETURNS_FP
@ FLAG_RETURNS_FP
Definition: ffi_darwin.c:45
MAYBE_UNUSED
#define MAYBE_UNUSED
Definition: ffi_common.h:32
FLAG_RETURNS_128BITS
@ FLAG_RETURNS_128BITS
Definition: ffi_darwin.c:43
unsigned
#define unsigned
Definition: rb_mjit_min_header-2.7.0.h:2875
extended_cif::cif
ffi_cif * cif
Definition: ffi_common.h:88
ruby::backward::cxxanyargs::type
VALUE type(ANYARGS)
ANYARGS-ed function type.
Definition: cxxanyargs.hpp:39
FLAG_FP_ARGUMENTS
@ FLAG_FP_ARGUMENTS
Definition: ffi_darwin.c:51
ffi_prep_args64
void FFI_HIDDEN ffi_prep_args64(extended_cif *, unsigned long *const)