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