1f180099ec619325d28c6a76a38df5419ef69651eThomas Heller/* -----------------------------------------------------------------------
2f180099ec619325d28c6a76a38df5419ef69651eThomas Heller   prep_cif.c - Copyright (c) 1996, 1998  Red Hat, Inc.
3f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
4f180099ec619325d28c6a76a38df5419ef69651eThomas Heller   Permission is hereby granted, free of charge, to any person obtaining
5f180099ec619325d28c6a76a38df5419ef69651eThomas Heller   a copy of this software and associated documentation files (the
6f180099ec619325d28c6a76a38df5419ef69651eThomas Heller   ``Software''), to deal in the Software without restriction, including
7f180099ec619325d28c6a76a38df5419ef69651eThomas Heller   without limitation the rights to use, copy, modify, merge, publish,
8f180099ec619325d28c6a76a38df5419ef69651eThomas Heller   distribute, sublicense, and/or sell copies of the Software, and to
9f180099ec619325d28c6a76a38df5419ef69651eThomas Heller   permit persons to whom the Software is furnished to do so, subject to
10f180099ec619325d28c6a76a38df5419ef69651eThomas Heller   the following conditions:
11f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
12f180099ec619325d28c6a76a38df5419ef69651eThomas Heller   The above copyright notice and this permission notice shall be included
13f180099ec619325d28c6a76a38df5419ef69651eThomas Heller   in all copies or substantial portions of the Software.
14f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
15f180099ec619325d28c6a76a38df5419ef69651eThomas Heller   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
16f180099ec619325d28c6a76a38df5419ef69651eThomas Heller   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17f180099ec619325d28c6a76a38df5419ef69651eThomas Heller   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18f180099ec619325d28c6a76a38df5419ef69651eThomas Heller   IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19f180099ec619325d28c6a76a38df5419ef69651eThomas Heller   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20f180099ec619325d28c6a76a38df5419ef69651eThomas Heller   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21f180099ec619325d28c6a76a38df5419ef69651eThomas Heller   OTHER DEALINGS IN THE SOFTWARE.
22f180099ec619325d28c6a76a38df5419ef69651eThomas Heller   ----------------------------------------------------------------------- */
23f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
24f180099ec619325d28c6a76a38df5419ef69651eThomas Heller#include <ffi.h>
25f180099ec619325d28c6a76a38df5419ef69651eThomas Heller#include <ffi_common.h>
26f180099ec619325d28c6a76a38df5419ef69651eThomas Heller#include <stdlib.h>
27f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
28f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
29f180099ec619325d28c6a76a38df5419ef69651eThomas Heller/* Round up to FFI_SIZEOF_ARG. */
30f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
31f180099ec619325d28c6a76a38df5419ef69651eThomas Heller#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG)
32f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
33f180099ec619325d28c6a76a38df5419ef69651eThomas Heller/* Perform machine independent initialization of aggregate type
34f180099ec619325d28c6a76a38df5419ef69651eThomas Heller   specifications. */
35f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
36f180099ec619325d28c6a76a38df5419ef69651eThomas Hellerstatic ffi_status initialize_aggregate(/*@out@*/ ffi_type *arg)
37f180099ec619325d28c6a76a38df5419ef69651eThomas Heller{
38f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  ffi_type **ptr;
39f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
40f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  FFI_ASSERT(arg != NULL);
41f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
42f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  /*@-usedef@*/
43f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
44f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  FFI_ASSERT(arg->elements != NULL);
45f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  FFI_ASSERT(arg->size == 0);
46f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  FFI_ASSERT(arg->alignment == 0);
47f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
48f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  ptr = &(arg->elements[0]);
49f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
50f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  while ((*ptr) != NULL)
51f180099ec619325d28c6a76a38df5419ef69651eThomas Heller    {
52f180099ec619325d28c6a76a38df5419ef69651eThomas Heller      if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK))
53f180099ec619325d28c6a76a38df5419ef69651eThomas Heller	return FFI_BAD_TYPEDEF;
54f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
55f180099ec619325d28c6a76a38df5419ef69651eThomas Heller      /* Perform a sanity check on the argument type */
56f180099ec619325d28c6a76a38df5419ef69651eThomas Heller      FFI_ASSERT_VALID_TYPE(*ptr);
57f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
58f180099ec619325d28c6a76a38df5419ef69651eThomas Heller      arg->size = ALIGN(arg->size, (*ptr)->alignment);
59f180099ec619325d28c6a76a38df5419ef69651eThomas Heller      arg->size += (*ptr)->size;
60f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
61f180099ec619325d28c6a76a38df5419ef69651eThomas Heller      arg->alignment = (arg->alignment > (*ptr)->alignment) ?
62f180099ec619325d28c6a76a38df5419ef69651eThomas Heller	arg->alignment : (*ptr)->alignment;
63f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
64f180099ec619325d28c6a76a38df5419ef69651eThomas Heller      ptr++;
65f180099ec619325d28c6a76a38df5419ef69651eThomas Heller    }
66f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
67f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  /* Structure size includes tail padding.  This is important for
68f180099ec619325d28c6a76a38df5419ef69651eThomas Heller     structures that fit in one register on ABIs like the PowerPC64
69f180099ec619325d28c6a76a38df5419ef69651eThomas Heller     Linux ABI that right justify small structs in a register.
70f180099ec619325d28c6a76a38df5419ef69651eThomas Heller     It's also needed for nested structure layout, for example
71f180099ec619325d28c6a76a38df5419ef69651eThomas Heller     struct A { long a; char b; }; struct B { struct A x; char y; };
72f180099ec619325d28c6a76a38df5419ef69651eThomas Heller     should find y at an offset of 2*sizeof(long) and result in a
73f180099ec619325d28c6a76a38df5419ef69651eThomas Heller     total size of 3*sizeof(long).  */
74f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  arg->size = ALIGN (arg->size, arg->alignment);
75f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
76f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  if (arg->size == 0)
77f180099ec619325d28c6a76a38df5419ef69651eThomas Heller    return FFI_BAD_TYPEDEF;
78f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  else
79f180099ec619325d28c6a76a38df5419ef69651eThomas Heller    return FFI_OK;
80f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
81f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  /*@=usedef@*/
82f180099ec619325d28c6a76a38df5419ef69651eThomas Heller}
83f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
84f180099ec619325d28c6a76a38df5419ef69651eThomas Heller/* Perform machine independent ffi_cif preparation, then call
85f180099ec619325d28c6a76a38df5419ef69651eThomas Heller   machine dependent routine. */
86f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
87f180099ec619325d28c6a76a38df5419ef69651eThomas Hellerffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif,
88f180099ec619325d28c6a76a38df5419ef69651eThomas Heller			ffi_abi abi, unsigned int nargs,
89f180099ec619325d28c6a76a38df5419ef69651eThomas Heller			/*@dependent@*/ /*@out@*/ /*@partial@*/ ffi_type *rtype,
90f180099ec619325d28c6a76a38df5419ef69651eThomas Heller			/*@dependent@*/ ffi_type **atypes)
91f180099ec619325d28c6a76a38df5419ef69651eThomas Heller{
92f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  unsigned bytes = 0;
93f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  unsigned int i;
94f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  ffi_type **ptr;
95f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
96f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  FFI_ASSERT(cif != NULL);
97f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  FFI_ASSERT((abi > FFI_FIRST_ABI) && (abi <= FFI_DEFAULT_ABI));
98f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
99f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  cif->abi = abi;
100f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  cif->arg_types = atypes;
101f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  cif->nargs = nargs;
102f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  cif->rtype = rtype;
103f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
104f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  cif->flags = 0;
105f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
106f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  /* Initialize the return type if necessary */
107f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  /*@-usedef@*/
108f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK))
109f180099ec619325d28c6a76a38df5419ef69651eThomas Heller    return FFI_BAD_TYPEDEF;
110f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  /*@=usedef@*/
111f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
112f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  /* Perform a sanity check on the return type */
113f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  FFI_ASSERT_VALID_TYPE(cif->rtype);
114f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
115f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  /* x86-64 and s390 stack space allocation is handled in prep_machdep.  */
116f180099ec619325d28c6a76a38df5419ef69651eThomas Heller#if !defined M68K && !defined __x86_64__ && !defined S390
117f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  /* Make space for the return structure pointer */
118f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  if (cif->rtype->type == FFI_TYPE_STRUCT
11931221a7285938aae7cb98bffffe205c6e5bfe31cSteve Dower#ifdef _WIN32
12031221a7285938aae7cb98bffffe205c6e5bfe31cSteve Dower      && (cif->rtype->size > 8)  /* MSVC returns small structs in registers */
12131221a7285938aae7cb98bffffe205c6e5bfe31cSteve Dower#endif
122f180099ec619325d28c6a76a38df5419ef69651eThomas Heller#ifdef SPARC
123f180099ec619325d28c6a76a38df5419ef69651eThomas Heller      && (cif->abi != FFI_V9 || cif->rtype->size > 32)
124f180099ec619325d28c6a76a38df5419ef69651eThomas Heller#endif
125f180099ec619325d28c6a76a38df5419ef69651eThomas Heller      )
126f180099ec619325d28c6a76a38df5419ef69651eThomas Heller    bytes = STACK_ARG_SIZE(sizeof(void*));
127f180099ec619325d28c6a76a38df5419ef69651eThomas Heller#endif
128f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
129f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
130f180099ec619325d28c6a76a38df5419ef69651eThomas Heller    {
131f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
132f180099ec619325d28c6a76a38df5419ef69651eThomas Heller      /* Initialize any uninitialized aggregate type definitions */
133f180099ec619325d28c6a76a38df5419ef69651eThomas Heller      if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK))
134f180099ec619325d28c6a76a38df5419ef69651eThomas Heller	return FFI_BAD_TYPEDEF;
135f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
136f180099ec619325d28c6a76a38df5419ef69651eThomas Heller      /* Perform a sanity check on the argument type, do this
137f180099ec619325d28c6a76a38df5419ef69651eThomas Heller	 check after the initialization.  */
138f180099ec619325d28c6a76a38df5419ef69651eThomas Heller      FFI_ASSERT_VALID_TYPE(*ptr);
139f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
140f180099ec619325d28c6a76a38df5419ef69651eThomas Heller#if !defined __x86_64__ && !defined S390
141f180099ec619325d28c6a76a38df5419ef69651eThomas Heller#ifdef SPARC
142f180099ec619325d28c6a76a38df5419ef69651eThomas Heller      if (((*ptr)->type == FFI_TYPE_STRUCT
143f180099ec619325d28c6a76a38df5419ef69651eThomas Heller	   && ((*ptr)->size > 16 || cif->abi != FFI_V9))
144f180099ec619325d28c6a76a38df5419ef69651eThomas Heller	  || ((*ptr)->type == FFI_TYPE_LONGDOUBLE
145f180099ec619325d28c6a76a38df5419ef69651eThomas Heller	      && cif->abi != FFI_V9))
14631221a7285938aae7cb98bffffe205c6e5bfe31cSteve Dower	  bytes += sizeof(void*);
14731221a7285938aae7cb98bffffe205c6e5bfe31cSteve Dower      else
14831221a7285938aae7cb98bffffe205c6e5bfe31cSteve Dower#elif defined (_WIN64)
14931221a7285938aae7cb98bffffe205c6e5bfe31cSteve Dower      if ((*ptr)->type == FFI_TYPE_STRUCT && ((*ptr)->size > 8))
15031221a7285938aae7cb98bffffe205c6e5bfe31cSteve Dower	    bytes += sizeof(void*);
151f180099ec619325d28c6a76a38df5419ef69651eThomas Heller      else
152f180099ec619325d28c6a76a38df5419ef69651eThomas Heller#endif
153f180099ec619325d28c6a76a38df5419ef69651eThomas Heller	{
154f180099ec619325d28c6a76a38df5419ef69651eThomas Heller#if !defined(_MSC_VER) && !defined(__MINGW32__)
155f180099ec619325d28c6a76a38df5419ef69651eThomas Heller		/* Don't know if this is a libffi bug or not.  At least on
156f180099ec619325d28c6a76a38df5419ef69651eThomas Heller		   Windows with MSVC, function call parameters are *not*
157f180099ec619325d28c6a76a38df5419ef69651eThomas Heller		   aligned in the same way as structure fields are, they are
158f180099ec619325d28c6a76a38df5419ef69651eThomas Heller		   only aligned in integer boundaries.
159f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
160f180099ec619325d28c6a76a38df5419ef69651eThomas Heller		   This doesn't do any harm for cdecl functions and closures,
161f180099ec619325d28c6a76a38df5419ef69651eThomas Heller		   since the caller cleans up the stack, but it is wrong for
162f180099ec619325d28c6a76a38df5419ef69651eThomas Heller		   stdcall functions where the callee cleans.
163f180099ec619325d28c6a76a38df5419ef69651eThomas Heller		*/
164f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
165f180099ec619325d28c6a76a38df5419ef69651eThomas Heller	  /* Add any padding if necessary */
166f180099ec619325d28c6a76a38df5419ef69651eThomas Heller	  if (((*ptr)->alignment - 1) & bytes)
167f180099ec619325d28c6a76a38df5419ef69651eThomas Heller	    bytes = ALIGN(bytes, (*ptr)->alignment);
168f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
169f180099ec619325d28c6a76a38df5419ef69651eThomas Heller#endif
170f180099ec619325d28c6a76a38df5419ef69651eThomas Heller	  bytes += STACK_ARG_SIZE((*ptr)->size);
171f180099ec619325d28c6a76a38df5419ef69651eThomas Heller	}
172f180099ec619325d28c6a76a38df5419ef69651eThomas Heller#endif
173f180099ec619325d28c6a76a38df5419ef69651eThomas Heller    }
174f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
17531221a7285938aae7cb98bffffe205c6e5bfe31cSteve Dower#ifdef _WIN64
17631221a7285938aae7cb98bffffe205c6e5bfe31cSteve Dower  /* Function call needs at least 40 bytes stack size, on win64 AMD64 */
17731221a7285938aae7cb98bffffe205c6e5bfe31cSteve Dower  if (bytes < 40)
17831221a7285938aae7cb98bffffe205c6e5bfe31cSteve Dower      bytes = 40;
17931221a7285938aae7cb98bffffe205c6e5bfe31cSteve Dower#endif
18031221a7285938aae7cb98bffffe205c6e5bfe31cSteve Dower
181f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  cif->bytes = bytes;
182f180099ec619325d28c6a76a38df5419ef69651eThomas Heller
183f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  /* Perform machine dependent cif processing */
184f180099ec619325d28c6a76a38df5419ef69651eThomas Heller  return ffi_prep_cif_machdep(cif);
185f180099ec619325d28c6a76a38df5419ef69651eThomas Heller}
186