blob: c9a306e51dcae5824ecfefc555e0197596ca8c06 [file] [log] [blame]
Thomas Heller8bdf81d2008-03-04 20:09:11 +00001#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
Thomas Heller8bdf81d2008-03-04 20:09:11 +000030#include <ffi.h>
31#include <ffi_common.h>
32
33#include <stdlib.h>
34
Thomas Heller8bdf81d2008-03-04 20:09:11 +000035/* ffi_prep_args is called by the assembly routine once stack space
Ronald Oussoren16766d72009-09-20 18:54:16 +000036 has been allocated for the function's arguments */
37
38void ffi_prep_args(char *stack, extended_cif *ecif)
Thomas Heller8bdf81d2008-03-04 20:09:11 +000039{
Ronald Oussoren16766d72009-09-20 18:54:16 +000040 register unsigned int i;
41 register void **p_argv;
42 register char *argp;
43 register ffi_type **p_arg;
44
45 argp = stack;
46
47 if (ecif->cif->flags == FFI_TYPE_STRUCT)
Thomas Heller8bdf81d2008-03-04 20:09:11 +000048 {
Ronald Oussoren16766d72009-09-20 18:54:16 +000049 *(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 ((sizeof(int) - 1) & (unsigned) argp)
63 argp = (char *) ALIGN(argp, sizeof(int));
64
65 z = (*p_arg)->size;
66 if (z < sizeof(int))
67 {
68 z = sizeof(int);
69 switch ((*p_arg)->type)
70 {
71 case FFI_TYPE_SINT8:
72 *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
73 break;
74
75 case FFI_TYPE_UINT8:
76 *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
77 break;
78
79 case FFI_TYPE_SINT16:
80 *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
81 break;
82
83 case FFI_TYPE_UINT16:
84 *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
85 break;
86
87 case FFI_TYPE_SINT32:
88 *(signed int *) argp = (signed int)*(SINT32 *)(* p_argv);
89 break;
90
91 case FFI_TYPE_UINT32:
92 *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
93 break;
94
95 case FFI_TYPE_STRUCT:
96 *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
97 break;
98
99 default:
100 FFI_ASSERT(0);
101 }
102 }
103 else
104 {
105 memcpy(argp, *p_argv, z);
106 }
107 p_argv++;
108 argp += z;
109 }
110
111 return;
Thomas Heller8bdf81d2008-03-04 20:09:11 +0000112}
113
114/* Perform machine dependent cif processing */
Ronald Oussoren16766d72009-09-20 18:54:16 +0000115ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
Thomas Heller8bdf81d2008-03-04 20:09:11 +0000116{
Ronald Oussoren16766d72009-09-20 18:54:16 +0000117 /* Set the return type flag */
118 switch (cif->rtype->type)
119 {
120 case FFI_TYPE_VOID:
121#ifdef X86
122 case FFI_TYPE_STRUCT:
123 case FFI_TYPE_UINT8:
124 case FFI_TYPE_UINT16:
125 case FFI_TYPE_SINT8:
126 case FFI_TYPE_SINT16:
Thomas Heller8bdf81d2008-03-04 20:09:11 +0000127#endif
Ronald Oussoren16766d72009-09-20 18:54:16 +0000128
129 case FFI_TYPE_SINT64:
130 case FFI_TYPE_FLOAT:
131 case FFI_TYPE_DOUBLE:
132 case FFI_TYPE_LONGDOUBLE:
133 cif->flags = (unsigned) cif->rtype->type;
134 break;
135
136 case FFI_TYPE_UINT64:
137 cif->flags = FFI_TYPE_SINT64;
138 break;
139
140#ifndef X86
141 case FFI_TYPE_STRUCT:
142 if (cif->rtype->size == 1)
143 {
144 cif->flags = FFI_TYPE_SINT8; /* same as char size */
145 }
146 else if (cif->rtype->size == 2)
147 {
148 cif->flags = FFI_TYPE_SINT16; /* same as short size */
149 }
150 else if (cif->rtype->size == 4)
151 {
152 cif->flags = FFI_TYPE_INT; /* same as int type */
153 }
154 else if (cif->rtype->size == 8)
155 {
156 cif->flags = FFI_TYPE_SINT64; /* same as int64 type */
157 }
158 else
159 {
160 cif->flags = FFI_TYPE_STRUCT;
161 }
162 break;
Thomas Heller8bdf81d2008-03-04 20:09:11 +0000163#endif
Ronald Oussoren16766d72009-09-20 18:54:16 +0000164
165 default:
166 cif->flags = FFI_TYPE_INT;
167 break;
168 }
169
170#ifdef X86_DARWIN
171 cif->bytes = (cif->bytes + 15) & ~0xF;
172#endif
173
174 return FFI_OK;
Thomas Heller8bdf81d2008-03-04 20:09:11 +0000175}
176
Ronald Oussoren16766d72009-09-20 18:54:16 +0000177extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
178 unsigned, unsigned, unsigned *, void (*fn)());
Thomas Heller8bdf81d2008-03-04 20:09:11 +0000179
180#ifdef X86_WIN32
Ronald Oussoren16766d72009-09-20 18:54:16 +0000181extern void ffi_call_STDCALL(void (*)(char *, extended_cif *), extended_cif *,
182 unsigned, unsigned, unsigned *, void (*fn)());
183
Thomas Heller8bdf81d2008-03-04 20:09:11 +0000184#endif /* X86_WIN32 */
185
Ronald Oussoren16766d72009-09-20 18:54:16 +0000186void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
Thomas Heller8bdf81d2008-03-04 20:09:11 +0000187{
Ronald Oussoren16766d72009-09-20 18:54:16 +0000188 extended_cif ecif;
189
190 ecif.cif = cif;
191 ecif.avalue = avalue;
192
193 /* If the return value is a struct and we don't have a return */
194 /* value address then we need to make one */
195
196 if ((rvalue == NULL) &&
197 (cif->flags == FFI_TYPE_STRUCT))
198 {
199 ecif.rvalue = alloca(cif->rtype->size);
200 }
201 else
202 ecif.rvalue = rvalue;
203
204
205 switch (cif->abi)
206 {
207 case FFI_SYSV:
208 ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
209 fn);
210 break;
Thomas Heller8bdf81d2008-03-04 20:09:11 +0000211#ifdef X86_WIN32
Ronald Oussoren16766d72009-09-20 18:54:16 +0000212 case FFI_STDCALL:
213 ffi_call_STDCALL(ffi_prep_args, &ecif, cif->bytes, cif->flags,
214 ecif.rvalue, fn);
215 break;
Thomas Heller8bdf81d2008-03-04 20:09:11 +0000216#endif /* X86_WIN32 */
Ronald Oussoren16766d72009-09-20 18:54:16 +0000217 default:
218 FFI_ASSERT(0);
219 break;
220 }
Thomas Heller8bdf81d2008-03-04 20:09:11 +0000221}
222
Ronald Oussoren16766d72009-09-20 18:54:16 +0000223
Thomas Heller8bdf81d2008-03-04 20:09:11 +0000224/** private members **/
225
Ronald Oussoren16766d72009-09-20 18:54:16 +0000226static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
227 void** args, ffi_cif* cif);
228void FFI_HIDDEN ffi_closure_SYSV (ffi_closure *)
229__attribute__ ((regparm(1)));
230unsigned int FFI_HIDDEN ffi_closure_SYSV_inner (ffi_closure *, void **, void *)
231__attribute__ ((regparm(1)));
232void FFI_HIDDEN ffi_closure_raw_SYSV (ffi_raw_closure *)
233__attribute__ ((regparm(1)));
Thomas Heller8bdf81d2008-03-04 20:09:11 +0000234
235/* This function is jumped to by the trampoline */
Ronald Oussoren16766d72009-09-20 18:54:16 +0000236
237unsigned int FFI_HIDDEN
238ffi_closure_SYSV_inner (closure, respp, args)
239ffi_closure *closure;
240void **respp;
241void *args;
Thomas Heller8bdf81d2008-03-04 20:09:11 +0000242{
Ronald Oussoren16766d72009-09-20 18:54:16 +0000243 // our various things...
244 ffi_cif *cif;
245 void **arg_area;
246
247 cif = closure->cif;
248 arg_area = (void**) alloca (cif->nargs * sizeof (void*));
249
250 /* this call will initialize ARG_AREA, such that each
251 * element in that array points to the corresponding
252 * value on the stack; and if the function returns
253 * a structure, it will re-set RESP to point to the
254 * structure return address. */
255
256 ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif);
257
258 (closure->fun) (cif, *respp, arg_area, closure->user_data);
259
260 return cif->flags;
Thomas Heller8bdf81d2008-03-04 20:09:11 +0000261}
262
Ronald Oussoren16766d72009-09-20 18:54:16 +0000263static void
264ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue,
265 ffi_cif *cif)
266{
267 register unsigned int i;
268 register void **p_argv;
269 register char *argp;
270 register ffi_type **p_arg;
271
272 argp = stack;
273
274 if ( cif->flags == FFI_TYPE_STRUCT ) {
275 *rvalue = *(void **) argp;
276 argp += 4;
277 }
278
279 p_argv = avalue;
280
281 for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
282 {
283 size_t z;
284
285 /* Align if necessary */
286 if ((sizeof(int) - 1) & (unsigned) argp) {
287 argp = (char *) ALIGN(argp, sizeof(int));
288 }
289
290 z = (*p_arg)->size;
291
292 /* because we're little endian, this is what it turns into. */
293
294 *p_argv = (void*) argp;
295
296 p_argv++;
297 argp += z;
298 }
299
300 return;
301}
Thomas Heller8bdf81d2008-03-04 20:09:11 +0000302
303/* How to make a trampoline. Derived from gcc/config/i386/i386.c. */
Ronald Oussoren16766d72009-09-20 18:54:16 +0000304
305#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \
306({ unsigned char *__tramp = (unsigned char*)(TRAMP); \
307unsigned int __fun = (unsigned int)(FUN); \
308unsigned int __ctx = (unsigned int)(CTX); \
309unsigned int __dis = __fun - (__ctx + FFI_TRAMPOLINE_SIZE); \
310*(unsigned char*) &__tramp[0] = 0xb8; \
311*(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
312*(unsigned char *) &__tramp[5] = 0xe9; \
313*(unsigned int*) &__tramp[6] = __dis; /* jmp __fun */ \
314})
315
Thomas Heller8bdf81d2008-03-04 20:09:11 +0000316
317/* the cif must already be prep'ed */
318ffi_status
Ronald Oussoren16766d72009-09-20 18:54:16 +0000319ffi_prep_closure (ffi_closure* closure,
320 ffi_cif* cif,
321 void (*fun)(ffi_cif*,void*,void**,void*),
322 void *user_data)
Thomas Heller8bdf81d2008-03-04 20:09:11 +0000323{
Thomas Heller8bdf81d2008-03-04 20:09:11 +0000324 if (cif->abi != FFI_SYSV)
325 return FFI_BAD_ABI;
Ronald Oussoren16766d72009-09-20 18:54:16 +0000326
327 FFI_INIT_TRAMPOLINE (&closure->tramp[0], \
328 &ffi_closure_SYSV, \
329 (void*)closure);
330
331 closure->cif = cif;
332 closure->user_data = user_data;
333 closure->fun = fun;
334
335 return FFI_OK;
Thomas Heller8bdf81d2008-03-04 20:09:11 +0000336}
337
338/* ------- Native raw API support -------------------------------- */
339
340#if !FFI_NO_RAW_API
341
Thomas Heller8bdf81d2008-03-04 20:09:11 +0000342ffi_status
Ronald Oussoren16766d72009-09-20 18:54:16 +0000343ffi_prep_raw_closure_loc (ffi_raw_closure* closure,
344 ffi_cif* cif,
345 void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
346 void *user_data,
347 void *codeloc)
Thomas Heller8bdf81d2008-03-04 20:09:11 +0000348{
Ronald Oussoren16766d72009-09-20 18:54:16 +0000349 int i;
350
351 FFI_ASSERT (cif->abi == FFI_SYSV);
352
353 // we currently don't support certain kinds of arguments for raw
354 // closures. This should be implemented by a separate assembly language
355 // routine, since it would require argument processing, something we
356 // don't do now for performance.
357
358 for (i = cif->nargs-1; i >= 0; i--)
359 {
360 FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_STRUCT);
361 FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE);
362 }
363
364
365 FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV,
366 codeloc);
367
368 closure->cif = cif;
369 closure->user_data = user_data;
370 closure->fun = fun;
371
372 return FFI_OK;
Thomas Heller8bdf81d2008-03-04 20:09:11 +0000373}
374
375static void
Ronald Oussoren16766d72009-09-20 18:54:16 +0000376ffi_prep_args_raw(char *stack, extended_cif *ecif)
Thomas Heller8bdf81d2008-03-04 20:09:11 +0000377{
Ronald Oussoren16766d72009-09-20 18:54:16 +0000378 memcpy (stack, ecif->avalue, ecif->cif->bytes);
Thomas Heller8bdf81d2008-03-04 20:09:11 +0000379}
380
Ronald Oussoren16766d72009-09-20 18:54:16 +0000381/* we borrow this routine from libffi (it must be changed, though, to
382 * actually call the function passed in the first argument. as of
383 * libffi-1.20, this is not the case.)
384 */
385
386extern void
387ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *, unsigned,
388 unsigned, unsigned *, void (*fn)());
Thomas Heller8bdf81d2008-03-04 20:09:11 +0000389
390#ifdef X86_WIN32
391extern void
Ronald Oussoren16766d72009-09-20 18:54:16 +0000392ffi_call_STDCALL(void (*)(char *, extended_cif *), extended_cif *, unsigned,
393 unsigned, unsigned *, void (*fn)());
394#endif /* X86_WIN32 */
Thomas Heller8bdf81d2008-03-04 20:09:11 +0000395
396void
Ronald Oussoren16766d72009-09-20 18:54:16 +0000397ffi_raw_call(ffi_cif *cif, void (*fn)(), void *rvalue, ffi_raw *fake_avalue)
Thomas Heller8bdf81d2008-03-04 20:09:11 +0000398{
Ronald Oussoren16766d72009-09-20 18:54:16 +0000399 extended_cif ecif;
400 void **avalue = (void **)fake_avalue;
401
402 ecif.cif = cif;
403 ecif.avalue = avalue;
404
405 /* If the return value is a struct and we don't have a return */
406 /* value address then we need to make one */
407
408 if ((rvalue == NULL) &&
409 (cif->rtype->type == FFI_TYPE_STRUCT))
410 {
411 ecif.rvalue = alloca(cif->rtype->size);
412 }
413 else
414 ecif.rvalue = rvalue;
415
416
417 switch (cif->abi)
418 {
419 case FFI_SYSV:
420 ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
421 ecif.rvalue, fn);
422 break;
Thomas Heller8bdf81d2008-03-04 20:09:11 +0000423#ifdef X86_WIN32
Ronald Oussoren16766d72009-09-20 18:54:16 +0000424 case FFI_STDCALL:
425 ffi_call_STDCALL(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
426 ecif.rvalue, fn);
427 break;
Thomas Heller8bdf81d2008-03-04 20:09:11 +0000428#endif /* X86_WIN32 */
Ronald Oussoren16766d72009-09-20 18:54:16 +0000429 default:
430 FFI_ASSERT(0);
431 break;
Thomas Heller8bdf81d2008-03-04 20:09:11 +0000432 }
433}
434
Ronald Oussoren16766d72009-09-20 18:54:16 +0000435#endif
436#endif // __i386__