Ruby  2.4.2p198(2017-09-14revision59899)
ffi.c
Go to the documentation of this file.
1 /* -----------------------------------------------------------------------
2  ffi.c - Copyright (c) 2012, 2013 Xilinx, Inc
3 
4  MicroBlaze Foreign Function Interface
5 
6  Permission is hereby granted, free of charge, to any person obtaining
7  a copy of this software and associated documentation files (the
8  ``Software''), to deal in the Software without restriction, including
9  without limitation the rights to use, copy, modify, merge, publish,
10  distribute, sublicense, and/or sell copies of the Software, and to
11  permit persons to whom the Software is furnished to do so, subject to
12  the following conditions:
13 
14  The above copyright notice and this permission notice shall be included
15  in all copies or substantial portions of the Software.
16 
17  THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
18  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24  DEALINGS IN THE SOFTWARE.
25  ----------------------------------------------------------------------- */
26 
27 #include <ffi.h>
28 #include <ffi_common.h>
29 
30 extern void ffi_call_SYSV(void (*)(void*, extended_cif*), extended_cif*,
31  unsigned int, unsigned int, unsigned int*, void (*fn)(void),
32  unsigned int, unsigned int);
33 
34 extern void ffi_closure_SYSV(void);
35 
36 #define WORD_SIZE sizeof(unsigned int)
37 #define ARGS_REGISTER_SIZE (WORD_SIZE * 6)
38 #define WORD_ALIGN(x) ALIGN(x, WORD_SIZE)
39 
40 /* ffi_prep_args is called by the assembly routine once stack space
41  has been allocated for the function's arguments */
42 void ffi_prep_args(void* stack, extended_cif* ecif)
43 {
44  unsigned int i;
45  ffi_type** p_arg;
46  void** p_argv;
47  void* stack_args_p = stack;
48 
49  p_argv = ecif->avalue;
50 
51  if (ecif == NULL || ecif->cif == NULL) {
52  return; /* no description to prepare */
53  }
54 
55  if ((ecif->cif->rtype != NULL) &&
56  (ecif->cif->rtype->type == FFI_TYPE_STRUCT))
57  {
58  /* if return type is a struct which is referenced on the stack/reg5,
59  * by a pointer. Stored the return value pointer in r5.
60  */
61  char* addr = stack_args_p;
62  memcpy(addr, &(ecif->rvalue), WORD_SIZE);
63  stack_args_p += WORD_SIZE;
64  }
65 
66  if (ecif->avalue == NULL) {
67  return; /* no arguments to prepare */
68  }
69 
70  for (i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs;
71  i++, p_arg++)
72  {
73  size_t size = (*p_arg)->size;
74  int type = (*p_arg)->type;
75  void* value = p_argv[i];
76  char* addr = stack_args_p;
77  int aligned_size = WORD_ALIGN(size);
78 
79  /* force word alignment on the stack */
80  stack_args_p += aligned_size;
81 
82  switch (type)
83  {
84  case FFI_TYPE_UINT8:
85  *(unsigned int *)addr = (unsigned int)*(UINT8*)(value);
86  break;
87  case FFI_TYPE_SINT8:
88  *(signed int *)addr = (signed int)*(SINT8*)(value);
89  break;
90  case FFI_TYPE_UINT16:
91  *(unsigned int *)addr = (unsigned int)*(UINT16*)(value);
92  break;
93  case FFI_TYPE_SINT16:
94  *(signed int *)addr = (signed int)*(SINT16*)(value);
95  break;
96  case FFI_TYPE_STRUCT:
97 #if __BIG_ENDIAN__
98  /*
99  * MicroBlaze toolchain appears to emit:
100  * bsrli r5, r5, 8 (caller)
101  * ...
102  * <branch to callee>
103  * ...
104  * bslli r5, r5, 8 (callee)
105  *
106  * For structs like "struct a { uint8_t a[3]; };", when passed
107  * by value.
108  *
109  * Structs like "struct b { uint16_t a; };" are also expected
110  * to be packed strangely in registers.
111  *
112  * This appears to be because the microblaze toolchain expects
113  * "struct b == uint16_t", which is only any issue for big
114  * endian.
115  *
116  * The following is a work around for big-endian only, for the
117  * above mentioned case, it will re-align the contents of a
118  * <= 3-byte struct value.
119  */
120  if (size < WORD_SIZE)
121  {
122  memcpy (addr + (WORD_SIZE - size), value, size);
123  break;
124  }
125 #endif
126  case FFI_TYPE_SINT32:
127  case FFI_TYPE_UINT32:
128  case FFI_TYPE_FLOAT:
129  case FFI_TYPE_SINT64:
130  case FFI_TYPE_UINT64:
131  case FFI_TYPE_DOUBLE:
132  default:
133  memcpy(addr, value, aligned_size);
134  }
135  }
136 }
137 
138 ffi_status ffi_prep_cif_machdep(ffi_cif* cif)
139 {
140  /* check ABI */
141  switch (cif->abi)
142  {
143  case FFI_SYSV:
144  break;
145  default:
146  return FFI_BAD_ABI;
147  }
148  return FFI_OK;
149 }
150 
151 void ffi_call(ffi_cif* cif, void (*fn)(void), void* rvalue, void** avalue)
152 {
153  extended_cif ecif;
154  ecif.cif = cif;
155  ecif.avalue = avalue;
156 
157  /* If the return value is a struct and we don't have a return */
158  /* value address then we need to make one */
159  if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) {
160  ecif.rvalue = alloca(cif->rtype->size);
161  } else {
162  ecif.rvalue = rvalue;
163  }
164 
165  switch (cif->abi)
166  {
167  case FFI_SYSV:
168  ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags,
169  ecif.rvalue, fn, cif->rtype->type, cif->rtype->size);
170  break;
171  default:
172  FFI_ASSERT(0);
173  break;
174  }
175 }
176 
177 void ffi_closure_call_SYSV(void* register_args, void* stack_args,
178  ffi_closure* closure, void* rvalue,
179  unsigned int* rtype, unsigned int* rsize)
180 {
181  /* prepare arguments for closure call */
182  ffi_cif* cif = closure->cif;
183  ffi_type** arg_types = cif->arg_types;
184 
185  /* re-allocate data for the args. This needs to be done in order to keep
186  * multi-word objects (e.g. structs) in contiguous memory. Callers are not
187  * required to store the value of args in the lower 6 words in the stack
188  * (although they are allocated in the stack).
189  */
190  char* stackclone = alloca(cif->bytes);
191  void** avalue = alloca(cif->nargs * sizeof(void*));
192  void* struct_rvalue = NULL;
193  char* ptr = stackclone;
194  int i;
195 
196  /* copy registers into stack clone */
197  int registers_used = cif->bytes;
198  if (registers_used > ARGS_REGISTER_SIZE) {
199  registers_used = ARGS_REGISTER_SIZE;
200  }
201  memcpy(stackclone, register_args, registers_used);
202 
203  /* copy stack allocated args into stack clone */
204  if (cif->bytes > ARGS_REGISTER_SIZE) {
205  int stack_used = cif->bytes - ARGS_REGISTER_SIZE;
206  memcpy(stackclone + ARGS_REGISTER_SIZE, stack_args, stack_used);
207  }
208 
209  /* preserve struct type return pointer passing */
210  if ((cif->rtype != NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) {
211  struct_rvalue = *((void**)ptr);
212  ptr += WORD_SIZE;
213  }
214 
215  /* populate arg pointer list */
216  for (i = 0; i < cif->nargs; i++)
217  {
218  switch (arg_types[i]->type)
219  {
220  case FFI_TYPE_SINT8:
221  case FFI_TYPE_UINT8:
222 #ifdef __BIG_ENDIAN__
223  avalue[i] = ptr + 3;
224 #else
225  avalue[i] = ptr;
226 #endif
227  break;
228  case FFI_TYPE_SINT16:
229  case FFI_TYPE_UINT16:
230 #ifdef __BIG_ENDIAN__
231  avalue[i] = ptr + 2;
232 #else
233  avalue[i] = ptr;
234 #endif
235  break;
236  case FFI_TYPE_STRUCT:
237 #if __BIG_ENDIAN__
238  /*
239  * Work around strange ABI behaviour.
240  * (see info in ffi_prep_args)
241  */
242  if (arg_types[i]->size < WORD_SIZE)
243  {
244  memcpy (ptr, ptr + (WORD_SIZE - arg_types[i]->size), arg_types[i]->size);
245  }
246 #endif
247  avalue[i] = (void*)ptr;
248  break;
249  case FFI_TYPE_UINT64:
250  case FFI_TYPE_SINT64:
251  case FFI_TYPE_DOUBLE:
252  avalue[i] = ptr;
253  break;
254  case FFI_TYPE_SINT32:
255  case FFI_TYPE_UINT32:
256  case FFI_TYPE_FLOAT:
257  default:
258  /* default 4-byte argument */
259  avalue[i] = ptr;
260  break;
261  }
262  ptr += WORD_ALIGN(arg_types[i]->size);
263  }
264 
265  /* set the return type info passed back to the wrapper */
266  *rsize = cif->rtype->size;
267  *rtype = cif->rtype->type;
268  if (struct_rvalue != NULL) {
269  closure->fun(cif, struct_rvalue, avalue, closure->user_data);
270  /* copy struct return pointer value into function return value */
271  *((void**)rvalue) = struct_rvalue;
272  } else {
273  closure->fun(cif, rvalue, avalue, closure->user_data);
274  }
275 }
276 
278  ffi_closure* closure, ffi_cif* cif,
279  void (*fun)(ffi_cif*, void*, void**, void*),
280  void* user_data, void* codeloc)
281 {
282  unsigned long* tramp = (unsigned long*)&(closure->tramp[0]);
283  unsigned long cls = (unsigned long)codeloc;
284  unsigned long fn = 0;
285  unsigned long fn_closure_call_sysv = (unsigned long)ffi_closure_call_SYSV;
286 
287  closure->cif = cif;
288  closure->fun = fun;
289  closure->user_data = user_data;
290 
291  switch (cif->abi)
292  {
293  case FFI_SYSV:
294  fn = (unsigned long)ffi_closure_SYSV;
295 
296  /* load r11 (temp) with fn */
297  /* imm fn(upper) */
298  tramp[0] = 0xb0000000 | ((fn >> 16) & 0xffff);
299  /* addik r11, r0, fn(lower) */
300  tramp[1] = 0x31600000 | (fn & 0xffff);
301 
302  /* load r12 (temp) with cls */
303  /* imm cls(upper) */
304  tramp[2] = 0xb0000000 | ((cls >> 16) & 0xffff);
305  /* addik r12, r0, cls(lower) */
306  tramp[3] = 0x31800000 | (cls & 0xffff);
307 
308  /* load r3 (temp) with ffi_closure_call_SYSV */
309  /* imm fn_closure_call_sysv(upper) */
310  tramp[4] = 0xb0000000 | ((fn_closure_call_sysv >> 16) & 0xffff);
311  /* addik r3, r0, fn_closure_call_sysv(lower) */
312  tramp[5] = 0x30600000 | (fn_closure_call_sysv & 0xffff);
313  /* branch/jump to address stored in r11 (fn) */
314  tramp[6] = 0x98085800; /* bra r11 */
315 
316  break;
317  default:
318  return FFI_BAD_ABI;
319  }
320  return FFI_OK;
321 }
void ffi_closure_call_SYSV(void *register_args, void *stack_args, ffi_closure *closure, void *rvalue, unsigned int *rtype, unsigned int *rsize)
Definition: ffi.c:177
#define FFI_ASSERT(x)
Definition: ffi_common.h:72
#define WORD_ALIGN(x)
Definition: ffi.c:38
void ffi_call_SYSV(unsigned(*)(struct call_context *context, unsigned char *, extended_cif *), struct call_context *context, extended_cif *, size_t, void(*fn)(void))
ffi_cif * cif
Definition: ffi_common.h:88
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
void * rvalue
Definition: ffi_common.h:89
#define WORD_SIZE
Definition: ffi.c:36
void ffi_call(ffi_cif *cif, void(*fn)(void), void *rvalue, void **avalue)
Definition: ffi.c:813
char * alloca()
int size
Definition: encoding.c:57
#define memcpy(d, s, n)
Definition: ffi_common.h:55
#define ARGS_REGISTER_SIZE
Definition: ffi.c:37
void ffi_prep_args(char *stack, extended_cif *ecif)
Definition: ffi.c:46
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
Definition: ffi.c:758
#define NULL
Definition: _sdbm.c:102
void ** avalue
Definition: ffi_common.h:90
void ffi_closure_SYSV(ffi_closure *)
Definition: ffi.c:420