Ruby  2.7.1p83(2020-03-31revisiona0c7c23c9cec0d0ffcba012279cd652d28ad5bf3)
ffi.c
Go to the documentation of this file.
1 /* libffi support for Altera Nios II.
2 
3  Copyright (c) 2013 Mentor Graphics.
4 
5  Permission is hereby granted, free of charge, to any person obtaining
6  a copy of this software and associated documentation files (the
7  ``Software''), to deal in the Software without restriction, including
8  without limitation the rights to use, copy, modify, merge, publish,
9  distribute, sublicense, and/or sell copies of the Software, and to
10  permit persons to whom the Software is furnished to do so, subject to
11  the following conditions:
12 
13  The above copyright notice and this permission notice shall be
14  included in all copies or substantial portions of the Software.
15 
16  THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
17  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
23 
24 
25 #include <ffi.h>
26 #include <ffi_common.h>
27 
28 #include <stdlib.h>
29 
30 /* The Nios II Processor Reference Handbook defines the procedure call
31  ABI as follows.
32 
33  Arguments are passed as if a structure containing the types of
34  the arguments were constructed. The first 16 bytes are passed in r4
35  through r7, the remainder on the stack. The first 16 bytes of a function
36  taking variable arguments are passed in r4-r7 in the same way.
37 
38  Return values of types up to 8 bytes are returned in r2 and r3. For
39  return values greater than 8 bytes, the caller must allocate memory for
40  the result and pass the address as if it were argument 0.
41 
42  While this isn't specified explicitly in the ABI documentation, GCC
43  promotes integral arguments smaller than int size to 32 bits.
44 
45  Also of note, the ABI specifies that all structure objects are
46  aligned to 32 bits even if all their fields have a smaller natural
47  alignment. See FFI_AGGREGATE_ALIGNMENT. */
48 
49 
50 /* Declare the assembly language hooks. */
51 
52 extern UINT64 ffi_call_sysv (void (*) (char *, extended_cif *),
53  extended_cif *,
54  unsigned,
55  void (*fn) (void));
56 extern void ffi_closure_sysv (void);
57 
58 /* Perform machine-dependent cif processing. */
59 
60 ffi_status ffi_prep_cif_machdep (ffi_cif *cif)
61 {
62  /* We always want at least 16 bytes in the parameter block since it
63  simplifies the low-level call function. Also round the parameter
64  block size up to a multiple of 4 bytes to preserve
65  32-bit alignment of the stack pointer. */
66  if (cif->bytes < 16)
67  cif->bytes = 16;
68  else
69  cif->bytes = (cif->bytes + 3) & ~3;
70 
71  return FFI_OK;
72 }
73 
74 
75 /* ffi_prep_args is called by the assembly routine to transfer arguments
76  to the stack using the pointers in the ecif array.
77  Note that the stack buffer is big enough to fit all the arguments,
78  but the first 16 bytes will be copied to registers for the actual
79  call. */
80 
81 void ffi_prep_args (char *stack, extended_cif *ecif)
82 {
83  char *argp = stack;
84  unsigned int i;
85 
86  /* The implicit return value pointer is passed as if it were a hidden
87  first argument. */
88  if (ecif->cif->rtype->type == FFI_TYPE_STRUCT
89  && ecif->cif->rtype->size > 8)
90  {
91  (*(void **) argp) = ecif->rvalue;
92  argp += 4;
93  }
94 
95  for (i = 0; i < ecif->cif->nargs; i++)
96  {
97  void *avalue = ecif->avalue[i];
98  ffi_type *atype = ecif->cif->arg_types[i];
99  size_t size = atype->size;
100  size_t alignment = atype->alignment;
101 
102  /* Align argp as appropriate for the argument type. */
103  if ((alignment - 1) & (unsigned) argp)
104  argp = (char *) ALIGN (argp, alignment);
105 
106  /* Copy the argument, promoting integral types smaller than a
107  word to word size. */
108  if (size < sizeof (int))
109  {
110  size = sizeof (int);
111  switch (atype->type)
112  {
113  case FFI_TYPE_SINT8:
114  *(signed int *) argp = (signed int) *(SINT8 *) avalue;
115  break;
116 
117  case FFI_TYPE_UINT8:
118  *(unsigned int *) argp = (unsigned int) *(UINT8 *) avalue;
119  break;
120 
121  case FFI_TYPE_SINT16:
122  *(signed int *) argp = (signed int) *(SINT16 *) avalue;
123  break;
124 
125  case FFI_TYPE_UINT16:
126  *(unsigned int *) argp = (unsigned int) *(UINT16 *) avalue;
127  break;
128 
129  case FFI_TYPE_STRUCT:
130  memcpy (argp, avalue, atype->size);
131  break;
132 
133  default:
134  FFI_ASSERT(0);
135  }
136  }
137  else if (size == sizeof (int))
138  *(unsigned int *) argp = (unsigned int) *(UINT32 *) avalue;
139  else
140  memcpy (argp, avalue, size);
141  argp += size;
142  }
143 }
144 
145 
146 /* Call FN using the prepared CIF. RVALUE points to space allocated by
147  the caller for the return value, and AVALUE is an array of argument
148  pointers. */
149 
150 void ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue)
151 {
152 
153  extended_cif ecif;
154  UINT64 result;
155 
156  /* If bigret is true, this is the case where a return value of larger
157  than 8 bytes is handled by being passed by reference as an implicit
158  argument. */
159  int bigret = (cif->rtype->type == FFI_TYPE_STRUCT
160  && cif->rtype->size > 8);
161 
162  ecif.cif = cif;
163  ecif.avalue = avalue;
164 
165  /* Allocate space for return value if this is the pass-by-reference case
166  and the caller did not provide a buffer. */
167  if (rvalue == NULL && bigret)
168  ecif.rvalue = alloca (cif->rtype->size);
169  else
170  ecif.rvalue = rvalue;
171 
172  result = ffi_call_sysv (ffi_prep_args, &ecif, cif->bytes, fn);
173 
174  /* Now result contains the 64 bit contents returned from fn in
175  r2 and r3. Copy the value of the appropriate size to the user-provided
176  rvalue buffer. */
177  if (rvalue && !bigret)
178  switch (cif->rtype->size)
179  {
180  case 1:
181  *(UINT8 *)rvalue = (UINT8) result;
182  break;
183  case 2:
184  *(UINT16 *)rvalue = (UINT16) result;
185  break;
186  case 4:
187  *(UINT32 *)rvalue = (UINT32) result;
188  break;
189  case 8:
190  *(UINT64 *)rvalue = (UINT64) result;
191  break;
192  default:
193  memcpy (rvalue, (void *)&result, cif->rtype->size);
194  break;
195  }
196 }
197 
198 /* This function is invoked from the closure trampoline to invoke
199  CLOSURE with argument block ARGS. Parse ARGS according to
200  CLOSURE->cfi and invoke CLOSURE->fun. */
201 
202 static UINT64
203 ffi_closure_helper (unsigned char *args,
204  ffi_closure *closure)
205 {
206  ffi_cif *cif = closure->cif;
207  unsigned char *argp = args;
208  void **parsed_args = alloca (cif->nargs * sizeof (void *));
209  UINT64 result;
210  void *retptr;
211  unsigned int i;
212 
213  /* First figure out what to do about the return type. If this is the
214  big-structure-return case, the first arg is the hidden return buffer
215  allocated by the caller. */
216  if (cif->rtype->type == FFI_TYPE_STRUCT
217  && cif->rtype->size > 8)
218  {
219  retptr = *((void **) argp);
220  argp += 4;
221  }
222  else
223  retptr = (void *) &result;
224 
225  /* Fill in the array of argument pointers. */
226  for (i = 0; i < cif->nargs; i++)
227  {
228  size_t size = cif->arg_types[i]->size;
229  size_t alignment = cif->arg_types[i]->alignment;
230 
231  /* Align argp as appropriate for the argument type. */
232  if ((alignment - 1) & (unsigned) argp)
233  argp = (char *) ALIGN (argp, alignment);
234 
235  /* Arguments smaller than an int are promoted to int. */
236  if (size < sizeof (int))
237  size = sizeof (int);
238 
239  /* Store the pointer. */
240  parsed_args[i] = argp;
241  argp += size;
242  }
243 
244  /* Call the user-supplied function. */
245  (closure->fun) (cif, retptr, parsed_args, closure->user_data);
246  return result;
247 }
248 
249 
250 /* Initialize CLOSURE with a trampoline to call FUN with
251  CIF and USER_DATA. */
252 ffi_status
253 ffi_prep_closure_loc (ffi_closure* closure,
254  ffi_cif* cif,
255  void (*fun) (ffi_cif*, void*, void**, void*),
256  void *user_data,
257  void *codeloc)
258 {
259  unsigned int *tramp = (unsigned int *) &closure->tramp[0];
260  int i;
261 
262  if (cif->abi != FFI_SYSV)
263  return FFI_BAD_ABI;
264 
265  /* The trampoline looks like:
266  movhi r8, %hi(ffi_closure_sysv)
267  ori r8, r8, %lo(ffi_closure_sysv)
268  movhi r9, %hi(ffi_closure_helper)
269  ori r0, r9, %lo(ffi_closure_helper)
270  movhi r10, %hi(closure)
271  ori r10, r10, %lo(closure)
272  jmp r8
273  and then ffi_closure_sysv retrieves the closure pointer out of r10
274  in addition to the arguments passed in the normal way for the call,
275  and invokes ffi_closure_helper. We encode the pointer to
276  ffi_closure_helper in the trampoline because making a PIC call
277  to it in ffi_closure_sysv would be messy (it would have to indirect
278  through the GOT). */
279 
280 #define HI(x) ((((unsigned int) (x)) >> 16) & 0xffff)
281 #define LO(x) (((unsigned int) (x)) & 0xffff)
282  tramp[0] = (0 << 27) | (8 << 22) | (HI (ffi_closure_sysv) << 6) | 0x34;
283  tramp[1] = (8 << 27) | (8 << 22) | (LO (ffi_closure_sysv) << 6) | 0x14;
284  tramp[2] = (0 << 27) | (9 << 22) | (HI (ffi_closure_helper) << 6) | 0x34;
285  tramp[3] = (9 << 27) | (9 << 22) | (LO (ffi_closure_helper) << 6) | 0x14;
286  tramp[4] = (0 << 27) | (10 << 22) | (HI (closure) << 6) | 0x34;
287  tramp[5] = (10 << 27) | (10 << 22) | (LO (closure) << 6) | 0x14;
288  tramp[6] = (8 << 27) | (0x0d << 11) | 0x3a;
289 #undef HI
290 #undef LO
291 
292  /* Flush the caches.
293  See Example 9-4 in the Nios II Software Developer's Handbook. */
294  for (i = 0; i < 7; i++)
295  asm volatile ("flushd 0(%0); flushi %0" :: "r"(tramp + i) : "memory");
296  asm volatile ("flushp" ::: "memory");
297 
298  closure->cif = cif;
299  closure->fun = fun;
300  closure->user_data = user_data;
301 
302  return FFI_OK;
303 }
304 
FFI_ASSERT
#define FFI_ASSERT(x)
Definition: ffi_common.h:72
i
uint32_t i
Definition: rb_mjit_min_header-2.7.1.h:5425
extended_cif::rvalue
void * rvalue
Definition: ffi_common.h:89
ffi_common.h
ffi_closure_sysv
void ffi_closure_sysv(void)
FFI_SYSV
@ FFI_SYSV
Definition: ffitarget.h:36
ALIGN
#define ALIGN(v, a)
Definition: ffi_common.h:77
NULL
#define NULL
Definition: _sdbm.c:101
ffi_prep_args
void ffi_prep_args(char *stack, extended_cif *ecif)
Definition: ffi.c:46
if
if((ID)(DISPID) nameid !=nameid)
Definition: win32ole.c:357
unsigned
#define unsigned
Definition: rb_mjit_min_header-2.7.1.h:2843
size
int size
Definition: encoding.c:58
ffi_prep_cif_machdep
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
Definition: ffi.c:758
extended_cif
Definition: ffi_common.h:86
HI
#define HI(x)
LO
#define LO(x)
extended_cif::avalue
void ** avalue
Definition: ffi_common.h:90
int
__inline__ int
Definition: rb_mjit_min_header-2.7.1.h:2807
memcpy
void * memcpy(void *__restrict, const void *__restrict, size_t)
ffi_call_sysv
UINT64 ffi_call_sysv(void(*)(char *, extended_cif *), extended_cif *, unsigned, void(*fn)(void))
ffi_call
void ffi_call(ffi_cif *cif, void(*fn)(void), void *rvalue, void **avalue)
Definition: ffi.c:813
alloca
#define alloca(size)
Definition: rb_mjit_min_header-2.7.1.h:2455
ffi_prep_closure_loc
ffi_status ffi_prep_closure_loc(ffi_closure *closure, ffi_cif *cif, void(*fun)(ffi_cif *, void *, void **, void *), void *user_data, void *codeloc)
Definition: ffi.c:928
extended_cif::cif
ffi_cif * cif
Definition: ffi_common.h:88