PageRenderTime 35ms CodeModel.GetById 2ms app.highlight 27ms RepoModel.GetById 1ms app.codeStats 0ms

/Modules/_ctypes/libffi_osx/x86/x86-ffi_darwin.c

http://unladen-swallow.googlecode.com/
C | 436 lines | 296 code | 83 blank | 57 comment | 40 complexity | 183ca90b67e7ce5d3e8a48512b4c93e5 MD5 | raw file
  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__