Line data Source code
1 : /* -----------------------------------------------------------------------
2 : prep_cif.c - Copyright (c) 2011, 2012 Anthony Green
3 : Copyright (c) 1996, 1998, 2007 Red Hat, Inc.
4 :
5 : Permission is hereby granted, free of charge, to any person obtaining
6 : a copy of this software and associated documentation files (the
7 : ``Software''), to deal in the Software without restriction, including
8 : without limitation the rights to use, copy, modify, merge, publish,
9 : distribute, sublicense, and/or sell copies of the Software, and to
10 : permit persons to whom the Software is furnished to do so, subject to
11 : the following conditions:
12 :
13 : The above copyright notice and this permission notice shall be included
14 : in all copies or substantial portions of the Software.
15 :
16 : THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
17 : EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 : MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 : NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20 : HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 : WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 : DEALINGS IN THE SOFTWARE.
24 : ----------------------------------------------------------------------- */
25 :
26 : #include <ffi.h>
27 : #include <ffi_common.h>
28 : #include <stdlib.h>
29 :
30 : /* Round up to FFI_SIZEOF_ARG. */
31 :
32 : #define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG)
33 :
34 : /* Perform machine independent initialization of aggregate type
35 : specifications. */
36 :
37 0 : static ffi_status initialize_aggregate(ffi_type *arg)
38 : {
39 : ffi_type **ptr;
40 :
41 0 : if (UNLIKELY(arg == NULL || arg->elements == NULL))
42 0 : return FFI_BAD_TYPEDEF;
43 :
44 0 : arg->size = 0;
45 0 : arg->alignment = 0;
46 :
47 0 : ptr = &(arg->elements[0]);
48 :
49 0 : if (UNLIKELY(ptr == 0))
50 0 : return FFI_BAD_TYPEDEF;
51 :
52 0 : while ((*ptr) != NULL)
53 : {
54 0 : if (UNLIKELY(((*ptr)->size == 0)
55 : && (initialize_aggregate((*ptr)) != FFI_OK)))
56 0 : return FFI_BAD_TYPEDEF;
57 :
58 : /* Perform a sanity check on the argument type */
59 : FFI_ASSERT_VALID_TYPE(*ptr);
60 :
61 0 : arg->size = ALIGN(arg->size, (*ptr)->alignment);
62 0 : arg->size += (*ptr)->size;
63 :
64 0 : arg->alignment = (arg->alignment > (*ptr)->alignment) ?
65 0 : arg->alignment : (*ptr)->alignment;
66 :
67 0 : ptr++;
68 : }
69 :
70 : /* Structure size includes tail padding. This is important for
71 : structures that fit in one register on ABIs like the PowerPC64
72 : Linux ABI that right justify small structs in a register.
73 : It's also needed for nested structure layout, for example
74 : struct A { long a; char b; }; struct B { struct A x; char y; };
75 : should find y at an offset of 2*sizeof(long) and result in a
76 : total size of 3*sizeof(long). */
77 0 : arg->size = ALIGN (arg->size, arg->alignment);
78 :
79 0 : if (arg->size == 0)
80 0 : return FFI_BAD_TYPEDEF;
81 : else
82 0 : return FFI_OK;
83 : }
84 :
85 : #ifndef __CRIS__
86 : /* The CRIS ABI specifies structure elements to have byte
87 : alignment only, so it completely overrides this functions,
88 : which assumes "natural" alignment and padding. */
89 :
90 : /* Perform machine independent ffi_cif preparation, then call
91 : machine dependent routine. */
92 :
93 : /* For non variadic functions isvariadic should be 0 and
94 : nfixedargs==ntotalargs.
95 :
96 : For variadic calls, isvariadic should be 1 and nfixedargs
97 : and ntotalargs set as appropriate. nfixedargs must always be >=1 */
98 :
99 :
100 0 : ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi,
101 : unsigned int isvariadic,
102 : unsigned int nfixedargs,
103 : unsigned int ntotalargs,
104 : ffi_type *rtype, ffi_type **atypes)
105 : {
106 0 : unsigned bytes = 0;
107 : unsigned int i;
108 : ffi_type **ptr;
109 :
110 : FFI_ASSERT(cif != NULL);
111 : FFI_ASSERT((!isvariadic) || (nfixedargs >= 1));
112 : FFI_ASSERT(nfixedargs <= ntotalargs);
113 :
114 : #ifndef X86_WIN32
115 0 : if (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI))
116 0 : return FFI_BAD_ABI;
117 : #else
118 : if (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI || abi == FFI_THISCALL))
119 : return FFI_BAD_ABI;
120 : #endif
121 :
122 0 : cif->abi = abi;
123 0 : cif->arg_types = atypes;
124 0 : cif->nargs = ntotalargs;
125 0 : cif->rtype = rtype;
126 :
127 0 : cif->flags = 0;
128 :
129 : /* Initialize the return type if necessary */
130 0 : if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK))
131 0 : return FFI_BAD_TYPEDEF;
132 :
133 : /* Perform a sanity check on the return type */
134 : FFI_ASSERT_VALID_TYPE(cif->rtype);
135 :
136 : /* x86, x86-64 and s390 stack space allocation is handled in prep_machdep. */
137 : #if !defined M68K && !defined X86_ANY && !defined S390 && !defined PA
138 : /* Make space for the return structure pointer */
139 : if (cif->rtype->type == FFI_TYPE_STRUCT
140 : #ifdef SPARC
141 : && (cif->abi != FFI_V9 || cif->rtype->size > 32)
142 : #endif
143 : )
144 : bytes = STACK_ARG_SIZE(sizeof(void*));
145 : #endif
146 :
147 0 : for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
148 : {
149 :
150 : /* Initialize any uninitialized aggregate type definitions */
151 0 : if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK))
152 0 : return FFI_BAD_TYPEDEF;
153 :
154 : /* Perform a sanity check on the argument type, do this
155 : check after the initialization. */
156 : FFI_ASSERT_VALID_TYPE(*ptr);
157 :
158 : #if !defined X86_ANY && !defined S390 && !defined PA
159 : #ifdef SPARC
160 : if (((*ptr)->type == FFI_TYPE_STRUCT
161 : && ((*ptr)->size > 16 || cif->abi != FFI_V9))
162 : || ((*ptr)->type == FFI_TYPE_LONGDOUBLE
163 : && cif->abi != FFI_V9))
164 : bytes += sizeof(void*);
165 : else
166 : #endif
167 : {
168 : /* Add any padding if necessary */
169 : if (((*ptr)->alignment - 1) & bytes)
170 : bytes = ALIGN(bytes, (*ptr)->alignment);
171 :
172 : bytes += STACK_ARG_SIZE((*ptr)->size);
173 : }
174 : #endif
175 : }
176 :
177 0 : cif->bytes = bytes;
178 :
179 : /* Perform machine dependent cif processing */
180 : #ifdef FFI_TARGET_SPECIFIC_VARIADIC
181 : if (isvariadic)
182 : return ffi_prep_cif_machdep_var(cif, nfixedargs, ntotalargs);
183 : #endif
184 :
185 0 : return ffi_prep_cif_machdep(cif);
186 : }
187 : #endif /* not __CRIS__ */
188 :
189 0 : ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs,
190 : ffi_type *rtype, ffi_type **atypes)
191 : {
192 0 : return ffi_prep_cif_core(cif, abi, 0, nargs, nargs, rtype, atypes);
193 : }
194 :
195 0 : ffi_status ffi_prep_cif_var(ffi_cif *cif,
196 : ffi_abi abi,
197 : unsigned int nfixedargs,
198 : unsigned int ntotalargs,
199 : ffi_type *rtype,
200 : ffi_type **atypes)
201 : {
202 0 : return ffi_prep_cif_core(cif, abi, 1, nfixedargs, ntotalargs, rtype, atypes);
203 : }
204 :
205 : #if FFI_CLOSURES
206 :
207 : ffi_status
208 0 : ffi_prep_closure (ffi_closure* closure,
209 : ffi_cif* cif,
210 : void (*fun)(ffi_cif*,void*,void**,void*),
211 : void *user_data)
212 : {
213 0 : return ffi_prep_closure_loc (closure, cif, fun, user_data, closure);
214 : }
215 :
216 : #endif
|