1/* -----------------------------------------------------------------------
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
6
7   x86 Foreign Function Interface
8
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
29#ifndef __x86_64__
30
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
39/*@-exportheader@*/
40void ffi_prep_args(char *stack, extended_cif *ecif)
41/*@=exportheader@*/
42{
43  register unsigned int i;
44  register void **p_argv;
45  register char *argp;
46  register ffi_type **p_arg;
47
48  argp = stack;
49
50  if (ecif->cif->flags == FFI_TYPE_STRUCT)
51    {
52      *(void **) argp = ecif->rvalue;
53      argp += 4;
54    }
55
56  p_argv = ecif->avalue;
57
58  for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
59       i != 0;
60       i--, p_arg++)
61    {
62      size_t z;
63
64      /* Align if necessary */
65      if ((sizeof(int) - 1) & (unsigned) argp)
66	argp = (char *) ALIGN(argp, sizeof(int));
67
68      z = (*p_arg)->size;
69      if (z < sizeof(int))
70	{
71	  z = sizeof(int);
72	  switch ((*p_arg)->type)
73	    {
74	    case FFI_TYPE_SINT8:
75	      *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
76	      break;
77
78	    case FFI_TYPE_UINT8:
79	      *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
80	      break;
81
82	    case FFI_TYPE_SINT16:
83	      *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
84	      break;
85
86	    case FFI_TYPE_UINT16:
87	      *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
88	      break;
89
90	    case FFI_TYPE_SINT32:
91	      *(signed int *) argp = (signed int)*(SINT32 *)(* p_argv);
92	      break;
93
94	    case FFI_TYPE_UINT32:
95	      *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
96	      break;
97
98	    case FFI_TYPE_STRUCT:
99	      *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
100	      break;
101
102	    default:
103	      FFI_ASSERT(0);
104	    }
105	}
106      else
107	{
108	  memcpy(argp, *p_argv, z);
109	}
110      p_argv++;
111      argp += z;
112    }
113
114  return;
115}
116
117/* Perform machine dependent cif processing */
118ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
119{
120  /* Set the return type flag */
121  switch (cif->rtype->type)
122    {
123    case FFI_TYPE_VOID:
124#if !defined(X86_WIN32) && !defined(__OpenBSD__) && !defined(__FreeBSD__)
125    case FFI_TYPE_STRUCT:
126#endif
127    case FFI_TYPE_SINT64:
128    case FFI_TYPE_FLOAT:
129    case FFI_TYPE_DOUBLE:
130    case FFI_TYPE_LONGDOUBLE:
131      cif->flags = (unsigned) cif->rtype->type;
132      break;
133
134    case FFI_TYPE_UINT64:
135      cif->flags = FFI_TYPE_SINT64;
136      break;
137
138#if defined(X86_WIN32) || defined(__OpenBSD__) || defined(__FreeBSD__)
139    case FFI_TYPE_STRUCT:
140      if (cif->rtype->size == 1)
141        {
142          cif->flags = FFI_TYPE_SINT8; /* same as char size */
143        }
144      else if (cif->rtype->size == 2)
145        {
146          cif->flags = FFI_TYPE_SINT16; /* same as short size */
147        }
148      else if (cif->rtype->size == 4)
149        {
150          cif->flags = FFI_TYPE_INT; /* same as int type */
151        }
152      else if (cif->rtype->size == 8)
153        {
154          cif->flags = FFI_TYPE_SINT64; /* same as int64 type */
155        }
156      else
157        {
158          cif->flags = FFI_TYPE_STRUCT;
159        }
160      break;
161#endif
162
163    default:
164      cif->flags = FFI_TYPE_INT;
165      break;
166    }
167
168  return FFI_OK;
169}
170
171/*@-declundef@*/
172/*@-exportheader@*/
173extern void ffi_call_SYSV(void (*)(char *, extended_cif *),
174			  /*@out@*/ extended_cif *,
175			  unsigned, unsigned,
176			  /*@out@*/ unsigned *,
177			  void (*fn)());
178/*@=declundef@*/
179/*@=exportheader@*/
180
181#ifdef X86_WIN32
182/*@-declundef@*/
183/*@-exportheader@*/
184extern void ffi_call_STDCALL(void (*)(char *, extended_cif *),
185			  /*@out@*/ extended_cif *,
186			  unsigned, unsigned,
187			  /*@out@*/ unsigned *,
188			  void (*fn)());
189/*@=declundef@*/
190/*@=exportheader@*/
191#endif /* X86_WIN32 */
192
193void ffi_call(/*@dependent@*/ ffi_cif *cif,
194	      void (*fn)(),
195	      /*@out@*/ void *rvalue,
196	      /*@dependent@*/ void **avalue)
197{
198  extended_cif ecif;
199
200  ecif.cif = cif;
201  ecif.avalue = avalue;
202
203  /* If the return value is a struct and we don't have a return	*/
204  /* value address then we need to make one		        */
205
206  if ((rvalue == NULL) &&
207      (cif->flags == FFI_TYPE_STRUCT))
208    {
209      /*@-sysunrecog@*/
210      ecif.rvalue = alloca(cif->rtype->size);
211      /*@=sysunrecog@*/
212    }
213  else
214    ecif.rvalue = rvalue;
215
216
217  switch (cif->abi)
218    {
219    case FFI_SYSV:
220      /*@-usedef@*/
221      ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes,
222		    cif->flags, ecif.rvalue, fn);
223      /*@=usedef@*/
224      break;
225#ifdef X86_WIN32
226    case FFI_STDCALL:
227      /*@-usedef@*/
228      ffi_call_STDCALL(ffi_prep_args, &ecif, cif->bytes,
229		    cif->flags, ecif.rvalue, fn);
230      /*@=usedef@*/
231      break;
232#endif /* X86_WIN32 */
233    default:
234      FFI_ASSERT(0);
235      break;
236    }
237}
238
239
240/** private members **/
241
242static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
243					 void** args, ffi_cif* cif);
244void FFI_HIDDEN ffi_closure_SYSV (ffi_closure *)
245     __attribute__ ((regparm(1)));
246unsigned int FFI_HIDDEN ffi_closure_SYSV_inner (ffi_closure *, void **, void *)
247     __attribute__ ((regparm(1)));
248void FFI_HIDDEN ffi_closure_raw_SYSV (ffi_raw_closure *)
249     __attribute__ ((regparm(1)));
250
251/* This function is jumped to by the trampoline */
252
253unsigned int FFI_HIDDEN
254ffi_closure_SYSV_inner (closure, respp, args)
255     ffi_closure *closure;
256     void **respp;
257     void *args;
258{
259  // our various things...
260  ffi_cif       *cif;
261  void         **arg_area;
262
263  cif         = closure->cif;
264  arg_area    = (void**) alloca (cif->nargs * sizeof (void*));
265
266  /* this call will initialize ARG_AREA, such that each
267   * element in that array points to the corresponding
268   * value on the stack; and if the function returns
269   * a structure, it will re-set RESP to point to the
270   * structure return address.  */
271
272  ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif);
273
274  (closure->fun) (cif, *respp, arg_area, closure->user_data);
275
276  return cif->flags;
277}
278
279/*@-exportheader@*/
280static void
281ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
282			    void **avalue, ffi_cif *cif)
283/*@=exportheader@*/
284{
285  register unsigned int i;
286  register void **p_argv;
287  register char *argp;
288  register ffi_type **p_arg;
289
290  argp = stack;
291
292  if ( cif->flags == FFI_TYPE_STRUCT ) {
293    *rvalue = *(void **) argp;
294    argp += 4;
295  }
296
297  p_argv = avalue;
298
299  for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
300    {
301      size_t z;
302
303      /* Align if necessary */
304      if ((sizeof(int) - 1) & (unsigned) argp) {
305	argp = (char *) ALIGN(argp, sizeof(int));
306      }
307
308      z = (*p_arg)->size;
309
310      /* because we're little endian, this is what it turns into.   */
311
312      *p_argv = (void*) argp;
313
314      p_argv++;
315      argp += z;
316    }
317
318  return;
319}
320
321/* How to make a trampoline.  Derived from gcc/config/i386/i386.c. */
322
323#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \
324({ unsigned char *__tramp = (unsigned char*)(TRAMP); \
325   unsigned int  __fun = (unsigned int)(FUN); \
326   unsigned int  __ctx = (unsigned int)(CTX); \
327   unsigned int  __dis = __fun - ((unsigned int) __tramp + FFI_TRAMPOLINE_SIZE); \
328   *(unsigned char*) &__tramp[0] = 0xb8; \
329   *(unsigned int*)  &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
330   *(unsigned char *)  &__tramp[5] = 0xe9; \
331   *(unsigned int*)  &__tramp[6] = __dis; /* jmp __fun  */ \
332 })
333
334
335/* the cif must already be prep'ed */
336
337ffi_status
338ffi_prep_closure (ffi_closure* closure,
339		  ffi_cif* cif,
340		  void (*fun)(ffi_cif*,void*,void**,void*),
341		  void *user_data)
342{
343  FFI_ASSERT (cif->abi == FFI_SYSV);
344
345  FFI_INIT_TRAMPOLINE (&closure->tramp[0], \
346		       &ffi_closure_SYSV,  \
347		       (void*)closure);
348
349  closure->cif  = cif;
350  closure->user_data = user_data;
351  closure->fun  = fun;
352
353  return FFI_OK;
354}
355
356/* ------- Native raw API support -------------------------------- */
357
358#if !FFI_NO_RAW_API
359
360ffi_status
361ffi_prep_raw_closure (ffi_raw_closure* closure,
362		      ffi_cif* cif,
363		      void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
364		      void *user_data)
365{
366  int i;
367
368  FFI_ASSERT (cif->abi == FFI_SYSV);
369
370  // we currently don't support certain kinds of arguments for raw
371  // closures.  This should be implemented by a separate assembly language
372  // routine, since it would require argument processing, something we
373  // don't do now for performance.
374
375  for (i = cif->nargs-1; i >= 0; i--)
376    {
377      FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_STRUCT);
378      FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE);
379    }
380
381
382  FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV,
383		       (void*)closure);
384
385  closure->cif  = cif;
386  closure->user_data = user_data;
387  closure->fun  = fun;
388
389  return FFI_OK;
390}
391
392static void
393ffi_prep_args_raw(char *stack, extended_cif *ecif)
394{
395  memcpy (stack, ecif->avalue, ecif->cif->bytes);
396}
397
398/* we borrow this routine from libffi (it must be changed, though, to
399 * actually call the function passed in the first argument.  as of
400 * libffi-1.20, this is not the case.)
401 */
402
403extern void
404ffi_call_SYSV(void (*)(char *, extended_cif *),
405	      /*@out@*/ extended_cif *,
406	      unsigned, unsigned,
407	      /*@out@*/ unsigned *,
408	      void (*fn)());
409
410#ifdef X86_WIN32
411extern void
412ffi_call_STDCALL(void (*)(char *, extended_cif *),
413	      /*@out@*/ extended_cif *,
414	      unsigned, unsigned,
415	      /*@out@*/ unsigned *,
416	      void (*fn)());
417#endif /* X86_WIN32 */
418
419void
420ffi_raw_call(/*@dependent@*/ ffi_cif *cif,
421	     void (*fn)(),
422	     /*@out@*/ void *rvalue,
423	     /*@dependent@*/ ffi_raw *fake_avalue)
424{
425  extended_cif ecif;
426  void **avalue = (void **)fake_avalue;
427
428  ecif.cif = cif;
429  ecif.avalue = avalue;
430
431  /* If the return value is a struct and we don't have a return	*/
432  /* value address then we need to make one		        */
433
434  if ((rvalue == NULL) &&
435      (cif->rtype->type == FFI_TYPE_STRUCT))
436    {
437      /*@-sysunrecog@*/
438      ecif.rvalue = alloca(cif->rtype->size);
439      /*@=sysunrecog@*/
440    }
441  else
442    ecif.rvalue = rvalue;
443
444
445  switch (cif->abi)
446    {
447    case FFI_SYSV:
448      /*@-usedef@*/
449      ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes,
450		    cif->flags, ecif.rvalue, fn);
451      /*@=usedef@*/
452      break;
453#ifdef X86_WIN32
454    case FFI_STDCALL:
455      /*@-usedef@*/
456      ffi_call_STDCALL(ffi_prep_args_raw, &ecif, cif->bytes,
457		    cif->flags, ecif.rvalue, fn);
458      /*@=usedef@*/
459      break;
460#endif /* X86_WIN32 */
461    default:
462      FFI_ASSERT(0);
463      break;
464    }
465}
466
467#endif
468
469#endif /* __x86_64__  */
470