1 #ifdef __i386__
2 /* -----------------------------------------------------------------------
3 ffi.c - Copyright (c) 1996, 1998, 1999, 2001 Red Hat, Inc.
4 Copyright (c) 2002 Ranjit Mathew
5 Copyright (c) 2002 Bo Thorsen
6 Copyright (c) 2002 Roger Sayle
7
8 x86 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, EXPRESS
22 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24 IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
25 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
26 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 OTHER DEALINGS IN THE SOFTWARE.
28 ----------------------------------------------------------------------- */
29
30 #include <ffi.h>
31 #include <ffi_common.h>
32
33 #include <stdlib.h>
34
35 /* ffi_prep_args is called by the assembly routine once stack space
36 has been allocated for the function's arguments */
37
38 void ffi_prep_args(char *stack, extended_cif *ecif);
39
ffi_prep_args(char * stack,extended_cif * ecif)40 void ffi_prep_args(char *stack, extended_cif *ecif)
41 {
42 register unsigned int i;
43 register void **p_argv;
44 register char *argp;
45 register ffi_type **p_arg;
46
47 argp = stack;
48
49 if (ecif->cif->flags == FFI_TYPE_STRUCT)
50 {
51 *(void **) argp = ecif->rvalue;
52 argp += 4;
53 }
54
55 p_argv = ecif->avalue;
56
57 for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
58 i != 0;
59 i--, p_arg++)
60 {
61 size_t z;
62
63 /* Align if necessary */
64 if ((sizeof(int) - 1) & (unsigned) argp)
65 argp = (char *) ALIGN(argp, sizeof(int));
66
67 z = (*p_arg)->size;
68 if (z < sizeof(int))
69 {
70 z = sizeof(int);
71 switch ((*p_arg)->type)
72 {
73 case FFI_TYPE_SINT8:
74 *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
75 break;
76
77 case FFI_TYPE_UINT8:
78 *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
79 break;
80
81 case FFI_TYPE_SINT16:
82 *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
83 break;
84
85 case FFI_TYPE_UINT16:
86 *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
87 break;
88
89 case FFI_TYPE_SINT32:
90 *(signed int *) argp = (signed int)*(SINT32 *)(* p_argv);
91 break;
92
93 case FFI_TYPE_UINT32:
94 *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
95 break;
96
97 case FFI_TYPE_STRUCT:
98 *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
99 break;
100
101 default:
102 FFI_ASSERT(0);
103 }
104 }
105 else
106 {
107 memcpy(argp, *p_argv, z);
108 }
109 p_argv++;
110 argp += z;
111 }
112
113 return;
114 }
115
116 /* Perform machine dependent cif processing */
ffi_prep_cif_machdep(ffi_cif * cif)117 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
118 {
119 /* Set the return type flag */
120 switch (cif->rtype->type)
121 {
122 case FFI_TYPE_VOID:
123 #ifdef X86
124 case FFI_TYPE_STRUCT:
125 case FFI_TYPE_UINT8:
126 case FFI_TYPE_UINT16:
127 case FFI_TYPE_SINT8:
128 case FFI_TYPE_SINT16:
129 #endif
130
131 case FFI_TYPE_SINT64:
132 case FFI_TYPE_FLOAT:
133 case FFI_TYPE_DOUBLE:
134 case FFI_TYPE_LONGDOUBLE:
135 cif->flags = (unsigned) cif->rtype->type;
136 break;
137
138 case FFI_TYPE_UINT64:
139 cif->flags = FFI_TYPE_SINT64;
140 break;
141
142 #ifndef X86
143 case FFI_TYPE_STRUCT:
144 if (cif->rtype->size == 1)
145 {
146 cif->flags = FFI_TYPE_SINT8; /* same as char size */
147 }
148 else if (cif->rtype->size == 2)
149 {
150 cif->flags = FFI_TYPE_SINT16; /* same as short size */
151 }
152 else if (cif->rtype->size == 4)
153 {
154 cif->flags = FFI_TYPE_INT; /* same as int type */
155 }
156 else if (cif->rtype->size == 8)
157 {
158 cif->flags = FFI_TYPE_SINT64; /* same as int64 type */
159 }
160 else
161 {
162 cif->flags = FFI_TYPE_STRUCT;
163 }
164 break;
165 #endif
166
167 default:
168 cif->flags = FFI_TYPE_INT;
169 break;
170 }
171
172 #ifdef X86_DARWIN
173 cif->bytes = (cif->bytes + 15) & ~0xF;
174 #endif
175
176 return FFI_OK;
177 }
178
179 extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
180 unsigned, unsigned, unsigned *, void (*fn)());
181
182 #ifdef X86_WIN32
183 extern void ffi_call_STDCALL(void (*)(char *, extended_cif *), extended_cif *,
184 unsigned, unsigned, unsigned *, void (*fn)());
185
186 #endif /* X86_WIN32 */
187
ffi_call(ffi_cif * cif,void (* fn)(),void * rvalue,void ** avalue)188 void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
189 {
190 extended_cif ecif;
191
192 ecif.cif = cif;
193 ecif.avalue = avalue;
194
195 /* If the return value is a struct and we don't have a return */
196 /* value address then we need to make one */
197
198 if ((rvalue == NULL) &&
199 (cif->flags == FFI_TYPE_STRUCT))
200 {
201 ecif.rvalue = alloca(cif->rtype->size);
202 }
203 else
204 ecif.rvalue = rvalue;
205
206
207 switch (cif->abi)
208 {
209 case FFI_SYSV:
210 ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
211 fn);
212 break;
213 #ifdef X86_WIN32
214 case FFI_STDCALL:
215 ffi_call_STDCALL(ffi_prep_args, &ecif, cif->bytes, cif->flags,
216 ecif.rvalue, fn);
217 break;
218 #endif /* X86_WIN32 */
219 default:
220 FFI_ASSERT(0);
221 break;
222 }
223 }
224
225
226 /** private members **/
227
228 static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
229 void** args, ffi_cif* cif);
230 void FFI_HIDDEN ffi_closure_SYSV (ffi_closure *)
231 __attribute__ ((regparm(1)));
232 unsigned int FFI_HIDDEN ffi_closure_SYSV_inner (ffi_closure *, void **, void *)
233 __attribute__ ((regparm(1)));
234 void FFI_HIDDEN ffi_closure_raw_SYSV (ffi_raw_closure *)
235 __attribute__ ((regparm(1)));
236
237 /* This function is jumped to by the trampoline */
238
239 unsigned int FFI_HIDDEN
ffi_closure_SYSV_inner(closure,respp,args)240 ffi_closure_SYSV_inner (closure, respp, args)
241 ffi_closure *closure;
242 void **respp;
243 void *args;
244 {
245 // our various things...
246 ffi_cif *cif;
247 void **arg_area;
248
249 cif = closure->cif;
250 arg_area = (void**) alloca (cif->nargs * sizeof (void*));
251
252 /* this call will initialize ARG_AREA, such that each
253 * element in that array points to the corresponding
254 * value on the stack; and if the function returns
255 * a structure, it will re-set RESP to point to the
256 * structure return address. */
257
258 ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif);
259
260 (closure->fun) (cif, *respp, arg_area, closure->user_data);
261
262 return cif->flags;
263 }
264
265 static void
ffi_prep_incoming_args_SYSV(char * stack,void ** rvalue,void ** avalue,ffi_cif * cif)266 ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue,
267 ffi_cif *cif)
268 {
269 register unsigned int i;
270 register void **p_argv;
271 register char *argp;
272 register ffi_type **p_arg;
273
274 argp = stack;
275
276 if ( cif->flags == FFI_TYPE_STRUCT ) {
277 *rvalue = *(void **) argp;
278 argp += 4;
279 }
280
281 p_argv = avalue;
282
283 for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
284 {
285 size_t z;
286
287 /* Align if necessary */
288 if ((sizeof(int) - 1) & (unsigned) argp) {
289 argp = (char *) ALIGN(argp, sizeof(int));
290 }
291
292 z = (*p_arg)->size;
293
294 /* because we're little endian, this is what it turns into. */
295
296 *p_argv = (void*) argp;
297
298 p_argv++;
299 argp += z;
300 }
301
302 return;
303 }
304
305 /* How to make a trampoline. Derived from gcc/config/i386/i386.c. */
306
307 #define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \
308 ({ unsigned char *__tramp = (unsigned char*)(TRAMP); \
309 unsigned int __fun = (unsigned int)(FUN); \
310 unsigned int __ctx = (unsigned int)(CTX); \
311 unsigned int __dis = __fun - (__ctx + FFI_TRAMPOLINE_SIZE); \
312 *(unsigned char*) &__tramp[0] = 0xb8; \
313 *(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
314 *(unsigned char *) &__tramp[5] = 0xe9; \
315 *(unsigned int*) &__tramp[6] = __dis; /* jmp __fun */ \
316 })
317
318
319 /* the cif must already be prep'ed */
320 ffi_status
ffi_prep_closure(ffi_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data)321 ffi_prep_closure (ffi_closure* closure,
322 ffi_cif* cif,
323 void (*fun)(ffi_cif*,void*,void**,void*),
324 void *user_data)
325 {
326 if (cif->abi != FFI_SYSV)
327 return FFI_BAD_ABI;
328
329 FFI_INIT_TRAMPOLINE (&closure->tramp[0], \
330 &ffi_closure_SYSV, \
331 (void*)closure);
332
333 closure->cif = cif;
334 closure->user_data = user_data;
335 closure->fun = fun;
336
337 return FFI_OK;
338 }
339
340 /* ------- Native raw API support -------------------------------- */
341
342 #if !FFI_NO_RAW_API
343
344 ffi_status
ffi_prep_raw_closure_loc(ffi_raw_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,ffi_raw *,void *),void * user_data,void * codeloc)345 ffi_prep_raw_closure_loc (ffi_raw_closure* closure,
346 ffi_cif* cif,
347 void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
348 void *user_data,
349 void *codeloc)
350 {
351 int i;
352
353 FFI_ASSERT (cif->abi == FFI_SYSV);
354
355 // we currently don't support certain kinds of arguments for raw
356 // closures. This should be implemented by a separate assembly language
357 // routine, since it would require argument processing, something we
358 // don't do now for performance.
359
360 for (i = cif->nargs-1; i >= 0; i--)
361 {
362 FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_STRUCT);
363 FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE);
364 }
365
366
367 FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV,
368 codeloc);
369
370 closure->cif = cif;
371 closure->user_data = user_data;
372 closure->fun = fun;
373
374 return FFI_OK;
375 }
376
377 static void
ffi_prep_args_raw(char * stack,extended_cif * ecif)378 ffi_prep_args_raw(char *stack, extended_cif *ecif)
379 {
380 memcpy (stack, ecif->avalue, ecif->cif->bytes);
381 }
382
383 /* we borrow this routine from libffi (it must be changed, though, to
384 * actually call the function passed in the first argument. as of
385 * libffi-1.20, this is not the case.)
386 */
387
388 extern void
389 ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *, unsigned,
390 unsigned, unsigned *, void (*fn)());
391
392 #ifdef X86_WIN32
393 extern void
394 ffi_call_STDCALL(void (*)(char *, extended_cif *), extended_cif *, unsigned,
395 unsigned, unsigned *, void (*fn)());
396 #endif /* X86_WIN32 */
397
398 void
ffi_raw_call(ffi_cif * cif,void (* fn)(),void * rvalue,ffi_raw * fake_avalue)399 ffi_raw_call(ffi_cif *cif, void (*fn)(), void *rvalue, ffi_raw *fake_avalue)
400 {
401 extended_cif ecif;
402 void **avalue = (void **)fake_avalue;
403
404 ecif.cif = cif;
405 ecif.avalue = avalue;
406
407 /* If the return value is a struct and we don't have a return */
408 /* value address then we need to make one */
409
410 if ((rvalue == NULL) &&
411 (cif->rtype->type == FFI_TYPE_STRUCT))
412 {
413 ecif.rvalue = alloca(cif->rtype->size);
414 }
415 else
416 ecif.rvalue = rvalue;
417
418
419 switch (cif->abi)
420 {
421 case FFI_SYSV:
422 ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
423 ecif.rvalue, fn);
424 break;
425 #ifdef X86_WIN32
426 case FFI_STDCALL:
427 ffi_call_STDCALL(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
428 ecif.rvalue, fn);
429 break;
430 #endif /* X86_WIN32 */
431 default:
432 FFI_ASSERT(0);
433 break;
434 }
435 }
436
437 #endif
438 #endif // __i386__
439