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