2009-06-04 Andrew Haley <aph@redhat.com>
[official-gcc.git] / libffi / src / x86 / ffi.c
blob5e09bedbaf23d63129d758cac754e507b24f460f
1 /* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 1996, 1998, 1999, 2001, 2007 Red Hat, Inc.
3 Copyright (c) 2002 Ranjit Mathew
4 Copyright (c) 2002 Bo Thorsen
5 Copyright (c) 2002 Roger Sayle
6 Copyright (C) 2008 Free Software Foundation, Inc.
8 x86 Foreign Function Interface
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:
18 The above copyright notice and this permission notice shall be included
19 in all copies or substantial portions of the Software.
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 ----------------------------------------------------------------------- */
31 #ifndef __x86_64__
33 #include <ffi.h>
34 #include <ffi_common.h>
36 #include <stdlib.h>
38 /* ffi_prep_args is called by the assembly routine once stack space
39 has been allocated for the function's arguments */
41 void ffi_prep_args(char *stack, extended_cif *ecif)
43 register unsigned int i;
44 register void **p_argv;
45 register char *argp;
46 register ffi_type **p_arg;
48 argp = stack;
50 if (ecif->cif->flags == FFI_TYPE_STRUCT)
52 *(void **) argp = ecif->rvalue;
53 argp += 4;
56 p_argv = ecif->avalue;
58 for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
59 i != 0;
60 i--, p_arg++)
62 size_t z;
64 /* Align if necessary */
65 if ((sizeof(int) - 1) & (unsigned) argp)
66 argp = (char *) ALIGN(argp, sizeof(int));
68 z = (*p_arg)->size;
69 if (z < sizeof(int))
71 z = sizeof(int);
72 switch ((*p_arg)->type)
74 case FFI_TYPE_SINT8:
75 *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
76 break;
78 case FFI_TYPE_UINT8:
79 *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
80 break;
82 case FFI_TYPE_SINT16:
83 *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
84 break;
86 case FFI_TYPE_UINT16:
87 *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
88 break;
90 case FFI_TYPE_SINT32:
91 *(signed int *) argp = (signed int)*(SINT32 *)(* p_argv);
92 break;
94 case FFI_TYPE_UINT32:
95 *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
96 break;
98 case FFI_TYPE_STRUCT:
99 *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
100 break;
102 default:
103 FFI_ASSERT(0);
106 else
108 memcpy(argp, *p_argv, z);
110 p_argv++;
111 argp += z;
114 return;
117 /* Perform machine dependent cif processing */
118 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
120 /* Set the return type flag */
121 switch (cif->rtype->type)
123 case FFI_TYPE_VOID:
124 #ifdef X86
125 case FFI_TYPE_STRUCT:
126 #endif
127 #if defined(X86) || defined(X86_DARWIN)
128 case FFI_TYPE_UINT8:
129 case FFI_TYPE_UINT16:
130 case FFI_TYPE_SINT8:
131 case FFI_TYPE_SINT16:
132 #endif
134 case FFI_TYPE_SINT64:
135 case FFI_TYPE_FLOAT:
136 case FFI_TYPE_DOUBLE:
137 case FFI_TYPE_LONGDOUBLE:
138 cif->flags = (unsigned) cif->rtype->type;
139 break;
141 case FFI_TYPE_UINT64:
142 cif->flags = FFI_TYPE_SINT64;
143 break;
145 #ifndef X86
146 case FFI_TYPE_STRUCT:
147 if (cif->rtype->size == 1)
149 cif->flags = FFI_TYPE_SMALL_STRUCT_1B; /* same as char size */
151 else if (cif->rtype->size == 2)
153 cif->flags = FFI_TYPE_SMALL_STRUCT_2B; /* same as short size */
155 else if (cif->rtype->size == 4)
157 cif->flags = FFI_TYPE_INT; /* same as int type */
159 else if (cif->rtype->size == 8)
161 cif->flags = FFI_TYPE_SINT64; /* same as int64 type */
163 else
165 cif->flags = FFI_TYPE_STRUCT;
167 break;
168 #endif
170 default:
171 cif->flags = FFI_TYPE_INT;
172 break;
175 #ifdef X86_DARWIN
176 cif->bytes = (cif->bytes + 15) & ~0xF;
177 #endif
179 return FFI_OK;
182 extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
183 unsigned, unsigned, unsigned *, void (*fn)());
185 #ifdef X86_WIN32
186 extern void ffi_call_STDCALL(void (*)(char *, extended_cif *), extended_cif *,
187 unsigned, unsigned, unsigned *, void (*fn)());
189 #endif /* X86_WIN32 */
191 void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
193 extended_cif ecif;
195 ecif.cif = cif;
196 ecif.avalue = avalue;
198 /* If the return value is a struct and we don't have a return */
199 /* value address then we need to make one */
201 if ((rvalue == NULL) &&
202 (cif->flags == FFI_TYPE_STRUCT))
204 ecif.rvalue = alloca(cif->rtype->size);
206 else
207 ecif.rvalue = rvalue;
210 switch (cif->abi)
212 case FFI_SYSV:
213 ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
214 fn);
215 break;
216 #ifdef X86_WIN32
217 case FFI_STDCALL:
218 ffi_call_STDCALL(ffi_prep_args, &ecif, cif->bytes, cif->flags,
219 ecif.rvalue, fn);
220 break;
221 #endif /* X86_WIN32 */
222 default:
223 FFI_ASSERT(0);
224 break;
229 /** private members **/
231 static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
232 void** args, ffi_cif* cif);
233 void FFI_HIDDEN ffi_closure_SYSV (ffi_closure *)
234 __attribute__ ((regparm(1)));
235 unsigned int FFI_HIDDEN ffi_closure_SYSV_inner (ffi_closure *, void **, void *)
236 __attribute__ ((regparm(1)));
237 void FFI_HIDDEN ffi_closure_raw_SYSV (ffi_raw_closure *)
238 __attribute__ ((regparm(1)));
240 /* This function is jumped to by the trampoline */
242 unsigned int FFI_HIDDEN
243 ffi_closure_SYSV_inner (closure, respp, args)
244 ffi_closure *closure;
245 void **respp;
246 void *args;
248 // our various things...
249 ffi_cif *cif;
250 void **arg_area;
252 cif = closure->cif;
253 arg_area = (void**) alloca (cif->nargs * sizeof (void*));
255 /* this call will initialize ARG_AREA, such that each
256 * element in that array points to the corresponding
257 * value on the stack; and if the function returns
258 * a structure, it will re-set RESP to point to the
259 * structure return address. */
261 ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif);
263 (closure->fun) (cif, *respp, arg_area, closure->user_data);
265 return cif->flags;
268 static void
269 ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue,
270 ffi_cif *cif)
272 register unsigned int i;
273 register void **p_argv;
274 register char *argp;
275 register ffi_type **p_arg;
277 argp = stack;
279 if ( cif->flags == FFI_TYPE_STRUCT ) {
280 *rvalue = *(void **) argp;
281 argp += 4;
284 p_argv = avalue;
286 for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
288 size_t z;
290 /* Align if necessary */
291 if ((sizeof(int) - 1) & (unsigned) argp) {
292 argp = (char *) ALIGN(argp, sizeof(int));
295 z = (*p_arg)->size;
297 /* because we're little endian, this is what it turns into. */
299 *p_argv = (void*) argp;
301 p_argv++;
302 argp += z;
305 return;
308 /* How to make a trampoline. Derived from gcc/config/i386/i386.c. */
310 #define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \
311 ({ unsigned char *__tramp = (unsigned char*)(TRAMP); \
312 unsigned int __fun = (unsigned int)(FUN); \
313 unsigned int __ctx = (unsigned int)(CTX); \
314 unsigned int __dis = __fun - (__ctx + FFI_TRAMPOLINE_SIZE); \
315 *(unsigned char*) &__tramp[0] = 0xb8; \
316 *(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
317 *(unsigned char *) &__tramp[5] = 0xe9; \
318 *(unsigned int*) &__tramp[6] = __dis; /* jmp __fun */ \
322 /* the cif must already be prep'ed */
324 ffi_status
325 ffi_prep_closure_loc (ffi_closure* closure,
326 ffi_cif* cif,
327 void (*fun)(ffi_cif*,void*,void**,void*),
328 void *user_data,
329 void *codeloc)
331 FFI_ASSERT (cif->abi == FFI_SYSV);
333 FFI_INIT_TRAMPOLINE (&closure->tramp[0], \
334 &ffi_closure_SYSV, \
335 codeloc);
337 closure->cif = cif;
338 closure->user_data = user_data;
339 closure->fun = fun;
341 return FFI_OK;
344 /* ------- Native raw API support -------------------------------- */
346 #if !FFI_NO_RAW_API
348 ffi_status
349 ffi_prep_raw_closure_loc (ffi_raw_closure* closure,
350 ffi_cif* cif,
351 void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
352 void *user_data,
353 void *codeloc)
355 int i;
357 FFI_ASSERT (cif->abi == FFI_SYSV);
359 // we currently don't support certain kinds of arguments for raw
360 // closures. This should be implemented by a separate assembly language
361 // routine, since it would require argument processing, something we
362 // don't do now for performance.
364 for (i = cif->nargs-1; i >= 0; i--)
366 FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_STRUCT);
367 FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE);
371 FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV,
372 codeloc);
374 closure->cif = cif;
375 closure->user_data = user_data;
376 closure->fun = fun;
378 return FFI_OK;
381 static void
382 ffi_prep_args_raw(char *stack, extended_cif *ecif)
384 memcpy (stack, ecif->avalue, ecif->cif->bytes);
387 /* we borrow this routine from libffi (it must be changed, though, to
388 * actually call the function passed in the first argument. as of
389 * libffi-1.20, this is not the case.)
392 extern void
393 ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *, unsigned,
394 unsigned, unsigned *, void (*fn)());
396 #ifdef X86_WIN32
397 extern void
398 ffi_call_STDCALL(void (*)(char *, extended_cif *), extended_cif *, unsigned,
399 unsigned, unsigned *, void (*fn)());
400 #endif /* X86_WIN32 */
402 void
403 ffi_raw_call(ffi_cif *cif, void (*fn)(), void *rvalue, ffi_raw *fake_avalue)
405 extended_cif ecif;
406 void **avalue = (void **)fake_avalue;
408 ecif.cif = cif;
409 ecif.avalue = avalue;
411 /* If the return value is a struct and we don't have a return */
412 /* value address then we need to make one */
414 if ((rvalue == NULL) &&
415 (cif->rtype->type == FFI_TYPE_STRUCT))
417 ecif.rvalue = alloca(cif->rtype->size);
419 else
420 ecif.rvalue = rvalue;
423 switch (cif->abi)
425 case FFI_SYSV:
426 ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
427 ecif.rvalue, fn);
428 break;
429 #ifdef X86_WIN32
430 case FFI_STDCALL:
431 ffi_call_STDCALL(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
432 ecif.rvalue, fn);
433 break;
434 #endif /* X86_WIN32 */
435 default:
436 FFI_ASSERT(0);
437 break;
441 #endif
443 #endif /* __x86_64__ */