1 /* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 1998 Cygnus Solutions
3 Copyright (c) 2004 Simon Posnjak
4 Copyright (c) 2005 Axis Communications AB
5 Copyright (C) 2007 Free Software Foundation, Inc.
6
7 CRIS Foreign Function Interface
8
9 Permission is hereby granted, free of charge, to any person obtaining
10 a copy of this software and associated documentation files (the
11 ``Software''), to deal in the Software without restriction, including
12 without limitation the rights to use, copy, modify, merge, publish,
13 distribute, sublicense, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
16
17 The above copyright notice and this permission notice shall be included
18 in all copies or substantial portions of the Software.
19
20 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 IN NO EVENT SHALL SIMON POSNJAK BE LIABLE FOR ANY CLAIM, DAMAGES OR
24 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 OTHER DEALINGS IN THE SOFTWARE.
27 ----------------------------------------------------------------------- */
28
29 #include <ffi.h>
30 #include <ffi_common.h>
31
32 #define STACK_ARG_SIZE(x) FFI_ALIGN(x, FFI_SIZEOF_ARG)
33
34 static ffi_status
initialize_aggregate_packed_struct(ffi_type * arg)35 initialize_aggregate_packed_struct (ffi_type * arg)
36 {
37 ffi_type **ptr;
38
39 FFI_ASSERT (arg != NULL);
40
41 FFI_ASSERT (arg->elements != NULL);
42 FFI_ASSERT (arg->size == 0);
43 FFI_ASSERT (arg->alignment == 0);
44
45 ptr = &(arg->elements[0]);
46
47 while ((*ptr) != NULL)
48 {
49 if (((*ptr)->size == 0)
50 && (initialize_aggregate_packed_struct ((*ptr)) != FFI_OK))
51 return FFI_BAD_TYPEDEF;
52
53 FFI_ASSERT (ffi_type_test ((*ptr)));
54
55 arg->size += (*ptr)->size;
56
57 arg->alignment = (arg->alignment > (*ptr)->alignment) ?
58 arg->alignment : (*ptr)->alignment;
59
60 ptr++;
61 }
62
63 if (arg->size == 0)
64 return FFI_BAD_TYPEDEF;
65 else
66 return FFI_OK;
67 }
68
69 int
ffi_prep_args(char * stack,extended_cif * ecif)70 ffi_prep_args (char *stack, extended_cif * ecif)
71 {
72 unsigned int i;
73 unsigned int struct_count = 0;
74 void **p_argv;
75 char *argp;
76 ffi_type **p_arg;
77
78 argp = stack;
79
80 p_argv = ecif->avalue;
81
82 for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
83 (i != 0); i--, p_arg++)
84 {
85 size_t z;
86
87 switch ((*p_arg)->type)
88 {
89 case FFI_TYPE_STRUCT:
90 {
91 z = (*p_arg)->size;
92 if (z <= 4)
93 {
94 memcpy (argp, *p_argv, z);
95 z = 4;
96 }
97 else if (z <= 8)
98 {
99 memcpy (argp, *p_argv, z);
100 z = 8;
101 }
102 else
103 {
104 unsigned int uiLocOnStack;
105 z = sizeof (void *);
106 uiLocOnStack = 4 * ecif->cif->nargs + struct_count;
107 struct_count = struct_count + (*p_arg)->size;
108 *(unsigned int *) argp =
109 (unsigned int) (UINT32 *) (stack + uiLocOnStack);
110 memcpy ((stack + uiLocOnStack), *p_argv, (*p_arg)->size);
111 }
112 break;
113 }
114 default:
115 z = (*p_arg)->size;
116 if (z < sizeof (int))
117 {
118 switch ((*p_arg)->type)
119 {
120 case FFI_TYPE_SINT8:
121 *(signed int *) argp = (signed int) *(SINT8 *) (*p_argv);
122 break;
123
124 case FFI_TYPE_UINT8:
125 *(unsigned int *) argp =
126 (unsigned int) *(UINT8 *) (*p_argv);
127 break;
128
129 case FFI_TYPE_SINT16:
130 *(signed int *) argp = (signed int) *(SINT16 *) (*p_argv);
131 break;
132
133 case FFI_TYPE_UINT16:
134 *(unsigned int *) argp =
135 (unsigned int) *(UINT16 *) (*p_argv);
136 break;
137
138 default:
139 FFI_ASSERT (0);
140 }
141 z = sizeof (int);
142 }
143 else if (z == sizeof (int))
144 *(unsigned int *) argp = (unsigned int) *(UINT32 *) (*p_argv);
145 else
146 memcpy (argp, *p_argv, z);
147 break;
148 }
149 p_argv++;
150 argp += z;
151 }
152
153 return (struct_count);
154 }
155
156 ffi_status FFI_HIDDEN
ffi_prep_cif_core(ffi_cif * cif,ffi_abi abi,unsigned int isvariadic,unsigned int nfixedargs,unsigned int ntotalargs,ffi_type * rtype,ffi_type ** atypes)157 ffi_prep_cif_core (ffi_cif * cif,
158 ffi_abi abi, unsigned int isvariadic,
159 unsigned int nfixedargs, unsigned int ntotalargs,
160 ffi_type * rtype, ffi_type ** atypes)
161 {
162 unsigned bytes = 0;
163 unsigned int i;
164 ffi_type **ptr;
165
166 FFI_ASSERT (cif != NULL);
167 FFI_ASSERT((!isvariadic) || (nfixedargs >= 1));
168 FFI_ASSERT(nfixedargs <= ntotalargs);
169 FFI_ASSERT (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI);
170
171 cif->abi = abi;
172 cif->arg_types = atypes;
173 cif->nargs = ntotalargs;
174 cif->rtype = rtype;
175
176 cif->flags = 0;
177
178 if ((cif->rtype->size == 0)
179 && (initialize_aggregate_packed_struct (cif->rtype) != FFI_OK))
180 return FFI_BAD_TYPEDEF;
181
182 FFI_ASSERT_VALID_TYPE (cif->rtype);
183
184 for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
185 {
186 if (((*ptr)->size == 0)
187 && (initialize_aggregate_packed_struct ((*ptr)) != FFI_OK))
188 return FFI_BAD_TYPEDEF;
189
190 FFI_ASSERT_VALID_TYPE (*ptr);
191
192 if (((*ptr)->alignment - 1) & bytes)
193 bytes = FFI_ALIGN (bytes, (*ptr)->alignment);
194 if ((*ptr)->type == FFI_TYPE_STRUCT)
195 {
196 if ((*ptr)->size > 8)
197 {
198 bytes += (*ptr)->size;
199 bytes += sizeof (void *);
200 }
201 else
202 {
203 if ((*ptr)->size > 4)
204 bytes += 8;
205 else
206 bytes += 4;
207 }
208 }
209 else
210 bytes += STACK_ARG_SIZE ((*ptr)->size);
211 }
212
213 cif->bytes = bytes;
214
215 return ffi_prep_cif_machdep (cif);
216 }
217
218 ffi_status
ffi_prep_cif_machdep(ffi_cif * cif)219 ffi_prep_cif_machdep (ffi_cif * cif)
220 {
221 switch (cif->rtype->type)
222 {
223 case FFI_TYPE_VOID:
224 case FFI_TYPE_STRUCT:
225 case FFI_TYPE_FLOAT:
226 case FFI_TYPE_DOUBLE:
227 case FFI_TYPE_SINT64:
228 case FFI_TYPE_UINT64:
229 cif->flags = (unsigned) cif->rtype->type;
230 break;
231
232 default:
233 cif->flags = FFI_TYPE_INT;
234 break;
235 }
236
237 return FFI_OK;
238 }
239
240 extern void ffi_call_SYSV (int (*)(char *, extended_cif *),
241 extended_cif *,
242 unsigned, unsigned, unsigned *, void (*fn) ())
243 __attribute__ ((__visibility__ ("hidden")));
244
245 void
ffi_call(ffi_cif * cif,void (* fn)(),void * rvalue,void ** avalue)246 ffi_call (ffi_cif * cif, void (*fn) (), void *rvalue, void **avalue)
247 {
248 extended_cif ecif;
249
250 ecif.cif = cif;
251 ecif.avalue = avalue;
252
253 if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT))
254 {
255 ecif.rvalue = alloca (cif->rtype->size);
256 }
257 else
258 ecif.rvalue = rvalue;
259
260 switch (cif->abi)
261 {
262 case FFI_SYSV:
263 ffi_call_SYSV (ffi_prep_args, &ecif, cif->bytes,
264 cif->flags, ecif.rvalue, fn);
265 break;
266 default:
267 FFI_ASSERT (0);
268 break;
269 }
270 }
271
272 /* Because the following variables are not exported outside libffi, we
273 mark them hidden. */
274
275 /* Assembly code for the jump stub. */
276 extern const char ffi_cris_trampoline_template[]
277 __attribute__ ((__visibility__ ("hidden")));
278
279 /* Offset into ffi_cris_trampoline_template of where to put the
280 ffi_prep_closure_inner function. */
281 extern const int ffi_cris_trampoline_fn_offset
282 __attribute__ ((__visibility__ ("hidden")));
283
284 /* Offset into ffi_cris_trampoline_template of where to put the
285 closure data. */
286 extern const int ffi_cris_trampoline_closure_offset
287 __attribute__ ((__visibility__ ("hidden")));
288
289 /* This function is sibling-called (jumped to) by the closure
290 trampoline. We get R10..R13 at PARAMS[0..3] and a copy of [SP] at
291 PARAMS[4] to simplify handling of a straddling parameter. A copy
292 of R9 is at PARAMS[5] and SP at PARAMS[6]. These parameters are
293 put at the appropriate place in CLOSURE which is then executed and
294 the return value is passed back to the caller. */
295
296 static unsigned long long
ffi_prep_closure_inner(void ** params,ffi_closure * closure)297 ffi_prep_closure_inner (void **params, ffi_closure* closure)
298 {
299 char *register_args = (char *) params;
300 void *struct_ret = params[5];
301 char *stack_args = params[6];
302 char *ptr = register_args;
303 ffi_cif *cif = closure->cif;
304 ffi_type **arg_types = cif->arg_types;
305
306 /* Max room needed is number of arguments as 64-bit values. */
307 void **avalue = alloca (closure->cif->nargs * sizeof(void *));
308 int i;
309 int doing_regs;
310 long long llret = 0;
311
312 /* Find the address of each argument. */
313 for (i = 0, doing_regs = 1; i < cif->nargs; i++)
314 {
315 /* Types up to and including 8 bytes go by-value. */
316 if (arg_types[i]->size <= 4)
317 {
318 avalue[i] = ptr;
319 ptr += 4;
320 }
321 else if (arg_types[i]->size <= 8)
322 {
323 avalue[i] = ptr;
324 ptr += 8;
325 }
326 else
327 {
328 FFI_ASSERT (arg_types[i]->type == FFI_TYPE_STRUCT);
329
330 /* Passed by-reference, so copy the pointer. */
331 avalue[i] = *(void **) ptr;
332 ptr += 4;
333 }
334
335 /* If we've handled more arguments than fit in registers, start
336 looking at the those passed on the stack. Step over the
337 first one if we had a straddling parameter. */
338 if (doing_regs && ptr >= register_args + 4*4)
339 {
340 ptr = stack_args + ((ptr > register_args + 4*4) ? 4 : 0);
341 doing_regs = 0;
342 }
343 }
344
345 /* Invoke the closure. */
346 (closure->fun) (cif,
347
348 cif->rtype->type == FFI_TYPE_STRUCT
349 /* The caller allocated space for the return
350 structure, and passed a pointer to this space in
351 R9. */
352 ? struct_ret
353
354 /* We take advantage of being able to ignore that
355 the high part isn't set if the return value is
356 not in R10:R11, but in R10 only. */
357 : (void *) &llret,
358
359 avalue, closure->user_data);
360
361 return llret;
362 }
363
364 /* API function: Prepare the trampoline. */
365
366 ffi_status
ffi_prep_closure_loc(ffi_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * codeloc)367 ffi_prep_closure_loc (ffi_closure* closure,
368 ffi_cif* cif,
369 void (*fun)(ffi_cif *, void *, void **, void*),
370 void *user_data,
371 void *codeloc)
372 {
373 void *innerfn = ffi_prep_closure_inner;
374 FFI_ASSERT (cif->abi == FFI_SYSV);
375 closure->cif = cif;
376 closure->user_data = user_data;
377 closure->fun = fun;
378 memcpy (closure->tramp, ffi_cris_trampoline_template,
379 FFI_CRIS_TRAMPOLINE_CODE_PART_SIZE);
380 memcpy (closure->tramp + ffi_cris_trampoline_fn_offset,
381 &innerfn, sizeof (void *));
382 memcpy (closure->tramp + ffi_cris_trampoline_closure_offset,
383 &codeloc, sizeof (void *));
384
385 return FFI_OK;
386 }
387