]>
Commit | Line | Data |
---|---|---|
63e5e3e0 | 1 | /* ----------------------------------------------------------------------- |
34fa7690 AG |
2 | ffi.c - Copyright (C) 2011 Anthony Green |
3 | Copyright (C) 2011 Kyle Moffett | |
4 | Copyright (C) 2008 Red Hat, Inc | |
5 | Copyright (C) 2007, 2008 Free Software Foundation, Inc | |
6 | Copyright (c) 1998 Geoffrey Keating | |
63e5e3e0 | 7 | |
16070e45 | 8 | PowerPC Foreign Function Interface |
63e5e3e0 AG |
9 | |
10 | Permission is hereby granted, free of charge, to any person obtaining | |
11 | a copy of this software and associated documentation files (the | |
12 | ``Software''), to deal in the Software without restriction, including | |
13 | without limitation the rights to use, copy, modify, merge, publish, | |
14 | distribute, sublicense, and/or sell copies of the Software, and to | |
15 | permit persons to whom the Software is furnished to do so, subject to | |
16 | the following conditions: | |
17 | ||
18 | The above copyright notice and this permission notice shall be included | |
19 | in all copies or substantial portions of the Software. | |
20 | ||
21 | THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS | |
22 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
23 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
24 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
25 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
26 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
27 | OTHER DEALINGS IN THE SOFTWARE. | |
28 | ----------------------------------------------------------------------- */ | |
29 | ||
30 | #include <ffi.h> | |
31 | #include <ffi_common.h> | |
32 | ||
33 | #include <stdlib.h> | |
cc4c8975 KH |
34 | #include <stdio.h> |
35 | ||
e9b84181 | 36 | |
cd4241aa AM |
37 | extern void ffi_closure_SYSV (void); |
38 | extern void FFI_HIDDEN ffi_closure_LINUX64 (void); | |
63e5e3e0 AG |
39 | |
40 | enum { | |
41 | /* The assembly depends on these exact flags. */ | |
97067642 | 42 | FLAG_RETURNS_SMST = 1 << (31-31), /* Used for FFI_SYSV small structs. */ |
63e5e3e0 | 43 | FLAG_RETURNS_NOTHING = 1 << (31-30), /* These go in cr7 */ |
34fa7690 | 44 | #ifndef __NO_FPRS__ |
63e5e3e0 | 45 | FLAG_RETURNS_FP = 1 << (31-29), |
34fa7690 | 46 | #endif |
63e5e3e0 | 47 | FLAG_RETURNS_64BITS = 1 << (31-28), |
e84296c6 AT |
48 | |
49 | FLAG_RETURNS_128BITS = 1 << (31-27), /* cr6 */ | |
6975f17f | 50 | |
63e5e3e0 | 51 | FLAG_ARG_NEEDS_COPY = 1 << (31- 7), |
34fa7690 | 52 | #ifndef __NO_FPRS__ |
63e5e3e0 | 53 | FLAG_FP_ARGUMENTS = 1 << (31- 6), /* cr1.eq; specified by ABI */ |
34fa7690 | 54 | #endif |
63e5e3e0 AG |
55 | FLAG_4_GPR_ARGUMENTS = 1 << (31- 5), |
56 | FLAG_RETVAL_REFERENCE = 1 << (31- 4) | |
57 | }; | |
58 | ||
59 | /* About the SYSV ABI. */ | |
34fa7690 AG |
60 | #define ASM_NEEDS_REGISTERS 4 |
61 | #define NUM_GPR_ARG_REGISTERS 8 | |
16287148 | 62 | #ifndef __NO_FPRS__ |
34fa7690 | 63 | # define NUM_FPR_ARG_REGISTERS 8 |
16287148 AT |
64 | #endif |
65 | ||
e9b84181 | 66 | /* ffi_prep_args_SYSV is called by the assembly routine once stack space |
63e5e3e0 AG |
67 | has been allocated for the function's arguments. |
68 | ||
69 | The stack layout we want looks like this: | |
70 | ||
71 | | Return address from ffi_call_SYSV 4bytes | higher addresses | |
72 | |--------------------------------------------| | |
16070e45 | 73 | | Previous backchain pointer 4 | stack pointer here |
63e5e3e0 AG |
74 | |--------------------------------------------|<+ <<< on entry to |
75 | | Saved r28-r31 4*4 | | ffi_call_SYSV | |
76 | |--------------------------------------------| | | |
77 | | GPR registers r3-r10 8*4 | | ffi_call_SYSV | |
78 | |--------------------------------------------| | | |
79 | | FPR registers f1-f8 (optional) 8*8 | | | |
80 | |--------------------------------------------| | stack | | |
81 | | Space for copied structures | | grows | | |
82 | |--------------------------------------------| | down V | |
83 | | Parameters that didn't fit in registers | | | |
84 | |--------------------------------------------| | lower addresses | |
85 | | Space for callee's LR 4 | | | |
86 | |--------------------------------------------| | stack pointer here | |
87 | | Current backchain pointer 4 |-/ during | |
88 | |--------------------------------------------| <<< ffi_call_SYSV | |
89 | ||
16070e45 | 90 | */ |
63e5e3e0 | 91 | |
cd4241aa AM |
92 | void |
93 | ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack) | |
63e5e3e0 AG |
94 | { |
95 | const unsigned bytes = ecif->cif->bytes; | |
96 | const unsigned flags = ecif->cif->flags; | |
16070e45 | 97 | |
cd4241aa AM |
98 | typedef union { |
99 | char *c; | |
100 | unsigned *u; | |
101 | long long *ll; | |
102 | float *f; | |
103 | double *d; | |
104 | } valp; | |
105 | ||
63e5e3e0 | 106 | /* 'stacktop' points at the previous backchain pointer. */ |
cd4241aa | 107 | valp stacktop; |
63e5e3e0 AG |
108 | |
109 | /* 'gpr_base' points at the space for gpr3, and grows upwards as | |
110 | we use GPR registers. */ | |
cd4241aa AM |
111 | valp gpr_base; |
112 | int intarg_count; | |
63e5e3e0 | 113 | |
34fa7690 | 114 | #ifndef __NO_FPRS__ |
63e5e3e0 AG |
115 | /* 'fpr_base' points at the space for fpr1, and grows upwards as |
116 | we use FPR registers. */ | |
cd4241aa AM |
117 | valp fpr_base; |
118 | int fparg_count; | |
34fa7690 | 119 | #endif |
63e5e3e0 AG |
120 | |
121 | /* 'copy_space' grows down as we put structures in it. It should | |
122 | stay 16-byte aligned. */ | |
cd4241aa | 123 | valp copy_space; |
63e5e3e0 AG |
124 | |
125 | /* 'next_arg' grows up as we put parameters in it. */ | |
cd4241aa | 126 | valp next_arg; |
63e5e3e0 | 127 | |
34fa7690 | 128 | int i; |
63e5e3e0 | 129 | ffi_type **ptr; |
40b45a6d AM |
130 | #ifndef __NO_FPRS__ |
131 | double double_tmp; | |
132 | #endif | |
cd4241aa AM |
133 | union { |
134 | void **v; | |
135 | char **c; | |
136 | signed char **sc; | |
137 | unsigned char **uc; | |
138 | signed short **ss; | |
139 | unsigned short **us; | |
140 | unsigned int **ui; | |
141 | long long **ll; | |
142 | float **f; | |
143 | double **d; | |
144 | } p_argv; | |
63e5e3e0 AG |
145 | size_t struct_copy_size; |
146 | unsigned gprvalue; | |
147 | ||
cd4241aa AM |
148 | stacktop.c = (char *) stack + bytes; |
149 | gpr_base.u = stacktop.u - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS; | |
150 | intarg_count = 0; | |
34fa7690 | 151 | #ifndef __NO_FPRS__ |
cd4241aa AM |
152 | fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS; |
153 | fparg_count = 0; | |
154 | copy_space.c = ((flags & FLAG_FP_ARGUMENTS) ? fpr_base.c : gpr_base.c); | |
34fa7690 AG |
155 | #else |
156 | copy_space.c = gpr_base.c; | |
157 | #endif | |
cd4241aa AM |
158 | next_arg.u = stack + 2; |
159 | ||
63e5e3e0 | 160 | /* Check that everything starts aligned properly. */ |
efe2a4b7 PB |
161 | FFI_ASSERT (((unsigned long) (char *) stack & 0xF) == 0); |
162 | FFI_ASSERT (((unsigned long) copy_space.c & 0xF) == 0); | |
163 | FFI_ASSERT (((unsigned long) stacktop.c & 0xF) == 0); | |
cd4241aa AM |
164 | FFI_ASSERT ((bytes & 0xF) == 0); |
165 | FFI_ASSERT (copy_space.c >= next_arg.c); | |
63e5e3e0 AG |
166 | |
167 | /* Deal with return values that are actually pass-by-reference. */ | |
168 | if (flags & FLAG_RETVAL_REFERENCE) | |
16070e45 | 169 | { |
cd4241aa | 170 | *gpr_base.u++ = (unsigned long) (char *) ecif->rvalue; |
16070e45 AT |
171 | intarg_count++; |
172 | } | |
63e5e3e0 AG |
173 | |
174 | /* Now for the arguments. */ | |
cd4241aa | 175 | p_argv.v = ecif->avalue; |
63e5e3e0 AG |
176 | for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs; |
177 | i > 0; | |
cd4241aa | 178 | i--, ptr++, p_argv.v++) |
63e5e3e0 | 179 | { |
34fa7690 AG |
180 | unsigned short typenum = (*ptr)->type; |
181 | ||
182 | /* We may need to handle some values depending on ABI */ | |
183 | if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT) { | |
184 | if (typenum == FFI_TYPE_FLOAT) | |
185 | typenum = FFI_TYPE_UINT32; | |
186 | if (typenum == FFI_TYPE_DOUBLE) | |
187 | typenum = FFI_TYPE_UINT64; | |
188 | if (typenum == FFI_TYPE_LONGDOUBLE) | |
189 | typenum = FFI_TYPE_UINT128; | |
190 | } else if (ecif->cif->abi != FFI_LINUX) { | |
191 | #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE | |
192 | if (typenum == FFI_TYPE_LONGDOUBLE) | |
193 | typenum = FFI_TYPE_STRUCT; | |
194 | #endif | |
195 | } | |
196 | ||
197 | /* Now test the translated value */ | |
198 | switch (typenum) { | |
199 | #ifndef __NO_FPRS__ | |
63e5e3e0 | 200 | case FFI_TYPE_FLOAT: |
16287148 | 201 | /* With FFI_LINUX_SOFT_FLOAT floats are handled like UINT32. */ |
cd4241aa | 202 | double_tmp = **p_argv.f; |
7b5102af TT |
203 | if (fparg_count >= NUM_FPR_ARG_REGISTERS) |
204 | { | |
cd4241aa AM |
205 | *next_arg.f = (float) double_tmp; |
206 | next_arg.u += 1; | |
302486f4 | 207 | intarg_count++; |
7b5102af | 208 | } |
63e5e3e0 | 209 | else |
cd4241aa | 210 | *fpr_base.d++ = double_tmp; |
7b5102af | 211 | fparg_count++; |
cd4241aa | 212 | FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); |
7b5102af TT |
213 | break; |
214 | ||
215 | case FFI_TYPE_DOUBLE: | |
16287148 | 216 | /* With FFI_LINUX_SOFT_FLOAT doubles are handled like UINT64. */ |
cd4241aa | 217 | double_tmp = **p_argv.d; |
63e5e3e0 AG |
218 | |
219 | if (fparg_count >= NUM_FPR_ARG_REGISTERS) | |
220 | { | |
2d9c5743 AM |
221 | if (intarg_count >= NUM_GPR_ARG_REGISTERS |
222 | && intarg_count % 2 != 0) | |
63e5e3e0 AG |
223 | { |
224 | intarg_count++; | |
cd4241aa | 225 | next_arg.u++; |
63e5e3e0 | 226 | } |
cd4241aa AM |
227 | *next_arg.d = double_tmp; |
228 | next_arg.u += 2; | |
63e5e3e0 AG |
229 | } |
230 | else | |
cd4241aa | 231 | *fpr_base.d++ = double_tmp; |
63e5e3e0 | 232 | fparg_count++; |
cd4241aa | 233 | FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); |
63e5e3e0 AG |
234 | break; |
235 | ||
75b8b1be AM |
236 | #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE |
237 | case FFI_TYPE_LONGDOUBLE: | |
16287148 | 238 | double_tmp = (*p_argv.d)[0]; |
75b8b1be | 239 | |
16287148 AT |
240 | if (fparg_count >= NUM_FPR_ARG_REGISTERS - 1) |
241 | { | |
242 | if (intarg_count >= NUM_GPR_ARG_REGISTERS | |
243 | && intarg_count % 2 != 0) | |
244 | { | |
245 | intarg_count++; | |
246 | next_arg.u++; | |
247 | } | |
248 | *next_arg.d = double_tmp; | |
249 | next_arg.u += 2; | |
250 | double_tmp = (*p_argv.d)[1]; | |
251 | *next_arg.d = double_tmp; | |
252 | next_arg.u += 2; | |
253 | } | |
254 | else | |
255 | { | |
256 | *fpr_base.d++ = double_tmp; | |
257 | double_tmp = (*p_argv.d)[1]; | |
258 | *fpr_base.d++ = double_tmp; | |
259 | } | |
260 | ||
261 | fparg_count += 2; | |
262 | FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); | |
75b8b1be AM |
263 | break; |
264 | #endif | |
34fa7690 AG |
265 | #endif /* have FPRs */ |
266 | ||
267 | /* | |
268 | * The soft float ABI for long doubles works like this, a long double | |
269 | * is passed in four consecutive GPRs if available. A maximum of 2 | |
270 | * long doubles can be passed in gprs. If we do not have 4 GPRs | |
271 | * left, the long double is passed on the stack, 4-byte aligned. | |
272 | */ | |
273 | case FFI_TYPE_UINT128: { | |
274 | unsigned int int_tmp = (*p_argv.ui)[0]; | |
275 | unsigned int ii; | |
276 | if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3) { | |
277 | if (intarg_count < NUM_GPR_ARG_REGISTERS) | |
278 | intarg_count += NUM_GPR_ARG_REGISTERS - intarg_count; | |
279 | *(next_arg.u++) = int_tmp; | |
280 | for (ii = 1; ii < 4; ii++) { | |
281 | int_tmp = (*p_argv.ui)[ii]; | |
282 | *(next_arg.u++) = int_tmp; | |
283 | } | |
284 | } else { | |
285 | *(gpr_base.u++) = int_tmp; | |
286 | for (ii = 1; ii < 4; ii++) { | |
287 | int_tmp = (*p_argv.ui)[ii]; | |
288 | *(gpr_base.u++) = int_tmp; | |
289 | } | |
290 | } | |
291 | intarg_count += 4; | |
292 | break; | |
293 | } | |
75b8b1be | 294 | |
63e5e3e0 AG |
295 | case FFI_TYPE_UINT64: |
296 | case FFI_TYPE_SINT64: | |
297 | if (intarg_count == NUM_GPR_ARG_REGISTERS-1) | |
298 | intarg_count++; | |
299 | if (intarg_count >= NUM_GPR_ARG_REGISTERS) | |
300 | { | |
cd4241aa | 301 | if (intarg_count % 2 != 0) |
63e5e3e0 AG |
302 | { |
303 | intarg_count++; | |
cd4241aa | 304 | next_arg.u++; |
63e5e3e0 | 305 | } |
cd4241aa AM |
306 | *next_arg.ll = **p_argv.ll; |
307 | next_arg.u += 2; | |
63e5e3e0 AG |
308 | } |
309 | else | |
310 | { | |
16070e45 AT |
311 | /* whoops: abi states only certain register pairs |
312 | * can be used for passing long long int | |
313 | * specifically (r3,r4), (r5,r6), (r7,r8), | |
314 | * (r9,r10) and if next arg is long long but | |
315 | * not correct starting register of pair then skip | |
316 | * until the proper starting register | |
cc4c8975 | 317 | */ |
cd4241aa | 318 | if (intarg_count % 2 != 0) |
16070e45 AT |
319 | { |
320 | intarg_count ++; | |
cd4241aa | 321 | gpr_base.u++; |
16070e45 | 322 | } |
cd4241aa | 323 | *gpr_base.ll++ = **p_argv.ll; |
63e5e3e0 AG |
324 | } |
325 | intarg_count += 2; | |
326 | break; | |
327 | ||
328 | case FFI_TYPE_STRUCT: | |
63e5e3e0 | 329 | struct_copy_size = ((*ptr)->size + 15) & ~0xF; |
cd4241aa AM |
330 | copy_space.c -= struct_copy_size; |
331 | memcpy (copy_space.c, *p_argv.c, (*ptr)->size); | |
16070e45 | 332 | |
cd4241aa | 333 | gprvalue = (unsigned long) copy_space.c; |
63e5e3e0 | 334 | |
cd4241aa AM |
335 | FFI_ASSERT (copy_space.c > next_arg.c); |
336 | FFI_ASSERT (flags & FLAG_ARG_NEEDS_COPY); | |
63e5e3e0 AG |
337 | goto putgpr; |
338 | ||
339 | case FFI_TYPE_UINT8: | |
cd4241aa | 340 | gprvalue = **p_argv.uc; |
63e5e3e0 AG |
341 | goto putgpr; |
342 | case FFI_TYPE_SINT8: | |
cd4241aa | 343 | gprvalue = **p_argv.sc; |
63e5e3e0 AG |
344 | goto putgpr; |
345 | case FFI_TYPE_UINT16: | |
cd4241aa | 346 | gprvalue = **p_argv.us; |
63e5e3e0 AG |
347 | goto putgpr; |
348 | case FFI_TYPE_SINT16: | |
cd4241aa | 349 | gprvalue = **p_argv.ss; |
63e5e3e0 AG |
350 | goto putgpr; |
351 | ||
352 | case FFI_TYPE_INT: | |
353 | case FFI_TYPE_UINT32: | |
354 | case FFI_TYPE_SINT32: | |
355 | case FFI_TYPE_POINTER: | |
16287148 | 356 | |
cd4241aa AM |
357 | gprvalue = **p_argv.ui; |
358 | ||
63e5e3e0 AG |
359 | putgpr: |
360 | if (intarg_count >= NUM_GPR_ARG_REGISTERS) | |
cd4241aa | 361 | *next_arg.u++ = gprvalue; |
63e5e3e0 | 362 | else |
cd4241aa | 363 | *gpr_base.u++ = gprvalue; |
63e5e3e0 AG |
364 | intarg_count++; |
365 | break; | |
366 | } | |
367 | } | |
368 | ||
369 | /* Check that we didn't overrun the stack... */ | |
cd4241aa AM |
370 | FFI_ASSERT (copy_space.c >= next_arg.c); |
371 | FFI_ASSERT (gpr_base.u <= stacktop.u - ASM_NEEDS_REGISTERS); | |
34fa7690 | 372 | #ifndef __NO_FPRS__ |
cd4241aa AM |
373 | FFI_ASSERT (fpr_base.u |
374 | <= stacktop.u - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS); | |
34fa7690 | 375 | #endif |
cd4241aa | 376 | FFI_ASSERT (flags & FLAG_4_GPR_ARGUMENTS || intarg_count <= 4); |
63e5e3e0 AG |
377 | } |
378 | ||
e9b84181 JJ |
379 | /* About the LINUX64 ABI. */ |
380 | enum { | |
381 | NUM_GPR_ARG_REGISTERS64 = 8, | |
382 | NUM_FPR_ARG_REGISTERS64 = 13 | |
383 | }; | |
384 | enum { ASM_NEEDS_REGISTERS64 = 4 }; | |
385 | ||
386 | /* ffi_prep_args64 is called by the assembly routine once stack space | |
387 | has been allocated for the function's arguments. | |
388 | ||
389 | The stack layout we want looks like this: | |
390 | ||
391 | | Ret addr from ffi_call_LINUX64 8bytes | higher addresses | |
392 | |--------------------------------------------| | |
393 | | CR save area 8bytes | | |
394 | |--------------------------------------------| | |
16070e45 | 395 | | Previous backchain pointer 8 | stack pointer here |
e9b84181 JJ |
396 | |--------------------------------------------|<+ <<< on entry to |
397 | | Saved r28-r31 4*8 | | ffi_call_LINUX64 | |
398 | |--------------------------------------------| | | |
399 | | GPR registers r3-r10 8*8 | | | |
400 | |--------------------------------------------| | | |
401 | | FPR registers f1-f13 (optional) 13*8 | | | |
402 | |--------------------------------------------| | | |
403 | | Parameter save area | | | |
404 | |--------------------------------------------| | | |
405 | | TOC save area 8 | | | |
406 | |--------------------------------------------| | stack | | |
b00badcd | 407 | | Linker doubleword 8 | | grows | |
e9b84181 JJ |
408 | |--------------------------------------------| | down V |
409 | | Compiler doubleword 8 | | | |
410 | |--------------------------------------------| | lower addresses | |
411 | | Space for callee's LR 8 | | | |
412 | |--------------------------------------------| | | |
413 | | CR save area 8 | | | |
414 | |--------------------------------------------| | stack pointer here | |
415 | | Current backchain pointer 8 |-/ during | |
416 | |--------------------------------------------| <<< ffi_call_LINUX64 | |
417 | ||
16070e45 | 418 | */ |
e9b84181 | 419 | |
cd4241aa AM |
420 | void FFI_HIDDEN |
421 | ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack) | |
e9b84181 JJ |
422 | { |
423 | const unsigned long bytes = ecif->cif->bytes; | |
424 | const unsigned long flags = ecif->cif->flags; | |
425 | ||
cd4241aa AM |
426 | typedef union { |
427 | char *c; | |
428 | unsigned long *ul; | |
429 | float *f; | |
430 | double *d; | |
431 | } valp; | |
432 | ||
e9b84181 | 433 | /* 'stacktop' points at the previous backchain pointer. */ |
cd4241aa | 434 | valp stacktop; |
e9b84181 JJ |
435 | |
436 | /* 'next_arg' points at the space for gpr3, and grows upwards as | |
437 | we use GPR registers, then continues at rest. */ | |
cd4241aa AM |
438 | valp gpr_base; |
439 | valp gpr_end; | |
440 | valp rest; | |
441 | valp next_arg; | |
e9b84181 JJ |
442 | |
443 | /* 'fpr_base' points at the space for fpr3, and grows upwards as | |
444 | we use FPR registers. */ | |
cd4241aa AM |
445 | valp fpr_base; |
446 | int fparg_count; | |
e9b84181 JJ |
447 | |
448 | int i, words; | |
449 | ffi_type **ptr; | |
450 | double double_tmp; | |
cd4241aa AM |
451 | union { |
452 | void **v; | |
453 | char **c; | |
454 | signed char **sc; | |
455 | unsigned char **uc; | |
456 | signed short **ss; | |
457 | unsigned short **us; | |
458 | signed int **si; | |
459 | unsigned int **ui; | |
460 | unsigned long **ul; | |
461 | float **f; | |
462 | double **d; | |
463 | } p_argv; | |
e9b84181 JJ |
464 | unsigned long gprvalue; |
465 | ||
cd4241aa AM |
466 | stacktop.c = (char *) stack + bytes; |
467 | gpr_base.ul = stacktop.ul - ASM_NEEDS_REGISTERS64 - NUM_GPR_ARG_REGISTERS64; | |
468 | gpr_end.ul = gpr_base.ul + NUM_GPR_ARG_REGISTERS64; | |
469 | rest.ul = stack + 6 + NUM_GPR_ARG_REGISTERS64; | |
470 | fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS64; | |
471 | fparg_count = 0; | |
472 | next_arg.ul = gpr_base.ul; | |
473 | ||
e9b84181 | 474 | /* Check that everything starts aligned properly. */ |
cd4241aa AM |
475 | FFI_ASSERT (((unsigned long) (char *) stack & 0xF) == 0); |
476 | FFI_ASSERT (((unsigned long) stacktop.c & 0xF) == 0); | |
477 | FFI_ASSERT ((bytes & 0xF) == 0); | |
e9b84181 JJ |
478 | |
479 | /* Deal with return values that are actually pass-by-reference. */ | |
480 | if (flags & FLAG_RETVAL_REFERENCE) | |
cd4241aa | 481 | *next_arg.ul++ = (unsigned long) (char *) ecif->rvalue; |
e9b84181 JJ |
482 | |
483 | /* Now for the arguments. */ | |
cd4241aa | 484 | p_argv.v = ecif->avalue; |
e9b84181 JJ |
485 | for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs; |
486 | i > 0; | |
cd4241aa | 487 | i--, ptr++, p_argv.v++) |
e9b84181 JJ |
488 | { |
489 | switch ((*ptr)->type) | |
490 | { | |
491 | case FFI_TYPE_FLOAT: | |
cd4241aa AM |
492 | double_tmp = **p_argv.f; |
493 | *next_arg.f = (float) double_tmp; | |
494 | if (++next_arg.ul == gpr_end.ul) | |
495 | next_arg.ul = rest.ul; | |
e9b84181 | 496 | if (fparg_count < NUM_FPR_ARG_REGISTERS64) |
cd4241aa | 497 | *fpr_base.d++ = double_tmp; |
e9b84181 | 498 | fparg_count++; |
cd4241aa | 499 | FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); |
e9b84181 JJ |
500 | break; |
501 | ||
502 | case FFI_TYPE_DOUBLE: | |
cd4241aa AM |
503 | double_tmp = **p_argv.d; |
504 | *next_arg.d = double_tmp; | |
505 | if (++next_arg.ul == gpr_end.ul) | |
506 | next_arg.ul = rest.ul; | |
e9b84181 | 507 | if (fparg_count < NUM_FPR_ARG_REGISTERS64) |
cd4241aa | 508 | *fpr_base.d++ = double_tmp; |
e9b84181 | 509 | fparg_count++; |
cd4241aa | 510 | FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); |
e9b84181 JJ |
511 | break; |
512 | ||
e9b84181 JJ |
513 | #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE |
514 | case FFI_TYPE_LONGDOUBLE: | |
cd4241aa AM |
515 | double_tmp = (*p_argv.d)[0]; |
516 | *next_arg.d = double_tmp; | |
517 | if (++next_arg.ul == gpr_end.ul) | |
518 | next_arg.ul = rest.ul; | |
4243752c | 519 | if (fparg_count < NUM_FPR_ARG_REGISTERS64) |
cd4241aa | 520 | *fpr_base.d++ = double_tmp; |
4243752c | 521 | fparg_count++; |
cd4241aa AM |
522 | double_tmp = (*p_argv.d)[1]; |
523 | *next_arg.d = double_tmp; | |
524 | if (++next_arg.ul == gpr_end.ul) | |
525 | next_arg.ul = rest.ul; | |
4243752c | 526 | if (fparg_count < NUM_FPR_ARG_REGISTERS64) |
cd4241aa | 527 | *fpr_base.d++ = double_tmp; |
4243752c | 528 | fparg_count++; |
75b8b1be | 529 | FFI_ASSERT (__LDBL_MANT_DIG__ == 106); |
cd4241aa | 530 | FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); |
4243752c | 531 | break; |
e9b84181 | 532 | #endif |
4243752c AM |
533 | |
534 | case FFI_TYPE_STRUCT: | |
e9b84181 | 535 | words = ((*ptr)->size + 7) / 8; |
cd4241aa | 536 | if (next_arg.ul >= gpr_base.ul && next_arg.ul + words > gpr_end.ul) |
e9b84181 | 537 | { |
cd4241aa AM |
538 | size_t first = gpr_end.c - next_arg.c; |
539 | memcpy (next_arg.c, *p_argv.c, first); | |
540 | memcpy (rest.c, *p_argv.c + first, (*ptr)->size - first); | |
541 | next_arg.c = rest.c + words * 8 - first; | |
e9b84181 JJ |
542 | } |
543 | else | |
544 | { | |
cd4241aa | 545 | char *where = next_arg.c; |
b00badcd | 546 | |
40b45a6d | 547 | #ifndef __LITTLE_ENDIAN__ |
b00badcd AM |
548 | /* Structures with size less than eight bytes are passed |
549 | left-padded. */ | |
550 | if ((*ptr)->size < 8) | |
551 | where += 8 - (*ptr)->size; | |
40b45a6d | 552 | #endif |
cd4241aa AM |
553 | memcpy (where, *p_argv.c, (*ptr)->size); |
554 | next_arg.ul += words; | |
555 | if (next_arg.ul == gpr_end.ul) | |
556 | next_arg.ul = rest.ul; | |
e9b84181 JJ |
557 | } |
558 | break; | |
559 | ||
560 | case FFI_TYPE_UINT8: | |
cd4241aa | 561 | gprvalue = **p_argv.uc; |
e9b84181 JJ |
562 | goto putgpr; |
563 | case FFI_TYPE_SINT8: | |
cd4241aa | 564 | gprvalue = **p_argv.sc; |
e9b84181 JJ |
565 | goto putgpr; |
566 | case FFI_TYPE_UINT16: | |
cd4241aa | 567 | gprvalue = **p_argv.us; |
e9b84181 JJ |
568 | goto putgpr; |
569 | case FFI_TYPE_SINT16: | |
cd4241aa | 570 | gprvalue = **p_argv.ss; |
e9b84181 JJ |
571 | goto putgpr; |
572 | case FFI_TYPE_UINT32: | |
cd4241aa | 573 | gprvalue = **p_argv.ui; |
e9b84181 JJ |
574 | goto putgpr; |
575 | case FFI_TYPE_INT: | |
576 | case FFI_TYPE_SINT32: | |
cd4241aa | 577 | gprvalue = **p_argv.si; |
e9b84181 | 578 | goto putgpr; |
16070e45 | 579 | |
e9b84181 JJ |
580 | case FFI_TYPE_UINT64: |
581 | case FFI_TYPE_SINT64: | |
582 | case FFI_TYPE_POINTER: | |
cd4241aa | 583 | gprvalue = **p_argv.ul; |
e9b84181 | 584 | putgpr: |
cd4241aa AM |
585 | *next_arg.ul++ = gprvalue; |
586 | if (next_arg.ul == gpr_end.ul) | |
587 | next_arg.ul = rest.ul; | |
e9b84181 JJ |
588 | break; |
589 | } | |
590 | } | |
591 | ||
cd4241aa AM |
592 | FFI_ASSERT (flags & FLAG_4_GPR_ARGUMENTS |
593 | || (next_arg.ul >= gpr_base.ul | |
594 | && next_arg.ul <= gpr_base.ul + 4)); | |
e9b84181 JJ |
595 | } |
596 | ||
597 | ||
598 | ||
63e5e3e0 | 599 | /* Perform machine dependent cif processing */ |
cd4241aa AM |
600 | ffi_status |
601 | ffi_prep_cif_machdep (ffi_cif *cif) | |
63e5e3e0 | 602 | { |
e9b84181 | 603 | /* All this is for the SYSV and LINUX64 ABI. */ |
63e5e3e0 AG |
604 | int i; |
605 | ffi_type **ptr; | |
606 | unsigned bytes; | |
607 | int fparg_count = 0, intarg_count = 0; | |
608 | unsigned flags = 0; | |
609 | unsigned struct_copy_size = 0; | |
bf310028 | 610 | unsigned type = cif->rtype->type; |
97067642 | 611 | unsigned size = cif->rtype->size; |
63e5e3e0 | 612 | |
e9b84181 | 613 | if (cif->abi != FFI_LINUX64) |
16070e45 | 614 | { |
e9b84181 JJ |
615 | /* All the machine-independent calculation of cif->bytes will be wrong. |
616 | Redo the calculation for SYSV. */ | |
63e5e3e0 | 617 | |
e9b84181 | 618 | /* Space for the frame pointer, callee's LR, and the asm's temp regs. */ |
cd4241aa | 619 | bytes = (2 + ASM_NEEDS_REGISTERS) * sizeof (int); |
63e5e3e0 | 620 | |
e9b84181 | 621 | /* Space for the GPR registers. */ |
cd4241aa | 622 | bytes += NUM_GPR_ARG_REGISTERS * sizeof (int); |
e9b84181 JJ |
623 | } |
624 | else | |
625 | { | |
626 | /* 64-bit ABI. */ | |
627 | ||
628 | /* Space for backchain, CR, LR, cc/ld doubleword, TOC and the asm's temp | |
629 | regs. */ | |
cd4241aa | 630 | bytes = (6 + ASM_NEEDS_REGISTERS64) * sizeof (long); |
e9b84181 JJ |
631 | |
632 | /* Space for the mandatory parm save area and general registers. */ | |
cd4241aa | 633 | bytes += 2 * NUM_GPR_ARG_REGISTERS64 * sizeof (long); |
e9b84181 JJ |
634 | } |
635 | ||
636 | /* Return value handling. The rules for SYSV are as follows: | |
63e5e3e0 AG |
637 | - 32-bit (or less) integer values are returned in gpr3; |
638 | - Structures of size <= 4 bytes also returned in gpr3; | |
639 | - 64-bit integer values and structures between 5 and 8 bytes are returned | |
16070e45 | 640 | in gpr3 and gpr4; |
63e5e3e0 | 641 | - Single/double FP values are returned in fpr1; |
75b8b1be AM |
642 | - Larger structures are allocated space and a pointer is passed as |
643 | the first argument. | |
644 | - long doubles (if not equivalent to double) are returned in | |
645 | fpr1,fpr2 for Linux and as for large structs for SysV. | |
e9b84181 JJ |
646 | For LINUX64: |
647 | - integer values in gpr3; | |
bf310028 | 648 | - Structures/Unions by reference; |
16287148 AT |
649 | - Single/double FP values in fpr1, long double in fpr1,fpr2. |
650 | - soft-float float/doubles are treated as UINT32/UINT64 respectivley. | |
651 | - soft-float long doubles are returned in gpr3-gpr6. */ | |
34fa7690 AG |
652 | /* First translate for softfloat/nonlinux */ |
653 | if (cif->abi == FFI_LINUX_SOFT_FLOAT) { | |
654 | if (type == FFI_TYPE_FLOAT) | |
655 | type = FFI_TYPE_UINT32; | |
656 | if (type == FFI_TYPE_DOUBLE) | |
657 | type = FFI_TYPE_UINT64; | |
658 | if (type == FFI_TYPE_LONGDOUBLE) | |
659 | type = FFI_TYPE_UINT128; | |
660 | } else if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64) { | |
661 | #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE | |
662 | if (type == FFI_TYPE_LONGDOUBLE) | |
663 | type = FFI_TYPE_STRUCT; | |
664 | #endif | |
665 | } | |
666 | ||
bf310028 | 667 | switch (type) |
63e5e3e0 | 668 | { |
34fa7690 | 669 | #ifndef __NO_FPRS__ |
8f093ea0 | 670 | #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE |
75b8b1be | 671 | case FFI_TYPE_LONGDOUBLE: |
75b8b1be AM |
672 | flags |= FLAG_RETURNS_128BITS; |
673 | /* Fall through. */ | |
8f093ea0 | 674 | #endif |
63e5e3e0 AG |
675 | case FFI_TYPE_DOUBLE: |
676 | flags |= FLAG_RETURNS_64BITS; | |
677 | /* Fall through. */ | |
678 | case FFI_TYPE_FLOAT: | |
34fa7690 | 679 | flags |= FLAG_RETURNS_FP; |
63e5e3e0 | 680 | break; |
34fa7690 | 681 | #endif |
63e5e3e0 | 682 | |
34fa7690 AG |
683 | case FFI_TYPE_UINT128: |
684 | flags |= FLAG_RETURNS_128BITS; | |
685 | /* Fall through. */ | |
63e5e3e0 AG |
686 | case FFI_TYPE_UINT64: |
687 | case FFI_TYPE_SINT64: | |
688 | flags |= FLAG_RETURNS_64BITS; | |
689 | break; | |
690 | ||
691 | case FFI_TYPE_STRUCT: | |
34fa7690 AG |
692 | /* |
693 | * The final SYSV ABI says that structures smaller or equal 8 bytes | |
694 | * are returned in r3/r4. The FFI_GCC_SYSV ABI instead returns them | |
695 | * in memory. | |
696 | * | |
697 | * NOTE: The assembly code can safely assume that it just needs to | |
698 | * store both r3 and r4 into a 8-byte word-aligned buffer, as | |
699 | * we allocate a temporary buffer in ffi_call() if this flag is | |
700 | * set. | |
701 | */ | |
702 | if (cif->abi == FFI_SYSV && size <= 8) | |
703 | flags |= FLAG_RETURNS_SMST; | |
63e5e3e0 AG |
704 | intarg_count++; |
705 | flags |= FLAG_RETVAL_REFERENCE; | |
706 | /* Fall through. */ | |
707 | case FFI_TYPE_VOID: | |
708 | flags |= FLAG_RETURNS_NOTHING; | |
709 | break; | |
710 | ||
711 | default: | |
712 | /* Returns 32-bit integer, or similar. Nothing to do here. */ | |
713 | break; | |
714 | } | |
715 | ||
e9b84181 JJ |
716 | if (cif->abi != FFI_LINUX64) |
717 | /* The first NUM_GPR_ARG_REGISTERS words of integer arguments, and the | |
718 | first NUM_FPR_ARG_REGISTERS fp arguments, go in registers; the rest | |
719 | goes on the stack. Structures and long doubles (if not equivalent | |
720 | to double) are passed as a pointer to a copy of the structure. | |
721 | Stuff on the stack needs to keep proper alignment. */ | |
722 | for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) | |
723 | { | |
34fa7690 AG |
724 | unsigned short typenum = (*ptr)->type; |
725 | ||
726 | /* We may need to handle some values depending on ABI */ | |
727 | if (cif->abi == FFI_LINUX_SOFT_FLOAT) { | |
728 | if (typenum == FFI_TYPE_FLOAT) | |
729 | typenum = FFI_TYPE_UINT32; | |
730 | if (typenum == FFI_TYPE_DOUBLE) | |
731 | typenum = FFI_TYPE_UINT64; | |
732 | if (typenum == FFI_TYPE_LONGDOUBLE) | |
733 | typenum = FFI_TYPE_UINT128; | |
734 | } else if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64) { | |
735 | #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE | |
736 | if (typenum == FFI_TYPE_LONGDOUBLE) | |
737 | typenum = FFI_TYPE_STRUCT; | |
738 | #endif | |
739 | } | |
740 | ||
741 | switch (typenum) { | |
742 | #ifndef __NO_FPRS__ | |
e9b84181 JJ |
743 | case FFI_TYPE_FLOAT: |
744 | fparg_count++; | |
745 | /* floating singles are not 8-aligned on stack */ | |
746 | break; | |
7b5102af | 747 | |
75b8b1be AM |
748 | #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE |
749 | case FFI_TYPE_LONGDOUBLE: | |
34fa7690 | 750 | fparg_count++; |
75b8b1be AM |
751 | /* Fall thru */ |
752 | #endif | |
e9b84181 JJ |
753 | case FFI_TYPE_DOUBLE: |
754 | fparg_count++; | |
755 | /* If this FP arg is going on the stack, it must be | |
756 | 8-byte-aligned. */ | |
757 | if (fparg_count > NUM_FPR_ARG_REGISTERS | |
2d9c5743 AM |
758 | && intarg_count >= NUM_GPR_ARG_REGISTERS |
759 | && intarg_count % 2 != 0) | |
e9b84181 JJ |
760 | intarg_count++; |
761 | break; | |
34fa7690 AG |
762 | #endif |
763 | case FFI_TYPE_UINT128: | |
764 | /* | |
765 | * A long double in FFI_LINUX_SOFT_FLOAT can use only a set | |
766 | * of four consecutive gprs. If we do not have enough, we | |
767 | * have to adjust the intarg_count value. | |
768 | */ | |
769 | if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3 | |
770 | && intarg_count < NUM_GPR_ARG_REGISTERS) | |
771 | intarg_count = NUM_GPR_ARG_REGISTERS; | |
772 | intarg_count += 4; | |
773 | break; | |
63e5e3e0 | 774 | |
e9b84181 JJ |
775 | case FFI_TYPE_UINT64: |
776 | case FFI_TYPE_SINT64: | |
777 | /* 'long long' arguments are passed as two words, but | |
778 | either both words must fit in registers or both go | |
779 | on the stack. If they go on the stack, they must | |
97067642 | 780 | be 8-byte-aligned. |
962eea0a AH |
781 | |
782 | Also, only certain register pairs can be used for | |
783 | passing long long int -- specifically (r3,r4), (r5,r6), | |
784 | (r7,r8), (r9,r10). | |
785 | */ | |
e9b84181 | 786 | if (intarg_count == NUM_GPR_ARG_REGISTERS-1 |
cd4241aa | 787 | || intarg_count % 2 != 0) |
e9b84181 JJ |
788 | intarg_count++; |
789 | intarg_count += 2; | |
790 | break; | |
791 | ||
792 | case FFI_TYPE_STRUCT: | |
e9b84181 JJ |
793 | /* We must allocate space for a copy of these to enforce |
794 | pass-by-value. Pad the space up to a multiple of 16 | |
795 | bytes (the maximum alignment required for anything under | |
796 | the SYSV ABI). */ | |
797 | struct_copy_size += ((*ptr)->size + 15) & ~0xF; | |
798 | /* Fall through (allocate space for the pointer). */ | |
799 | ||
34fa7690 AG |
800 | case FFI_TYPE_POINTER: |
801 | case FFI_TYPE_INT: | |
802 | case FFI_TYPE_UINT32: | |
803 | case FFI_TYPE_SINT32: | |
804 | case FFI_TYPE_UINT16: | |
805 | case FFI_TYPE_SINT16: | |
806 | case FFI_TYPE_UINT8: | |
807 | case FFI_TYPE_SINT8: | |
e9b84181 JJ |
808 | /* Everything else is passed as a 4-byte word in a GPR, either |
809 | the object itself or a pointer to it. */ | |
63e5e3e0 | 810 | intarg_count++; |
e9b84181 | 811 | break; |
34fa7690 AG |
812 | default: |
813 | FFI_ASSERT (0); | |
e9b84181 JJ |
814 | } |
815 | } | |
816 | else | |
817 | for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) | |
818 | { | |
819 | switch ((*ptr)->type) | |
820 | { | |
bf310028 AM |
821 | #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE |
822 | case FFI_TYPE_LONGDOUBLE: | |
16287148 AT |
823 | if (cif->abi == FFI_LINUX_SOFT_FLOAT) |
824 | intarg_count += 4; | |
825 | else | |
826 | { | |
827 | fparg_count += 2; | |
828 | intarg_count += 2; | |
829 | } | |
bf310028 AM |
830 | break; |
831 | #endif | |
e9b84181 JJ |
832 | case FFI_TYPE_FLOAT: |
833 | case FFI_TYPE_DOUBLE: | |
834 | fparg_count++; | |
835 | intarg_count++; | |
836 | break; | |
63e5e3e0 | 837 | |
e9b84181 | 838 | case FFI_TYPE_STRUCT: |
5af1c806 | 839 | intarg_count += ((*ptr)->size + 7) / 8; |
e9b84181 | 840 | break; |
63e5e3e0 | 841 | |
34fa7690 AG |
842 | case FFI_TYPE_POINTER: |
843 | case FFI_TYPE_UINT64: | |
844 | case FFI_TYPE_SINT64: | |
845 | case FFI_TYPE_INT: | |
846 | case FFI_TYPE_UINT32: | |
847 | case FFI_TYPE_SINT32: | |
848 | case FFI_TYPE_UINT16: | |
849 | case FFI_TYPE_SINT16: | |
850 | case FFI_TYPE_UINT8: | |
851 | case FFI_TYPE_SINT8: | |
e9b84181 JJ |
852 | /* Everything else is passed as a 8-byte word in a GPR, either |
853 | the object itself or a pointer to it. */ | |
854 | intarg_count++; | |
855 | break; | |
34fa7690 AG |
856 | default: |
857 | FFI_ASSERT (0); | |
e9b84181 JJ |
858 | } |
859 | } | |
63e5e3e0 | 860 | |
34fa7690 | 861 | #ifndef __NO_FPRS__ |
63e5e3e0 AG |
862 | if (fparg_count != 0) |
863 | flags |= FLAG_FP_ARGUMENTS; | |
34fa7690 | 864 | #endif |
63e5e3e0 AG |
865 | if (intarg_count > 4) |
866 | flags |= FLAG_4_GPR_ARGUMENTS; | |
867 | if (struct_copy_size != 0) | |
868 | flags |= FLAG_ARG_NEEDS_COPY; | |
63e5e3e0 | 869 | |
e9b84181 JJ |
870 | if (cif->abi != FFI_LINUX64) |
871 | { | |
34fa7690 | 872 | #ifndef __NO_FPRS__ |
e9b84181 JJ |
873 | /* Space for the FPR registers, if needed. */ |
874 | if (fparg_count != 0) | |
cd4241aa | 875 | bytes += NUM_FPR_ARG_REGISTERS * sizeof (double); |
34fa7690 | 876 | #endif |
e9b84181 JJ |
877 | |
878 | /* Stack space. */ | |
879 | if (intarg_count > NUM_GPR_ARG_REGISTERS) | |
cd4241aa | 880 | bytes += (intarg_count - NUM_GPR_ARG_REGISTERS) * sizeof (int); |
34fa7690 | 881 | #ifndef __NO_FPRS__ |
e9b84181 | 882 | if (fparg_count > NUM_FPR_ARG_REGISTERS) |
cd4241aa | 883 | bytes += (fparg_count - NUM_FPR_ARG_REGISTERS) * sizeof (double); |
34fa7690 | 884 | #endif |
e9b84181 JJ |
885 | } |
886 | else | |
887 | { | |
34fa7690 | 888 | #ifndef __NO_FPRS__ |
e9b84181 JJ |
889 | /* Space for the FPR registers, if needed. */ |
890 | if (fparg_count != 0) | |
cd4241aa | 891 | bytes += NUM_FPR_ARG_REGISTERS64 * sizeof (double); |
34fa7690 | 892 | #endif |
e9b84181 JJ |
893 | |
894 | /* Stack space. */ | |
895 | if (intarg_count > NUM_GPR_ARG_REGISTERS64) | |
cd4241aa | 896 | bytes += (intarg_count - NUM_GPR_ARG_REGISTERS64) * sizeof (long); |
e9b84181 | 897 | } |
63e5e3e0 AG |
898 | |
899 | /* The stack space allocated needs to be a multiple of 16 bytes. */ | |
900 | bytes = (bytes + 15) & ~0xF; | |
901 | ||
902 | /* Add in the space for the copied structures. */ | |
903 | bytes += struct_copy_size; | |
904 | ||
905 | cif->flags = flags; | |
906 | cif->bytes = bytes; | |
907 | ||
908 | return FFI_OK; | |
909 | } | |
910 | ||
ac6ed182 | 911 | extern void ffi_call_SYSV(extended_cif *, unsigned, unsigned, unsigned *, |
7446546a | 912 | void (*fn)(void)); |
ac6ed182 AT |
913 | extern void FFI_HIDDEN ffi_call_LINUX64(extended_cif *, unsigned long, |
914 | unsigned long, unsigned long *, | |
7446546a | 915 | void (*fn)(void)); |
63e5e3e0 | 916 | |
cd4241aa | 917 | void |
7446546a | 918 | ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) |
63e5e3e0 | 919 | { |
34fa7690 AG |
920 | /* |
921 | * The final SYSV ABI says that structures smaller or equal 8 bytes | |
922 | * are returned in r3/r4. The FFI_GCC_SYSV ABI instead returns them | |
923 | * in memory. | |
924 | * | |
925 | * Just to keep things simple for the assembly code, we will always | |
926 | * bounce-buffer struct return values less than or equal to 8 bytes. | |
927 | * This allows the ASM to handle SYSV small structures by directly | |
928 | * writing r3 and r4 to memory without worrying about struct size. | |
929 | */ | |
930 | unsigned int smst_buffer[2]; | |
63e5e3e0 | 931 | extended_cif ecif; |
efe2a4b7 | 932 | unsigned int rsize = 0; |
63e5e3e0 AG |
933 | |
934 | ecif.cif = cif; | |
935 | ecif.avalue = avalue; | |
16070e45 | 936 | |
34fa7690 AG |
937 | /* Ensure that we have a valid struct return value */ |
938 | ecif.rvalue = rvalue; | |
939 | if (cif->rtype->type == FFI_TYPE_STRUCT) { | |
940 | rsize = cif->rtype->size; | |
941 | if (rsize <= 8) | |
942 | ecif.rvalue = smst_buffer; | |
943 | else if (!rvalue) | |
944 | ecif.rvalue = alloca(rsize); | |
945 | } | |
16070e45 AT |
946 | |
947 | switch (cif->abi) | |
63e5e3e0 | 948 | { |
e9b84181 | 949 | #ifndef POWERPC64 |
34fa7690 | 950 | # ifndef __NO_FPRS__ |
63e5e3e0 AG |
951 | case FFI_SYSV: |
952 | case FFI_GCC_SYSV: | |
75b8b1be | 953 | case FFI_LINUX: |
34fa7690 | 954 | # endif |
16287148 | 955 | case FFI_LINUX_SOFT_FLOAT: |
cd4241aa | 956 | ffi_call_SYSV (&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn); |
63e5e3e0 | 957 | break; |
e9b84181 JJ |
958 | #else |
959 | case FFI_LINUX64: | |
cd4241aa | 960 | ffi_call_LINUX64 (&ecif, -(long) cif->bytes, cif->flags, ecif.rvalue, fn); |
e9b84181 JJ |
961 | break; |
962 | #endif | |
63e5e3e0 | 963 | default: |
cd4241aa | 964 | FFI_ASSERT (0); |
63e5e3e0 AG |
965 | break; |
966 | } | |
34fa7690 AG |
967 | |
968 | /* Check for a bounce-buffered return value */ | |
969 | if (rvalue && ecif.rvalue == smst_buffer) | |
970 | memcpy(rvalue, smst_buffer, rsize); | |
63e5e3e0 | 971 | } |
cc4c8975 KH |
972 | |
973 | ||
e9b84181 | 974 | #ifndef POWERPC64 |
e9b84181 JJ |
975 | #define MIN_CACHE_LINE_SIZE 8 |
976 | ||
cd4241aa | 977 | static void |
18fa3240 | 978 | flush_icache (char *wraddr, char *xaddr, int size) |
e9b84181 JJ |
979 | { |
980 | int i; | |
cd4241aa | 981 | for (i = 0; i < size; i += MIN_CACHE_LINE_SIZE) |
8b9cf39e AO |
982 | __asm__ volatile ("icbi 0,%0;" "dcbf 0,%1;" |
983 | : : "r" (xaddr + i), "r" (wraddr + i) : "memory"); | |
18fa3240 AO |
984 | __asm__ volatile ("icbi 0,%0;" "dcbf 0,%1;" "sync;" "isync;" |
985 | : : "r"(xaddr + size - 1), "r"(wraddr + size - 1) | |
986 | : "memory"); | |
e9b84181 JJ |
987 | } |
988 | #endif | |
989 | ||
cc4c8975 | 990 | ffi_status |
18fa3240 AO |
991 | ffi_prep_closure_loc (ffi_closure *closure, |
992 | ffi_cif *cif, | |
993 | void (*fun) (ffi_cif *, void *, void **, void *), | |
994 | void *user_data, | |
995 | void *codeloc) | |
cc4c8975 | 996 | { |
e9b84181 JJ |
997 | #ifdef POWERPC64 |
998 | void **tramp = (void **) &closure->tramp[0]; | |
999 | ||
34fa7690 AG |
1000 | if (cif->abi != FFI_LINUX64) |
1001 | return FFI_BAD_ABI; | |
e9b84181 JJ |
1002 | /* Copy function address and TOC from ffi_closure_LINUX64. */ |
1003 | memcpy (tramp, (char *) ffi_closure_LINUX64, 16); | |
8b9cf39e | 1004 | tramp[2] = codeloc; |
e9b84181 | 1005 | #else |
cc4c8975 KH |
1006 | unsigned int *tramp; |
1007 | ||
34fa7690 AG |
1008 | if (! (cif->abi == FFI_GCC_SYSV |
1009 | || cif->abi == FFI_SYSV | |
1010 | || cif->abi == FFI_LINUX | |
1011 | || cif->abi == FFI_LINUX_SOFT_FLOAT)) | |
1012 | return FFI_BAD_ABI; | |
cc4c8975 KH |
1013 | |
1014 | tramp = (unsigned int *) &closure->tramp[0]; | |
1015 | tramp[0] = 0x7c0802a6; /* mflr r0 */ | |
1016 | tramp[1] = 0x4800000d; /* bl 10 <trampoline_initial+0x10> */ | |
1017 | tramp[4] = 0x7d6802a6; /* mflr r11 */ | |
1018 | tramp[5] = 0x7c0803a6; /* mtlr r0 */ | |
1019 | tramp[6] = 0x800b0000; /* lwz r0,0(r11) */ | |
1020 | tramp[7] = 0x816b0004; /* lwz r11,4(r11) */ | |
1021 | tramp[8] = 0x7c0903a6; /* mtctr r0 */ | |
1022 | tramp[9] = 0x4e800420; /* bctr */ | |
cd4241aa | 1023 | *(void **) &tramp[2] = (void *) ffi_closure_SYSV; /* function */ |
8b9cf39e | 1024 | *(void **) &tramp[3] = codeloc; /* context */ |
cc4c8975 | 1025 | |
e9b84181 | 1026 | /* Flush the icache. */ |
8b9cf39e | 1027 | flush_icache ((char *)tramp, (char *)codeloc, FFI_TRAMPOLINE_SIZE); |
e9b84181 JJ |
1028 | #endif |
1029 | ||
cc4c8975 KH |
1030 | closure->cif = cif; |
1031 | closure->fun = fun; | |
1032 | closure->user_data = user_data; | |
1033 | ||
cc4c8975 KH |
1034 | return FFI_OK; |
1035 | } | |
1036 | ||
e9b84181 | 1037 | typedef union |
cc4c8975 | 1038 | { |
e9b84181 JJ |
1039 | float f; |
1040 | double d; | |
1041 | } ffi_dblfl; | |
cc4c8975 | 1042 | |
cd4241aa AM |
1043 | int ffi_closure_helper_SYSV (ffi_closure *, void *, unsigned long *, |
1044 | ffi_dblfl *, unsigned long *); | |
cc4c8975 | 1045 | |
16070e45 | 1046 | /* Basically the trampoline invokes ffi_closure_SYSV, and on |
cc4c8975 KH |
1047 | * entry, r11 holds the address of the closure. |
1048 | * After storing the registers that could possibly contain | |
1049 | * parameters to be passed into the stack frame and setting | |
16070e45 | 1050 | * up space for a return value, ffi_closure_SYSV invokes the |
cc4c8975 KH |
1051 | * following helper function to do most of the work |
1052 | */ | |
1053 | ||
1054 | int | |
cd4241aa AM |
1055 | ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue, |
1056 | unsigned long *pgr, ffi_dblfl *pfr, | |
1057 | unsigned long *pst) | |
cc4c8975 KH |
1058 | { |
1059 | /* rvalue is the pointer to space for return value in closure assembly */ | |
1060 | /* pgr is the pointer to where r3-r10 are stored in ffi_closure_SYSV */ | |
1061 | /* pfr is the pointer to where f1-f8 are stored in ffi_closure_SYSV */ | |
1062 | /* pst is the pointer to outgoing parameter stack in original caller */ | |
1063 | ||
1064 | void ** avalue; | |
1065 | ffi_type ** arg_types; | |
1066 | long i, avn; | |
34fa7690 AG |
1067 | #ifndef __NO_FPRS__ |
1068 | long nf = 0; /* number of floating registers already used */ | |
1069 | #endif | |
1070 | long ng = 0; /* number of general registers already used */ | |
1071 | ||
1072 | ffi_cif *cif = closure->cif; | |
1073 | unsigned size = cif->rtype->size; | |
1074 | unsigned short rtypenum = cif->rtype->type; | |
cc4c8975 | 1075 | |
cd4241aa | 1076 | avalue = alloca (cif->nargs * sizeof (void *)); |
cc4c8975 | 1077 | |
34fa7690 AG |
1078 | /* First translate for softfloat/nonlinux */ |
1079 | if (cif->abi == FFI_LINUX_SOFT_FLOAT) { | |
1080 | if (rtypenum == FFI_TYPE_FLOAT) | |
1081 | rtypenum = FFI_TYPE_UINT32; | |
1082 | if (rtypenum == FFI_TYPE_DOUBLE) | |
1083 | rtypenum = FFI_TYPE_UINT64; | |
1084 | if (rtypenum == FFI_TYPE_LONGDOUBLE) | |
1085 | rtypenum = FFI_TYPE_UINT128; | |
1086 | } else if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64) { | |
1087 | #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE | |
1088 | if (rtypenum == FFI_TYPE_LONGDOUBLE) | |
1089 | rtypenum = FFI_TYPE_STRUCT; | |
1090 | #endif | |
1091 | } | |
1092 | ||
cc4c8975 KH |
1093 | |
1094 | /* Copy the caller's structure return value address so that the closure | |
97067642 AT |
1095 | returns the data directly to the caller. |
1096 | For FFI_SYSV the result is passed in r3/r4 if the struct size is less | |
1097 | or equal 8 bytes. */ | |
34fa7690 | 1098 | if (rtypenum == FFI_TYPE_STRUCT && ((cif->abi != FFI_SYSV) || (size > 8))) { |
75b8b1be AM |
1099 | rvalue = (void *) *pgr; |
1100 | ng++; | |
1101 | pgr++; | |
cc4c8975 KH |
1102 | } |
1103 | ||
1104 | i = 0; | |
1105 | avn = cif->nargs; | |
1106 | arg_types = cif->arg_types; | |
16070e45 | 1107 | |
cc4c8975 | 1108 | /* Grab the addresses of the arguments from the stack frame. */ |
34fa7690 AG |
1109 | while (i < avn) { |
1110 | unsigned short typenum = arg_types[i]->type; | |
1111 | ||
1112 | /* We may need to handle some values depending on ABI */ | |
1113 | if (cif->abi == FFI_LINUX_SOFT_FLOAT) { | |
1114 | if (typenum == FFI_TYPE_FLOAT) | |
1115 | typenum = FFI_TYPE_UINT32; | |
1116 | if (typenum == FFI_TYPE_DOUBLE) | |
1117 | typenum = FFI_TYPE_UINT64; | |
1118 | if (typenum == FFI_TYPE_LONGDOUBLE) | |
1119 | typenum = FFI_TYPE_UINT128; | |
1120 | } else if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64) { | |
1121 | #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE | |
1122 | if (typenum == FFI_TYPE_LONGDOUBLE) | |
1123 | typenum = FFI_TYPE_STRUCT; | |
1124 | #endif | |
1125 | } | |
1126 | ||
1127 | switch (typenum) { | |
1128 | #ifndef __NO_FPRS__ | |
1129 | case FFI_TYPE_FLOAT: | |
1130 | /* unfortunately float values are stored as doubles | |
1131 | * in the ffi_closure_SYSV code (since we don't check | |
1132 | * the type in that routine). | |
1133 | */ | |
1134 | ||
1135 | /* there are 8 64bit floating point registers */ | |
1136 | ||
1137 | if (nf < 8) | |
1138 | { | |
efe2a4b7 | 1139 | double temp = pfr->d; |
34fa7690 AG |
1140 | pfr->f = (float) temp; |
1141 | avalue[i] = pfr; | |
1142 | nf++; | |
1143 | pfr++; | |
1144 | } | |
1145 | else | |
1146 | { | |
1147 | /* FIXME? here we are really changing the values | |
1148 | * stored in the original calling routines outgoing | |
1149 | * parameter stack. This is probably a really | |
1150 | * naughty thing to do but... | |
1151 | */ | |
1152 | avalue[i] = pst; | |
1153 | pst += 1; | |
1154 | } | |
1155 | break; | |
1156 | ||
1157 | case FFI_TYPE_DOUBLE: | |
1158 | /* On the outgoing stack all values are aligned to 8 */ | |
1159 | /* there are 8 64bit floating point registers */ | |
1160 | ||
1161 | if (nf < 8) | |
1162 | { | |
1163 | avalue[i] = pfr; | |
1164 | nf++; | |
1165 | pfr++; | |
1166 | } | |
1167 | else | |
1168 | { | |
1169 | if (((long) pst) & 4) | |
1170 | pst++; | |
1171 | avalue[i] = pst; | |
1172 | pst += 2; | |
1173 | } | |
1174 | break; | |
1175 | ||
1176 | #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE | |
1177 | case FFI_TYPE_LONGDOUBLE: | |
1178 | if (nf < 7) | |
1179 | { | |
1180 | avalue[i] = pfr; | |
1181 | pfr += 2; | |
1182 | nf += 2; | |
1183 | } | |
1184 | else | |
1185 | { | |
1186 | if (((long) pst) & 4) | |
1187 | pst++; | |
1188 | avalue[i] = pst; | |
1189 | pst += 4; | |
1190 | nf = 8; | |
1191 | } | |
1192 | break; | |
1193 | #endif | |
1194 | #endif /* have FPRS */ | |
1195 | ||
1196 | case FFI_TYPE_UINT128: | |
1197 | /* | |
1198 | * Test if for the whole long double, 4 gprs are available. | |
1199 | * otherwise the stuff ends up on the stack. | |
1200 | */ | |
1201 | if (ng < 5) { | |
1202 | avalue[i] = pgr; | |
1203 | pgr += 4; | |
1204 | ng += 4; | |
1205 | } else { | |
1206 | avalue[i] = pst; | |
1207 | pst += 4; | |
1208 | ng = 8+4; | |
1209 | } | |
1210 | break; | |
1211 | ||
cc4c8975 KH |
1212 | case FFI_TYPE_SINT8: |
1213 | case FFI_TYPE_UINT8: | |
40b45a6d | 1214 | #ifndef __LITTLE_ENDIAN__ |
16070e45 | 1215 | /* there are 8 gpr registers used to pass values */ |
cd4241aa AM |
1216 | if (ng < 8) |
1217 | { | |
1218 | avalue[i] = (char *) pgr + 3; | |
1219 | ng++; | |
1220 | pgr++; | |
1221 | } | |
1222 | else | |
1223 | { | |
1224 | avalue[i] = (char *) pst + 3; | |
1225 | pst++; | |
1226 | } | |
cc4c8975 | 1227 | break; |
40b45a6d | 1228 | #endif |
cc4c8975 KH |
1229 | case FFI_TYPE_SINT16: |
1230 | case FFI_TYPE_UINT16: | |
40b45a6d | 1231 | #ifndef __LITTLE_ENDIAN__ |
16070e45 | 1232 | /* there are 8 gpr registers used to pass values */ |
cd4241aa AM |
1233 | if (ng < 8) |
1234 | { | |
1235 | avalue[i] = (char *) pgr + 2; | |
1236 | ng++; | |
1237 | pgr++; | |
1238 | } | |
1239 | else | |
1240 | { | |
1241 | avalue[i] = (char *) pst + 2; | |
1242 | pst++; | |
1243 | } | |
cc4c8975 | 1244 | break; |
40b45a6d | 1245 | #endif |
cc4c8975 KH |
1246 | case FFI_TYPE_SINT32: |
1247 | case FFI_TYPE_UINT32: | |
1248 | case FFI_TYPE_POINTER: | |
086a4bd7 | 1249 | /* there are 8 gpr registers used to pass values */ |
cd4241aa AM |
1250 | if (ng < 8) |
1251 | { | |
1252 | avalue[i] = pgr; | |
1253 | ng++; | |
1254 | pgr++; | |
1255 | } | |
1256 | else | |
1257 | { | |
1258 | avalue[i] = pst; | |
1259 | pst++; | |
1260 | } | |
cc4c8975 | 1261 | break; |
bf310028 | 1262 | |
086a4bd7 | 1263 | case FFI_TYPE_STRUCT: |
16070e45 | 1264 | /* Structs are passed by reference. The address will appear in a |
086a4bd7 | 1265 | gpr if it is one of the first 8 arguments. */ |
cd4241aa AM |
1266 | if (ng < 8) |
1267 | { | |
1268 | avalue[i] = (void *) *pgr; | |
1269 | ng++; | |
1270 | pgr++; | |
1271 | } | |
1272 | else | |
1273 | { | |
1274 | avalue[i] = (void *) *pst; | |
1275 | pst++; | |
1276 | } | |
086a4bd7 | 1277 | break; |
cc4c8975 KH |
1278 | |
1279 | case FFI_TYPE_SINT64: | |
1280 | case FFI_TYPE_UINT64: | |
1281 | /* passing long long ints are complex, they must | |
16070e45 AT |
1282 | * be passed in suitable register pairs such as |
1283 | * (r3,r4) or (r5,r6) or (r6,r7), or (r7,r8) or (r9,r10) | |
1284 | * and if the entire pair aren't available then the outgoing | |
1285 | * parameter stack is used for both but an alignment of 8 | |
1286 | * must will be kept. So we must either look in pgr | |
1287 | * or pst to find the correct address for this type | |
1288 | * of parameter. | |
1289 | */ | |
cd4241aa AM |
1290 | if (ng < 7) |
1291 | { | |
1292 | if (ng & 0x01) | |
1293 | { | |
1294 | /* skip r4, r6, r8 as starting points */ | |
1295 | ng++; | |
1296 | pgr++; | |
1297 | } | |
1298 | avalue[i] = pgr; | |
1299 | ng += 2; | |
1300 | pgr += 2; | |
1301 | } | |
1302 | else | |
1303 | { | |
1304 | if (((long) pst) & 4) | |
1305 | pst++; | |
1306 | avalue[i] = pst; | |
1307 | pst += 2; | |
302486f4 | 1308 | ng = 8; |
16070e45 | 1309 | } |
16070e45 | 1310 | break; |
cc4c8975 | 1311 | |
cc4c8975 | 1312 | default: |
34fa7690 | 1313 | FFI_ASSERT (0); |
cc4c8975 KH |
1314 | } |
1315 | ||
1316 | i++; | |
1317 | } | |
1318 | ||
1319 | ||
1320 | (closure->fun) (cif, rvalue, avalue, closure->user_data); | |
1321 | ||
97067642 AT |
1322 | /* Tell ffi_closure_SYSV how to perform return type promotions. |
1323 | Because the FFI_SYSV ABI returns the structures <= 8 bytes in r3/r4 | |
d7f68a67 AT |
1324 | we have to tell ffi_closure_SYSV how to treat them. We combine the base |
1325 | type FFI_SYSV_TYPE_SMALL_STRUCT - 1 with the size of the struct. | |
1326 | So a one byte struct gets the return type 16. Return type 1 to 15 are | |
1327 | already used and we never have a struct with size zero. That is the reason | |
1328 | for the subtraction of 1. See the comment in ffitarget.h about ordering. | |
1329 | */ | |
34fa7690 | 1330 | if (cif->abi == FFI_SYSV && rtypenum == FFI_TYPE_STRUCT && size <= 8) |
d7f68a67 | 1331 | return (FFI_SYSV_TYPE_SMALL_STRUCT - 1) + size; |
34fa7690 | 1332 | return rtypenum; |
cc4c8975 KH |
1333 | } |
1334 | ||
cd4241aa AM |
1335 | int FFI_HIDDEN ffi_closure_helper_LINUX64 (ffi_closure *, void *, |
1336 | unsigned long *, ffi_dblfl *); | |
cc4c8975 | 1337 | |
8a42356f | 1338 | int FFI_HIDDEN |
16070e45 | 1339 | ffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue, |
bf310028 | 1340 | unsigned long *pst, ffi_dblfl *pfr) |
e9b84181 JJ |
1341 | { |
1342 | /* rvalue is the pointer to space for return value in closure assembly */ | |
1343 | /* pst is the pointer to parameter save area | |
1344 | (r3-r10 are stored into its first 8 slots by ffi_closure_LINUX64) */ | |
1345 | /* pfr is the pointer to where f1-f13 are stored in ffi_closure_LINUX64 */ | |
1346 | ||
bf310028 AM |
1347 | void **avalue; |
1348 | ffi_type **arg_types; | |
1349 | long i, avn; | |
16070e45 | 1350 | ffi_cif *cif; |
bf310028 | 1351 | ffi_dblfl *end_pfr = pfr + NUM_FPR_ARG_REGISTERS64; |
cc4c8975 | 1352 | |
e9b84181 | 1353 | cif = closure->cif; |
bf310028 | 1354 | avalue = alloca (cif->nargs * sizeof (void *)); |
cc4c8975 | 1355 | |
e9b84181 JJ |
1356 | /* Copy the caller's structure return value address so that the closure |
1357 | returns the data directly to the caller. */ | |
1358 | if (cif->rtype->type == FFI_TYPE_STRUCT) | |
1359 | { | |
1360 | rvalue = (void *) *pst; | |
e9b84181 JJ |
1361 | pst++; |
1362 | } | |
1363 | ||
1364 | i = 0; | |
1365 | avn = cif->nargs; | |
1366 | arg_types = cif->arg_types; | |
16070e45 | 1367 | |
e9b84181 JJ |
1368 | /* Grab the addresses of the arguments from the stack frame. */ |
1369 | while (i < avn) | |
1370 | { | |
1371 | switch (arg_types[i]->type) | |
1372 | { | |
1373 | case FFI_TYPE_SINT8: | |
1374 | case FFI_TYPE_UINT8: | |
40b45a6d | 1375 | #ifndef __LITTLE_ENDIAN__ |
e9b84181 | 1376 | avalue[i] = (char *) pst + 7; |
e9b84181 JJ |
1377 | pst++; |
1378 | break; | |
40b45a6d | 1379 | #endif |
e9b84181 JJ |
1380 | case FFI_TYPE_SINT16: |
1381 | case FFI_TYPE_UINT16: | |
40b45a6d | 1382 | #ifndef __LITTLE_ENDIAN__ |
e9b84181 | 1383 | avalue[i] = (char *) pst + 6; |
e9b84181 JJ |
1384 | pst++; |
1385 | break; | |
40b45a6d | 1386 | #endif |
e9b84181 JJ |
1387 | case FFI_TYPE_SINT32: |
1388 | case FFI_TYPE_UINT32: | |
40b45a6d | 1389 | #ifndef __LITTLE_ENDIAN__ |
e9b84181 | 1390 | avalue[i] = (char *) pst + 4; |
e9b84181 JJ |
1391 | pst++; |
1392 | break; | |
40b45a6d | 1393 | #endif |
e9b84181 JJ |
1394 | case FFI_TYPE_SINT64: |
1395 | case FFI_TYPE_UINT64: | |
1396 | case FFI_TYPE_POINTER: | |
1397 | avalue[i] = pst; | |
e9b84181 JJ |
1398 | pst++; |
1399 | break; | |
1400 | ||
1401 | case FFI_TYPE_STRUCT: | |
40b45a6d | 1402 | #ifndef __LITTLE_ENDIAN__ |
b00badcd AM |
1403 | /* Structures with size less than eight bytes are passed |
1404 | left-padded. */ | |
1405 | if (arg_types[i]->size < 8) | |
e9b84181 JJ |
1406 | avalue[i] = (char *) pst + 8 - arg_types[i]->size; |
1407 | else | |
40b45a6d | 1408 | #endif |
e9b84181 | 1409 | avalue[i] = pst; |
e9b84181 JJ |
1410 | pst += (arg_types[i]->size + 7) / 8; |
1411 | break; | |
1412 | ||
1413 | case FFI_TYPE_FLOAT: | |
1414 | /* unfortunately float values are stored as doubles | |
16070e45 AT |
1415 | * in the ffi_closure_LINUX64 code (since we don't check |
1416 | * the type in that routine). | |
1417 | */ | |
e9b84181 | 1418 | |
16070e45 | 1419 | /* there are 13 64bit floating point registers */ |
e9b84181 | 1420 | |
16070e45 | 1421 | if (pfr < end_pfr) |
bf310028 AM |
1422 | { |
1423 | double temp = pfr->d; | |
1424 | pfr->f = (float) temp; | |
1425 | avalue[i] = pfr; | |
1426 | pfr++; | |
1427 | } | |
1428 | else | |
1429 | avalue[i] = pst; | |
e9b84181 JJ |
1430 | pst++; |
1431 | break; | |
1432 | ||
1433 | case FFI_TYPE_DOUBLE: | |
1434 | /* On the outgoing stack all values are aligned to 8 */ | |
16070e45 | 1435 | /* there are 13 64bit floating point registers */ |
e9b84181 | 1436 | |
bf310028 AM |
1437 | if (pfr < end_pfr) |
1438 | { | |
1439 | avalue[i] = pfr; | |
1440 | pfr++; | |
1441 | } | |
1442 | else | |
1443 | avalue[i] = pst; | |
e9b84181 JJ |
1444 | pst++; |
1445 | break; | |
1446 | ||
bf310028 AM |
1447 | #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE |
1448 | case FFI_TYPE_LONGDOUBLE: | |
4243752c | 1449 | if (pfr + 1 < end_pfr) |
bf310028 AM |
1450 | { |
1451 | avalue[i] = pfr; | |
1452 | pfr += 2; | |
1453 | } | |
1454 | else | |
1455 | { | |
1456 | if (pfr < end_pfr) | |
1457 | { | |
1458 | /* Passed partly in f13 and partly on the stack. | |
1459 | Move it all to the stack. */ | |
1460 | *pst = *(unsigned long *) pfr; | |
1461 | pfr++; | |
1462 | } | |
1463 | avalue[i] = pst; | |
1464 | } | |
1465 | pst += 2; | |
1466 | break; | |
1467 | #endif | |
1468 | ||
e9b84181 | 1469 | default: |
cd4241aa | 1470 | FFI_ASSERT (0); |
e9b84181 JJ |
1471 | } |
1472 | ||
1473 | i++; | |
1474 | } | |
1475 | ||
1476 | ||
1477 | (closure->fun) (cif, rvalue, avalue, closure->user_data); | |
1478 | ||
1479 | /* Tell ffi_closure_LINUX64 how to perform return type promotions. */ | |
1480 | return cif->rtype->type; | |
e9b84181 | 1481 | } |