1 /* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 1996, 1998, 1999 Cygnus Solutions
4 x86 Foreign Function Interface
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:
14 The above copyright notice and this permission notice shall be included
15 in all copies or substantial portions of the Software.
17 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 OTHER DEALINGS IN THE SOFTWARE.
24 ----------------------------------------------------------------------- */
29 #include <ffi_common.h>
33 /* ffi_prep_args is called by the assembly routine once stack space
34 has been allocated for the function's arguments */
37 void ffi_prep_args(char *stack, extended_cif *ecif)
40 register unsigned int i;
41 register void **p_argv;
43 register ffi_type **p_arg;
47 if (ecif->cif->rtype->type == FFI_TYPE_STRUCT)
49 *(void **) argp = ecif->rvalue;
53 p_argv = ecif->avalue;
55 for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
61 /* Align if necessary */
62 if (((*p_arg)->alignment - 1) & (unsigned) argp)
63 argp = (char *) ALIGN(argp, (*p_arg)->alignment);
69 switch ((*p_arg)->type)
72 *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
76 *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
80 *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
84 *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
88 *(signed int *) argp = (signed int)*(SINT32 *)(* p_argv);
92 *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
96 *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
105 memcpy(argp, *p_argv, z);
114 /* Perform machine dependent cif processing */
115 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
117 /* Set the return type flag */
118 switch (cif->rtype->type)
121 case FFI_TYPE_STRUCT:
122 case FFI_TYPE_SINT64:
124 case FFI_TYPE_DOUBLE:
125 case FFI_TYPE_LONGDOUBLE:
126 cif->flags = (unsigned) cif->rtype->type;
129 case FFI_TYPE_UINT64:
130 cif->flags = FFI_TYPE_SINT64;
134 cif->flags = FFI_TYPE_INT;
143 extern void ffi_call_SYSV(void (*)(char *, extended_cif *),
144 /*@out@*/ extended_cif *,
146 /*@out@*/ unsigned *,
151 void ffi_call(/*@dependent@*/ ffi_cif *cif,
153 /*@out@*/ void *rvalue,
154 /*@dependent@*/ void **avalue)
159 ecif.avalue = avalue;
161 /* If the return value is a struct and we don't have a return */
162 /* value address then we need to make one */
164 if ((rvalue == NULL) &&
165 (cif->rtype->type == FFI_TYPE_STRUCT))
168 ecif.rvalue = alloca(cif->rtype->size);
172 ecif.rvalue = rvalue;
179 ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes,
180 cif->flags, ecif.rvalue, fn);
190 /** private members **/
192 static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
193 void** args, ffi_cif* cif);
194 static void ffi_closure_SYSV ();
195 static void ffi_closure_raw_SYSV ();
197 /* This function is jumped to by the trampoline, on entry, %ecx (a
198 * caller-save register) holds the address of the closure.
199 * Clearly, this requires __GNUC__, so perhaps we should translate this
200 * into an assembly file if this is to be distributed with ffi.
206 // this is our return value storage
209 // our various things...
213 ffi_closure *closure;
214 unsigned short rtype;
215 void *resp = (void*)&res;
217 /* grab the trampoline context pointer */
218 asm ("movl %%ecx,%0" : "=r" (closure));
221 arg_area = (void**) alloca (cif->nargs * sizeof (void*));
222 asm ("leal 8(%%ebp),%0" : "=q" (args));
224 /* this call will initialize ARG_AREA, such that each
225 * element in that array points to the corresponding
226 * value on the stack; and if the function returns
227 * a structure, it will re-set RESP to point to the
228 * structure return address. */
230 ffi_prep_incoming_args_SYSV(args, (void**)&resp, arg_area, cif);
232 (closure->fun) (cif, resp, arg_area, closure->user_data);
236 /* now, do a generic return based on the value of rtype */
237 if (rtype == FFI_TYPE_INT)
239 asm ("movl (%0),%%eax" : : "r" (resp) : "eax");
241 else if (rtype == FFI_TYPE_FLOAT)
243 asm ("flds (%0)" : : "r" (resp) : "st" );
245 else if (rtype == FFI_TYPE_DOUBLE)
247 asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" );
249 else if (rtype == FFI_TYPE_LONGDOUBLE)
251 asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" );
253 else if (rtype == FFI_TYPE_SINT64)
255 asm ("movl 0(%0),%%eax;"
264 ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
265 void **avalue, ffi_cif *cif)
268 register unsigned int i;
269 register void **p_argv;
271 register ffi_type **p_arg;
275 if ( cif->rtype->type == FFI_TYPE_STRUCT ) {
276 *rvalue = *(void **) argp;
282 for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
286 /* Align if necessary */
287 if (((*p_arg)->alignment - 1) & (unsigned) argp) {
288 argp = (char *) ALIGN(argp, (*p_arg)->alignment);
293 /* because we're little endian, this is what it turns into. */
295 *p_argv = (void*) argp;
304 /* How to make a trampoline. Derived from gcc/config/i386/i386.c. */
306 #define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \
307 ({ unsigned char *__tramp = (unsigned char*)(TRAMP); \
308 unsigned int __fun = (unsigned int)(FUN); \
309 unsigned int __ctx = (unsigned int)(CTX); \
310 unsigned int __dis = __fun - ((unsigned int) __tramp + 10); \
311 *(unsigned char*) &__tramp[0] = 0xb9; \
312 *(unsigned int*) &__tramp[1] = __ctx; \
313 *(unsigned char*) &__tramp[5] = 0xe9; \
314 *(unsigned int*) &__tramp[6] = __dis; \
318 /* the cif must already be prep'ed */
321 ffi_prep_closure (ffi_closure* closure,
323 void (*fun)(ffi_cif*,void*,void**,void*),
326 FFI_ASSERT (cif->abi == FFI_SYSV);
328 FFI_INIT_TRAMPOLINE (&closure->tramp[0], \
333 closure->user_data = user_data;
339 /* ------- Native raw API support -------------------------------- */
344 ffi_closure_raw_SYSV ()
346 // this is our return value storage
349 // our various things...
353 ffi_raw_closure *closure;
354 unsigned short rtype;
355 void *resp = (void*)&res;
357 /* grab the trampoline context pointer */
358 asm ("movl %%ecx,%0" : "=r" (closure));
360 /* take the argument pointer */
361 asm ("leal 8(%%ebp),%0" : "=q" (args));
366 /* the SYSV/X86 abi matches the RAW API exactly, well.. almost */
367 raw_args = (ffi_raw*) args;
369 (closure->fun) (cif, resp, raw_args, closure->user_data);
373 /* now, do a generic return based on the value of rtype */
374 if (rtype == FFI_TYPE_INT)
376 asm ("movl (%0),%%eax" : : "r" (resp) : "eax");
378 else if (rtype == FFI_TYPE_FLOAT)
380 asm ("flds (%0)" : : "r" (resp) : "st" );
382 else if (rtype == FFI_TYPE_DOUBLE)
384 asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" );
386 else if (rtype == FFI_TYPE_LONGDOUBLE)
388 asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" );
390 else if (rtype == FFI_TYPE_SINT64)
392 asm ("movl 0(%0),%%eax; movl 4(%0),%%edx"
402 ffi_prep_raw_closure (ffi_raw_closure* closure,
404 void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
409 FFI_ASSERT (cif->abi == FFI_SYSV);
411 // we currently don't support certain kinds of arguments for raw
412 // closures. This should be implemented by a separate assembly language
413 // routine, since it would require argument processing, something we
414 // don't do now for performance.
416 for (i = cif->nargs-1; i >= 0; i--)
418 FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_STRUCT);
419 FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE);
423 FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV,
427 closure->user_data = user_data;
434 ffi_prep_args_raw(char *stack, extended_cif *ecif)
436 memcpy (stack, ecif->avalue, ecif->cif->bytes);
439 /* we borrow this routine from libffi (it must be changed, though, to
440 * actually call the function passed in the first argument. as of
441 * libffi-1.20, this is not the case.)
445 ffi_call_SYSV(void (*)(char *, extended_cif *),
446 /*@out@*/ extended_cif *,
448 /*@out@*/ unsigned *,
452 ffi_raw_call(/*@dependent@*/ ffi_cif *cif,
454 /*@out@*/ void *rvalue,
455 /*@dependent@*/ ffi_raw *fake_avalue)
458 void **avalue = (void **)fake_avalue;
461 ecif.avalue = avalue;
463 /* If the return value is a struct and we don't have a return */
464 /* value address then we need to make one */
466 if ((rvalue == NULL) &&
467 (cif->rtype->type == FFI_TYPE_STRUCT))
470 ecif.rvalue = alloca(cif->rtype->size);
474 ecif.rvalue = rvalue;
481 ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes,
482 cif->flags, ecif.rvalue, fn);
493 #endif /* __x86_64__ */