Skip to content
Newer
Older
100644 315 lines (246 sloc) 7.83 KB
3ac848f @parmanoir Initial commit
authored Aug 30, 2009
1
2 #if !TARGET_IPHONE_SIMULATOR
3
4
5 /* -----------------------------------------------------------------------
6 ffi.c - Copyright (c) 1998, 2008 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 /* ffi_prep_args is called by the assembly routine once stack space
37 has been allocated for the function's arguments */
38
39 void ffi_prep_args(char *stack, extended_cif *ecif)
40 {
41 register unsigned int i;
42 register void **p_argv;
43 register char *argp;
44 register ffi_type **p_arg;
45
46 argp = stack;
47
48 if ( ecif->cif->flags == FFI_TYPE_STRUCT ) {
49 *(void **) argp = ecif->rvalue;
50 argp += 4;
51 }
52
53 p_argv = ecif->avalue;
54
55 for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
56 (i != 0);
57 i--, p_arg++)
58 {
59 size_t z;
60
61 /* Align if necessary */
62 if (((*p_arg)->alignment - 1) & (unsigned) argp) {
63 argp = (char *) ALIGN(argp, (*p_arg)->alignment);
64 }
65
66 if ((*p_arg)->type == FFI_TYPE_STRUCT)
67 argp = (char *) ALIGN(argp, 4);
68
69 z = (*p_arg)->size;
70 if (z < sizeof(int))
71 {
72 z = sizeof(int);
73 switch ((*p_arg)->type)
74 {
75 case FFI_TYPE_SINT8:
76 *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
77 break;
78
79 case FFI_TYPE_UINT8:
80 *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
81 break;
82
83 case FFI_TYPE_SINT16:
84 *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
85 break;
86
87 case FFI_TYPE_UINT16:
88 *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
89 break;
90
91 case FFI_TYPE_STRUCT:
92 memcpy(argp, *p_argv, (*p_arg)->size);
93 break;
94
95 default:
96 FFI_ASSERT(0);
97 }
98 }
99 else if (z == sizeof(int))
100 {
101 *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
102 }
103 else
104 {
105 memcpy(argp, *p_argv, z);
106 }
107 p_argv++;
108 argp += z;
109 }
110
111 return;
112 }
113
114 /* Perform machine dependent cif processing */
115 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
116 {
117 /* Round the stack up to a multiple of 8 bytes. This isn't needed
118 everywhere, but it is on some platforms, and it doesn't harm anything
119 when it isn't needed. */
120 cif->bytes = (cif->bytes + 7) & ~7;
121
122 /* Set the return type flag */
123 switch (cif->rtype->type)
124 {
125 case FFI_TYPE_VOID:
126 case FFI_TYPE_FLOAT:
127 case FFI_TYPE_DOUBLE:
128 cif->flags = (unsigned) cif->rtype->type;
129 break;
130
131 case FFI_TYPE_SINT64:
132 case FFI_TYPE_UINT64:
133 cif->flags = (unsigned) FFI_TYPE_SINT64;
134 break;
135
136 case FFI_TYPE_STRUCT:
137 if (cif->rtype->size <= 4)
138 /* A Composite Type not larger than 4 bytes is returned in r0. */
139 cif->flags = (unsigned)FFI_TYPE_INT;
140 else
141 /* A Composite Type larger than 4 bytes, or whose size cannot
142 be determined statically ... is stored in memory at an
143 address passed [in r0]. */
144 cif->flags = (unsigned)FFI_TYPE_STRUCT;
145 break;
146
147 default:
148 cif->flags = FFI_TYPE_INT;
149 break;
150 }
151
152 return FFI_OK;
153 }
154
155 extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
156 unsigned, unsigned, unsigned *, void (*fn)(void));
157
158 void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
159 {
160 extended_cif ecif;
161
162 int small_struct = (cif->flags == FFI_TYPE_INT
163 && cif->rtype->type == FFI_TYPE_STRUCT);
164
165 ecif.cif = cif;
166 ecif.avalue = avalue;
167
168 unsigned int temp;
169
170 /* If the return value is a struct and we don't have a return */
171 /* value address then we need to make one */
172
173 if ((rvalue == NULL) &&
174 (cif->flags == FFI_TYPE_STRUCT))
175 {
176 ecif.rvalue = alloca(cif->rtype->size);
177 }
178 else if (small_struct)
179 ecif.rvalue = &temp;
180 else
181 ecif.rvalue = rvalue;
182
183 switch (cif->abi)
184 {
185 case FFI_SYSV:
186 ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
187 fn);
188
189 break;
190 default:
191 FFI_ASSERT(0);
192 break;
193 }
194 if (small_struct)
195 memcpy (rvalue, &temp, cif->rtype->size);
196 }
197
198 /** private members **/
199
200 static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
201 void** args, ffi_cif* cif);
202
203 void ffi_closure_SYSV (ffi_closure *);
204
205 /* This function is jumped to by the trampoline */
206
207 unsigned int
208 ffi_closure_SYSV_inner (closure, respp, args)
209 ffi_closure *closure;
210 void **respp;
211 void *args;
212 {
213 // our various things...
214 ffi_cif *cif;
215 void **arg_area;
216
217 cif = closure->cif;
218 arg_area = (void**) alloca (cif->nargs * sizeof (void*));
219
220 /* this call will initialize ARG_AREA, such that each
221 * element in that array points to the corresponding
222 * value on the stack; and if the function returns
223 * a structure, it will re-set RESP to point to the
224 * structure return address. */
225
226 ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif);
227
228 (closure->fun) (cif, *respp, arg_area, closure->user_data);
229
230 return cif->flags;
231 }
232
233 /*@-exportheader@*/
234 static void
235 ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
236 void **avalue, ffi_cif *cif)
237 /*@=exportheader@*/
238 {
239 register unsigned int i;
240 register void **p_argv;
241 register char *argp;
242 register ffi_type **p_arg;
243
244 argp = stack;
245
246 if ( cif->flags == FFI_TYPE_STRUCT ) {
247 *rvalue = *(void **) argp;
248 argp += 4;
249 }
250
251 p_argv = avalue;
252
253 for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
254 {
255 size_t z;
256
257 size_t alignment = (*p_arg)->alignment;
258 if (alignment < 4)
259 alignment = 4;
260 /* Align if necessary */
261 if ((alignment - 1) & (unsigned) argp) {
262 argp = (char *) ALIGN(argp, alignment);
263 }
264
265 z = (*p_arg)->size;
266
267 /* because we're little endian, this is what it turns into. */
268
269 *p_argv = (void*) argp;
270
271 p_argv++;
272 argp += z;
273 }
274
275 return;
276 }
277
278 /* How to make a trampoline. */
279
280 #define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \
281 ({ unsigned char *__tramp = (unsigned char*)(TRAMP); \
282 unsigned int __fun = (unsigned int)(FUN); \
283 unsigned int __ctx = (unsigned int)(CTX); \
284 *(unsigned int*) &__tramp[0] = 0xe92d000f; /* stmfd sp!, {r0-r3} */ \
285 *(unsigned int*) &__tramp[4] = 0xe59f0000; /* ldr r0, [pc] */ \
286 *(unsigned int*) &__tramp[8] = 0xe59ff000; /* ldr pc, [pc] */ \
287 *(unsigned int*) &__tramp[12] = __ctx; \
288 *(unsigned int*) &__tramp[16] = __fun; \
289 __clear_cache((&__tramp[0]), (&__tramp[19])); \
290 })
291
292
293 /* the cif must already be prep'ed */
294
295 ffi_status
296 ffi_prep_closure_loc (ffi_closure* closure,
297 ffi_cif* cif,
298 void (*fun)(ffi_cif*,void*,void**,void*),
299 void *user_data,
300 void *codeloc)
301 {
302 FFI_ASSERT (cif->abi == FFI_SYSV);
303
304 FFI_INIT_TRAMPOLINE (&closure->tramp[0], \
305 &ffi_closure_SYSV, \
306 codeloc);
307
308 closure->cif = cif;
309 closure->user_data = user_data;
310 closure->fun = fun;
311
312 return FFI_OK;
313 }
314
315 #endif
Something went wrong with that request. Please try again.