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
38void ffi_prep_args(char *stack, extended_cif *ecif);
39
40void 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 */
117ffi_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
179extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
180                          unsigned, unsigned, unsigned *, void (*fn)());
181
182#ifdef X86_WIN32
183extern void ffi_call_STDCALL(void (*)(char *, extended_cif *), extended_cif *,
184                             unsigned, unsigned, unsigned *, void (*fn)());
185
186#endif /* X86_WIN32 */
187
188void 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
228static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
229                                         void** args, ffi_cif* cif);
230void FFI_HIDDEN ffi_closure_SYSV (ffi_closure *)
231__attribute__ ((regparm(1)));
232unsigned int FFI_HIDDEN ffi_closure_SYSV_inner (ffi_closure *, void **, void *)
233__attribute__ ((regparm(1)));
234void FFI_HIDDEN ffi_closure_raw_SYSV (ffi_raw_closure *)
235__attribute__ ((regparm(1)));
236
237/* This function is jumped to by the trampoline */
238
239unsigned int FFI_HIDDEN
240ffi_closure_SYSV_inner (closure, respp, args)
241ffi_closure *closure;
242void **respp;
243void *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
265static void
266ffi_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); \
309unsigned int  __fun = (unsigned int)(FUN); \
310unsigned int  __ctx = (unsigned int)(CTX); \
311unsigned 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 */
320ffi_status
321ffi_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
344ffi_status
345ffi_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
377static void
378ffi_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
388extern void
389ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *, unsigned,
390              unsigned, unsigned *, void (*fn)());
391
392#ifdef X86_WIN32
393extern void
394ffi_call_STDCALL(void (*)(char *, extended_cif *), extended_cif *, unsigned,
395                 unsigned, unsigned *, void (*fn)());
396#endif /* X86_WIN32 */
397
398void
399ffi_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