OSDN Git Service

600cf20527ff9d1c81fb5c9ad8010e8d82a88c03
[pf3gnuchains/gcc-fork.git] / libffi / src / m68k / ffi.c
1 /* -----------------------------------------------------------------------
2    ffi.c
3    
4    m68k Foreign Function Interface 
5    ----------------------------------------------------------------------- */
6
7 #include <ffi.h>
8 #include <ffi_common.h>
9
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <sys/syscall.h>
13 #include <asm/cachectl.h>
14
15 void ffi_call_SYSV (extended_cif *,
16                     unsigned, unsigned,
17                     void *, void (*fn) ());
18 void *ffi_prep_args (void *stack, extended_cif *ecif);
19 void ffi_closure_SYSV (ffi_closure *);
20 void ffi_closure_struct_SYSV (ffi_closure *);
21 unsigned int ffi_closure_SYSV_inner (ffi_closure *closure,
22                                      void *resp, void *args);
23
24 /* ffi_prep_args is called by the assembly routine once stack space has
25    been allocated for the function's arguments.  */
26
27 void *
28 ffi_prep_args (void *stack, extended_cif *ecif)
29 {
30   unsigned int i;
31   void **p_argv;
32   char *argp;
33   ffi_type **p_arg;
34   void *struct_value_ptr;
35
36   argp = stack;
37
38   if (ecif->cif->rtype->type == FFI_TYPE_STRUCT
39       && !ecif->cif->flags)
40     struct_value_ptr = ecif->rvalue;
41   else
42     struct_value_ptr = NULL;
43
44   p_argv = ecif->avalue;
45
46   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
47        i != 0;
48        i--, p_arg++)
49     {
50       size_t z;
51
52       z = (*p_arg)->size;
53       if (z < sizeof (int))
54         {
55           switch ((*p_arg)->type)
56             {
57             case FFI_TYPE_SINT8:
58               *(signed int *) argp = (signed int) *(SINT8 *) *p_argv;
59               break;
60
61             case FFI_TYPE_UINT8:
62               *(unsigned int *) argp = (unsigned int) *(UINT8 *) *p_argv;
63               break;
64
65             case FFI_TYPE_SINT16:
66               *(signed int *) argp = (signed int) *(SINT16 *) *p_argv;
67               break;
68
69             case FFI_TYPE_UINT16:
70               *(unsigned int *) argp = (unsigned int) *(UINT16 *) *p_argv;
71               break;
72
73             case FFI_TYPE_STRUCT:
74               memcpy (argp + sizeof (int) - z, *p_argv, z);
75               break;
76
77             default:
78               FFI_ASSERT (0);
79             }
80           z = sizeof (int);
81         }
82       else
83         {
84           memcpy (argp, *p_argv, z);
85
86           /* Align if necessary.  */
87           if ((sizeof(int) - 1) & z)
88             z = ALIGN(z, sizeof(int));
89         }
90
91       p_argv++;
92       argp += z;
93     }
94
95   return struct_value_ptr;
96 }
97
98 #define CIF_FLAGS_INT           1
99 #define CIF_FLAGS_DINT          2
100 #define CIF_FLAGS_FLOAT         4
101 #define CIF_FLAGS_DOUBLE        8
102 #define CIF_FLAGS_LDOUBLE       16
103 #define CIF_FLAGS_POINTER       32
104 #define CIF_FLAGS_STRUCT1       64
105 #define CIF_FLAGS_STRUCT2       128
106
107 /* Perform machine dependent cif processing */
108 ffi_status
109 ffi_prep_cif_machdep (ffi_cif *cif)
110 {
111   /* Set the return type flag */
112   switch (cif->rtype->type)
113     {
114     case FFI_TYPE_VOID:
115       cif->flags = 0;
116       break;
117
118     case FFI_TYPE_STRUCT:
119       switch (cif->rtype->size)
120         {
121         case 1:
122           cif->flags = CIF_FLAGS_STRUCT1;
123           break;
124         case 2:
125           cif->flags = CIF_FLAGS_STRUCT2;
126           break;
127         case 4:
128           cif->flags = CIF_FLAGS_INT;
129           break;
130         case 8:
131           cif->flags = CIF_FLAGS_DINT;
132           break;
133         default:
134           cif->flags = 0;
135           break;
136         }
137       break;
138
139     case FFI_TYPE_FLOAT:
140       cif->flags = CIF_FLAGS_FLOAT;
141       break;
142
143     case FFI_TYPE_DOUBLE:
144       cif->flags = CIF_FLAGS_DOUBLE;
145       break;
146
147     case FFI_TYPE_LONGDOUBLE:
148       cif->flags = CIF_FLAGS_LDOUBLE;
149       break;
150
151     case FFI_TYPE_POINTER:
152       cif->flags = CIF_FLAGS_POINTER;
153       break;
154
155     case FFI_TYPE_SINT64:
156     case FFI_TYPE_UINT64:
157       cif->flags = CIF_FLAGS_DINT;
158       break;
159
160     default:
161       cif->flags = CIF_FLAGS_INT;
162       break;
163     }
164
165   return FFI_OK;
166 }
167
168 void
169 ffi_call (ffi_cif *cif, void (*fn) (), void *rvalue, void **avalue)
170 {
171   extended_cif ecif;
172
173   ecif.cif = cif;
174   ecif.avalue = avalue;
175
176   /* If the return value is a struct and we don't have a return value
177      address then we need to make one.  */
178
179   if (rvalue == NULL
180       && cif->rtype->type == FFI_TYPE_STRUCT
181       && cif->rtype->size > 8)
182     ecif.rvalue = alloca (cif->rtype->size);
183   else
184     ecif.rvalue = rvalue;
185
186   switch (cif->abi)
187     {
188     case FFI_SYSV:
189       ffi_call_SYSV (&ecif, cif->bytes, cif->flags,
190                      ecif.rvalue, fn);
191       break;
192
193     default:
194       FFI_ASSERT (0);
195       break;
196     }
197 }
198
199 static void
200 ffi_prep_incoming_args_SYSV (char *stack, void **avalue, ffi_cif *cif)
201 {
202   unsigned int i;
203   void **p_argv;
204   char *argp;
205   ffi_type **p_arg;
206
207   argp = stack;
208   p_argv = avalue;
209
210   for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
211     {
212       size_t z;
213
214       z = (*p_arg)->size;
215       if (z <= 4)
216         {
217           *p_argv = (void *) (argp + 4 - z);
218
219           z = 4;
220         }
221       else
222         {
223           *p_argv = (void *) argp;
224
225           /* Align if necessary */
226           if ((sizeof(int) - 1) & z)
227             z = ALIGN(z, sizeof(int));
228         }
229
230       p_argv++;
231       argp += z;
232     }
233 }
234
235 unsigned int
236 ffi_closure_SYSV_inner (ffi_closure *closure, void *resp, void *args)
237 {
238   ffi_cif *cif;
239   void **arg_area;
240
241   cif = closure->cif;
242   arg_area = (void**) alloca (cif->nargs * sizeof (void *));
243
244   ffi_prep_incoming_args_SYSV(args, arg_area, cif);
245
246   (closure->fun) (cif, resp, arg_area, closure->user_data);
247
248   return cif->flags;
249 }
250
251 ffi_status
252 ffi_prep_closure_loc (ffi_closure* closure,
253                       ffi_cif* cif,
254                       void (*fun)(ffi_cif*,void*,void**,void*),
255                       void *user_data,
256                       void *codeloc)
257 {
258   FFI_ASSERT (cif->abi == FFI_SYSV);
259
260   *(unsigned short *)closure->tramp = 0x207c;
261   *(void **)(closure->tramp + 2) = codeloc;
262   *(unsigned short *)(closure->tramp + 6) = 0x4ef9;
263   if (cif->rtype->type == FFI_TYPE_STRUCT
264       && !cif->flags)
265     *(void **)(closure->tramp + 8) = ffi_closure_struct_SYSV;
266   else
267     *(void **)(closure->tramp + 8) = ffi_closure_SYSV;
268
269   syscall(SYS_cacheflush, codeloc, FLUSH_SCOPE_LINE,
270           FLUSH_CACHE_BOTH, FFI_TRAMPOLINE_SIZE);
271
272   closure->cif  = cif;
273   closure->user_data = user_data;
274   closure->fun  = fun;
275
276   return FFI_OK;
277 }
278