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{
40    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)
48    {
49        *(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;
112}
113
114/* Perform machine dependent cif processing */
115ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
116{
117    /* 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:
127#endif
128
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;
163#endif
164
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;
175}
176
177extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
178                          unsigned, unsigned, unsigned *, void (*fn)());
179
180#ifdef X86_WIN32
181extern void ffi_call_STDCALL(void (*)(char *, extended_cif *), extended_cif *,
182                             unsigned, unsigned, unsigned *, void (*fn)());
183
184#endif /* X86_WIN32 */
185
186void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
187{
188    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;
211#ifdef X86_WIN32
212        case FFI_STDCALL:
213            ffi_call_STDCALL(ffi_prep_args, &ecif, cif->bytes, cif->flags,
214                             ecif.rvalue, fn);
215            break;
216#endif /* X86_WIN32 */
217        default:
218            FFI_ASSERT(0);
219            break;
220    }
221}
222
223
224/** private members **/
225
226static 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)));
234
235/* This function is jumped to by the trampoline */
236
237unsigned int FFI_HIDDEN
238ffi_closure_SYSV_inner (closure, respp, args)
239ffi_closure *closure;
240void **respp;
241void *args;
242{
243    // 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;
261}
262
263static 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}
302
303/* How to make a trampoline.  Derived from gcc/config/i386/i386.c. */
304
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
316
317/* the cif must already be prep'ed */
318ffi_status
319ffi_prep_closure (ffi_closure* closure,
320                  ffi_cif* cif,
321                  void (*fun)(ffi_cif*,void*,void**,void*),
322                  void *user_data)
323{
324	if (cif->abi != FFI_SYSV)
325		return FFI_BAD_ABI;
326
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;
336}
337
338/* ------- Native raw API support -------------------------------- */
339
340#if !FFI_NO_RAW_API
341
342ffi_status
343ffi_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)
348{
349    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;
373}
374
375static void
376ffi_prep_args_raw(char *stack, extended_cif *ecif)
377{
378    memcpy (stack, ecif->avalue, ecif->cif->bytes);
379}
380
381/* 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)());
389
390#ifdef X86_WIN32
391extern void
392ffi_call_STDCALL(void (*)(char *, extended_cif *), extended_cif *, unsigned,
393                 unsigned, unsigned *, void (*fn)());
394#endif /* X86_WIN32 */
395
396void
397ffi_raw_call(ffi_cif *cif, void (*fn)(), void *rvalue, ffi_raw *fake_avalue)
398{
399    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;
423#ifdef X86_WIN32
424        case FFI_STDCALL:
425            ffi_call_STDCALL(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
426                             ecif.rvalue, fn);
427            break;
428#endif /* X86_WIN32 */
429        default:
430            FFI_ASSERT(0);
431            break;
432    }
433}
434
435#endif
436#endif	// __i386__