annotate libffi/src/powerpc/ffi_linux64.c @ 155:da32f4b04d38

fix __code name conflict
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 17:51:46 +0900
parents 84e7813d76e9
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 /* -----------------------------------------------------------------------
kono
parents:
diff changeset
2 ffi_linux64.c - Copyright (C) 2013 IBM
kono
parents:
diff changeset
3 Copyright (C) 2011 Anthony Green
kono
parents:
diff changeset
4 Copyright (C) 2011 Kyle Moffett
kono
parents:
diff changeset
5 Copyright (C) 2008 Red Hat, Inc
kono
parents:
diff changeset
6 Copyright (C) 2007, 2008 Free Software Foundation, Inc
kono
parents:
diff changeset
7 Copyright (c) 1998 Geoffrey Keating
kono
parents:
diff changeset
8
kono
parents:
diff changeset
9 PowerPC Foreign Function Interface
kono
parents:
diff changeset
10
kono
parents:
diff changeset
11 Permission is hereby granted, free of charge, to any person obtaining
kono
parents:
diff changeset
12 a copy of this software and associated documentation files (the
kono
parents:
diff changeset
13 ``Software''), to deal in the Software without restriction, including
kono
parents:
diff changeset
14 without limitation the rights to use, copy, modify, merge, publish,
kono
parents:
diff changeset
15 distribute, sublicense, and/or sell copies of the Software, and to
kono
parents:
diff changeset
16 permit persons to whom the Software is furnished to do so, subject to
kono
parents:
diff changeset
17 the following conditions:
kono
parents:
diff changeset
18
kono
parents:
diff changeset
19 The above copyright notice and this permission notice shall be included
kono
parents:
diff changeset
20 in all copies or substantial portions of the Software.
kono
parents:
diff changeset
21
kono
parents:
diff changeset
22 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
kono
parents:
diff changeset
23 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
kono
parents:
diff changeset
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
kono
parents:
diff changeset
25 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
kono
parents:
diff changeset
26 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
kono
parents:
diff changeset
27 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
kono
parents:
diff changeset
28 OTHER DEALINGS IN THE SOFTWARE.
kono
parents:
diff changeset
29 ----------------------------------------------------------------------- */
kono
parents:
diff changeset
30
kono
parents:
diff changeset
31 #include "ffi.h"
kono
parents:
diff changeset
32
kono
parents:
diff changeset
33 #ifdef POWERPC64
kono
parents:
diff changeset
34 #include "ffi_common.h"
kono
parents:
diff changeset
35 #include "ffi_powerpc.h"
kono
parents:
diff changeset
36
kono
parents:
diff changeset
37
kono
parents:
diff changeset
38 /* About the LINUX64 ABI. */
kono
parents:
diff changeset
39 enum {
kono
parents:
diff changeset
40 NUM_GPR_ARG_REGISTERS64 = 8,
kono
parents:
diff changeset
41 NUM_FPR_ARG_REGISTERS64 = 13
kono
parents:
diff changeset
42 };
kono
parents:
diff changeset
43 enum { ASM_NEEDS_REGISTERS64 = 4 };
kono
parents:
diff changeset
44
kono
parents:
diff changeset
45
kono
parents:
diff changeset
46 #if HAVE_LONG_DOUBLE_VARIANT && FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
kono
parents:
diff changeset
47 /* Adjust size of ffi_type_longdouble. */
kono
parents:
diff changeset
48 void FFI_HIDDEN
kono
parents:
diff changeset
49 ffi_prep_types_linux64 (ffi_abi abi)
kono
parents:
diff changeset
50 {
kono
parents:
diff changeset
51 if ((abi & (FFI_LINUX | FFI_LINUX_LONG_DOUBLE_128)) == FFI_LINUX)
kono
parents:
diff changeset
52 {
kono
parents:
diff changeset
53 ffi_type_longdouble.size = 8;
kono
parents:
diff changeset
54 ffi_type_longdouble.alignment = 8;
kono
parents:
diff changeset
55 }
kono
parents:
diff changeset
56 else
kono
parents:
diff changeset
57 {
kono
parents:
diff changeset
58 ffi_type_longdouble.size = 16;
kono
parents:
diff changeset
59 ffi_type_longdouble.alignment = 16;
kono
parents:
diff changeset
60 }
kono
parents:
diff changeset
61 }
kono
parents:
diff changeset
62 #endif
kono
parents:
diff changeset
63
kono
parents:
diff changeset
64
kono
parents:
diff changeset
65 static unsigned int
kono
parents:
diff changeset
66 discover_homogeneous_aggregate (const ffi_type *t, unsigned int *elnum)
kono
parents:
diff changeset
67 {
kono
parents:
diff changeset
68 switch (t->type)
kono
parents:
diff changeset
69 {
kono
parents:
diff changeset
70 case FFI_TYPE_FLOAT:
kono
parents:
diff changeset
71 case FFI_TYPE_DOUBLE:
kono
parents:
diff changeset
72 *elnum = 1;
kono
parents:
diff changeset
73 return (int) t->type;
kono
parents:
diff changeset
74
kono
parents:
diff changeset
75 case FFI_TYPE_STRUCT:;
kono
parents:
diff changeset
76 {
kono
parents:
diff changeset
77 unsigned int base_elt = 0, total_elnum = 0;
kono
parents:
diff changeset
78 ffi_type **el = t->elements;
kono
parents:
diff changeset
79 while (*el)
kono
parents:
diff changeset
80 {
kono
parents:
diff changeset
81 unsigned int el_elt, el_elnum = 0;
kono
parents:
diff changeset
82 el_elt = discover_homogeneous_aggregate (*el, &el_elnum);
kono
parents:
diff changeset
83 if (el_elt == 0
kono
parents:
diff changeset
84 || (base_elt && base_elt != el_elt))
kono
parents:
diff changeset
85 return 0;
kono
parents:
diff changeset
86 base_elt = el_elt;
kono
parents:
diff changeset
87 total_elnum += el_elnum;
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
88 #if _CALL_ELF == 2
111
kono
parents:
diff changeset
89 if (total_elnum > 8)
kono
parents:
diff changeset
90 return 0;
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
91 #else
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
92 if (total_elnum > 1)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
93 return 0;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
94 #endif
111
kono
parents:
diff changeset
95 el++;
kono
parents:
diff changeset
96 }
kono
parents:
diff changeset
97 *elnum = total_elnum;
kono
parents:
diff changeset
98 return base_elt;
kono
parents:
diff changeset
99 }
kono
parents:
diff changeset
100
kono
parents:
diff changeset
101 default:
kono
parents:
diff changeset
102 return 0;
kono
parents:
diff changeset
103 }
kono
parents:
diff changeset
104 }
kono
parents:
diff changeset
105
kono
parents:
diff changeset
106
kono
parents:
diff changeset
107 /* Perform machine dependent cif processing */
kono
parents:
diff changeset
108 static ffi_status
kono
parents:
diff changeset
109 ffi_prep_cif_linux64_core (ffi_cif *cif)
kono
parents:
diff changeset
110 {
kono
parents:
diff changeset
111 ffi_type **ptr;
kono
parents:
diff changeset
112 unsigned bytes;
kono
parents:
diff changeset
113 unsigned i, fparg_count = 0, intarg_count = 0;
kono
parents:
diff changeset
114 unsigned flags = cif->flags;
kono
parents:
diff changeset
115 unsigned int elt, elnum;
kono
parents:
diff changeset
116
kono
parents:
diff changeset
117 #if FFI_TYPE_LONGDOUBLE == FFI_TYPE_DOUBLE
kono
parents:
diff changeset
118 /* If compiled without long double support.. */
kono
parents:
diff changeset
119 if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
kono
parents:
diff changeset
120 return FFI_BAD_ABI;
kono
parents:
diff changeset
121 #endif
kono
parents:
diff changeset
122
kono
parents:
diff changeset
123 /* The machine-independent calculation of cif->bytes doesn't work
kono
parents:
diff changeset
124 for us. Redo the calculation. */
kono
parents:
diff changeset
125 #if _CALL_ELF == 2
kono
parents:
diff changeset
126 /* Space for backchain, CR, LR, TOC and the asm's temp regs. */
kono
parents:
diff changeset
127 bytes = (4 + ASM_NEEDS_REGISTERS64) * sizeof (long);
kono
parents:
diff changeset
128
kono
parents:
diff changeset
129 /* Space for the general registers. */
kono
parents:
diff changeset
130 bytes += NUM_GPR_ARG_REGISTERS64 * sizeof (long);
kono
parents:
diff changeset
131 #else
kono
parents:
diff changeset
132 /* Space for backchain, CR, LR, cc/ld doubleword, TOC and the asm's temp
kono
parents:
diff changeset
133 regs. */
kono
parents:
diff changeset
134 bytes = (6 + ASM_NEEDS_REGISTERS64) * sizeof (long);
kono
parents:
diff changeset
135
kono
parents:
diff changeset
136 /* Space for the mandatory parm save area and general registers. */
kono
parents:
diff changeset
137 bytes += 2 * NUM_GPR_ARG_REGISTERS64 * sizeof (long);
kono
parents:
diff changeset
138 #endif
kono
parents:
diff changeset
139
kono
parents:
diff changeset
140 /* Return value handling. */
kono
parents:
diff changeset
141 switch (cif->rtype->type)
kono
parents:
diff changeset
142 {
kono
parents:
diff changeset
143 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
kono
parents:
diff changeset
144 case FFI_TYPE_LONGDOUBLE:
kono
parents:
diff changeset
145 if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
kono
parents:
diff changeset
146 flags |= FLAG_RETURNS_128BITS;
kono
parents:
diff changeset
147 /* Fall through. */
kono
parents:
diff changeset
148 #endif
kono
parents:
diff changeset
149 case FFI_TYPE_DOUBLE:
kono
parents:
diff changeset
150 flags |= FLAG_RETURNS_64BITS;
kono
parents:
diff changeset
151 /* Fall through. */
kono
parents:
diff changeset
152 case FFI_TYPE_FLOAT:
kono
parents:
diff changeset
153 flags |= FLAG_RETURNS_FP;
kono
parents:
diff changeset
154 break;
kono
parents:
diff changeset
155
kono
parents:
diff changeset
156 case FFI_TYPE_UINT128:
kono
parents:
diff changeset
157 flags |= FLAG_RETURNS_128BITS;
kono
parents:
diff changeset
158 /* Fall through. */
kono
parents:
diff changeset
159 case FFI_TYPE_UINT64:
kono
parents:
diff changeset
160 case FFI_TYPE_SINT64:
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
161 case FFI_TYPE_POINTER:
111
kono
parents:
diff changeset
162 flags |= FLAG_RETURNS_64BITS;
kono
parents:
diff changeset
163 break;
kono
parents:
diff changeset
164
kono
parents:
diff changeset
165 case FFI_TYPE_STRUCT:
kono
parents:
diff changeset
166 #if _CALL_ELF == 2
kono
parents:
diff changeset
167 elt = discover_homogeneous_aggregate (cif->rtype, &elnum);
kono
parents:
diff changeset
168 if (elt)
kono
parents:
diff changeset
169 {
kono
parents:
diff changeset
170 if (elt == FFI_TYPE_DOUBLE)
kono
parents:
diff changeset
171 flags |= FLAG_RETURNS_64BITS;
kono
parents:
diff changeset
172 flags |= FLAG_RETURNS_FP | FLAG_RETURNS_SMST;
kono
parents:
diff changeset
173 break;
kono
parents:
diff changeset
174 }
kono
parents:
diff changeset
175 if (cif->rtype->size <= 16)
kono
parents:
diff changeset
176 {
kono
parents:
diff changeset
177 flags |= FLAG_RETURNS_SMST;
kono
parents:
diff changeset
178 break;
kono
parents:
diff changeset
179 }
kono
parents:
diff changeset
180 #endif
kono
parents:
diff changeset
181 intarg_count++;
kono
parents:
diff changeset
182 flags |= FLAG_RETVAL_REFERENCE;
kono
parents:
diff changeset
183 /* Fall through. */
kono
parents:
diff changeset
184 case FFI_TYPE_VOID:
kono
parents:
diff changeset
185 flags |= FLAG_RETURNS_NOTHING;
kono
parents:
diff changeset
186 break;
kono
parents:
diff changeset
187
kono
parents:
diff changeset
188 default:
kono
parents:
diff changeset
189 /* Returns 32-bit integer, or similar. Nothing to do here. */
kono
parents:
diff changeset
190 break;
kono
parents:
diff changeset
191 }
kono
parents:
diff changeset
192
kono
parents:
diff changeset
193 for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
kono
parents:
diff changeset
194 {
kono
parents:
diff changeset
195 unsigned int align;
kono
parents:
diff changeset
196
kono
parents:
diff changeset
197 switch ((*ptr)->type)
kono
parents:
diff changeset
198 {
kono
parents:
diff changeset
199 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
kono
parents:
diff changeset
200 case FFI_TYPE_LONGDOUBLE:
kono
parents:
diff changeset
201 if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
kono
parents:
diff changeset
202 {
kono
parents:
diff changeset
203 fparg_count++;
kono
parents:
diff changeset
204 intarg_count++;
kono
parents:
diff changeset
205 }
kono
parents:
diff changeset
206 /* Fall through. */
kono
parents:
diff changeset
207 #endif
kono
parents:
diff changeset
208 case FFI_TYPE_DOUBLE:
kono
parents:
diff changeset
209 case FFI_TYPE_FLOAT:
kono
parents:
diff changeset
210 fparg_count++;
kono
parents:
diff changeset
211 intarg_count++;
kono
parents:
diff changeset
212 if (fparg_count > NUM_FPR_ARG_REGISTERS64)
kono
parents:
diff changeset
213 flags |= FLAG_ARG_NEEDS_PSAVE;
kono
parents:
diff changeset
214 break;
kono
parents:
diff changeset
215
kono
parents:
diff changeset
216 case FFI_TYPE_STRUCT:
kono
parents:
diff changeset
217 if ((cif->abi & FFI_LINUX_STRUCT_ALIGN) != 0)
kono
parents:
diff changeset
218 {
kono
parents:
diff changeset
219 align = (*ptr)->alignment;
kono
parents:
diff changeset
220 if (align > 16)
kono
parents:
diff changeset
221 align = 16;
kono
parents:
diff changeset
222 align = align / 8;
kono
parents:
diff changeset
223 if (align > 1)
kono
parents:
diff changeset
224 intarg_count = ALIGN (intarg_count, align);
kono
parents:
diff changeset
225 }
kono
parents:
diff changeset
226 intarg_count += ((*ptr)->size + 7) / 8;
kono
parents:
diff changeset
227 elt = discover_homogeneous_aggregate (*ptr, &elnum);
kono
parents:
diff changeset
228 if (elt)
kono
parents:
diff changeset
229 {
kono
parents:
diff changeset
230 fparg_count += elnum;
kono
parents:
diff changeset
231 if (fparg_count > NUM_FPR_ARG_REGISTERS64)
kono
parents:
diff changeset
232 flags |= FLAG_ARG_NEEDS_PSAVE;
kono
parents:
diff changeset
233 }
kono
parents:
diff changeset
234 else
kono
parents:
diff changeset
235 {
kono
parents:
diff changeset
236 if (intarg_count > NUM_GPR_ARG_REGISTERS64)
kono
parents:
diff changeset
237 flags |= FLAG_ARG_NEEDS_PSAVE;
kono
parents:
diff changeset
238 }
kono
parents:
diff changeset
239 break;
kono
parents:
diff changeset
240
kono
parents:
diff changeset
241 case FFI_TYPE_POINTER:
kono
parents:
diff changeset
242 case FFI_TYPE_UINT64:
kono
parents:
diff changeset
243 case FFI_TYPE_SINT64:
kono
parents:
diff changeset
244 case FFI_TYPE_INT:
kono
parents:
diff changeset
245 case FFI_TYPE_UINT32:
kono
parents:
diff changeset
246 case FFI_TYPE_SINT32:
kono
parents:
diff changeset
247 case FFI_TYPE_UINT16:
kono
parents:
diff changeset
248 case FFI_TYPE_SINT16:
kono
parents:
diff changeset
249 case FFI_TYPE_UINT8:
kono
parents:
diff changeset
250 case FFI_TYPE_SINT8:
kono
parents:
diff changeset
251 /* Everything else is passed as a 8-byte word in a GPR, either
kono
parents:
diff changeset
252 the object itself or a pointer to it. */
kono
parents:
diff changeset
253 intarg_count++;
kono
parents:
diff changeset
254 if (intarg_count > NUM_GPR_ARG_REGISTERS64)
kono
parents:
diff changeset
255 flags |= FLAG_ARG_NEEDS_PSAVE;
kono
parents:
diff changeset
256 break;
kono
parents:
diff changeset
257 default:
kono
parents:
diff changeset
258 FFI_ASSERT (0);
kono
parents:
diff changeset
259 }
kono
parents:
diff changeset
260 }
kono
parents:
diff changeset
261
kono
parents:
diff changeset
262 if (fparg_count != 0)
kono
parents:
diff changeset
263 flags |= FLAG_FP_ARGUMENTS;
kono
parents:
diff changeset
264 if (intarg_count > 4)
kono
parents:
diff changeset
265 flags |= FLAG_4_GPR_ARGUMENTS;
kono
parents:
diff changeset
266
kono
parents:
diff changeset
267 /* Space for the FPR registers, if needed. */
kono
parents:
diff changeset
268 if (fparg_count != 0)
kono
parents:
diff changeset
269 bytes += NUM_FPR_ARG_REGISTERS64 * sizeof (double);
kono
parents:
diff changeset
270
kono
parents:
diff changeset
271 /* Stack space. */
kono
parents:
diff changeset
272 #if _CALL_ELF == 2
kono
parents:
diff changeset
273 if ((flags & FLAG_ARG_NEEDS_PSAVE) != 0)
kono
parents:
diff changeset
274 bytes += intarg_count * sizeof (long);
kono
parents:
diff changeset
275 #else
kono
parents:
diff changeset
276 if (intarg_count > NUM_GPR_ARG_REGISTERS64)
kono
parents:
diff changeset
277 bytes += (intarg_count - NUM_GPR_ARG_REGISTERS64) * sizeof (long);
kono
parents:
diff changeset
278 #endif
kono
parents:
diff changeset
279
kono
parents:
diff changeset
280 /* The stack space allocated needs to be a multiple of 16 bytes. */
kono
parents:
diff changeset
281 bytes = (bytes + 15) & ~0xF;
kono
parents:
diff changeset
282
kono
parents:
diff changeset
283 cif->flags = flags;
kono
parents:
diff changeset
284 cif->bytes = bytes;
kono
parents:
diff changeset
285
kono
parents:
diff changeset
286 return FFI_OK;
kono
parents:
diff changeset
287 }
kono
parents:
diff changeset
288
kono
parents:
diff changeset
289 ffi_status FFI_HIDDEN
kono
parents:
diff changeset
290 ffi_prep_cif_linux64 (ffi_cif *cif)
kono
parents:
diff changeset
291 {
kono
parents:
diff changeset
292 if ((cif->abi & FFI_LINUX) != 0)
kono
parents:
diff changeset
293 cif->nfixedargs = cif->nargs;
kono
parents:
diff changeset
294 #if _CALL_ELF != 2
kono
parents:
diff changeset
295 else if (cif->abi == FFI_COMPAT_LINUX64)
kono
parents:
diff changeset
296 {
kono
parents:
diff changeset
297 /* This call is from old code. Don't touch cif->nfixedargs
kono
parents:
diff changeset
298 since old code will be using a smaller cif. */
kono
parents:
diff changeset
299 cif->flags |= FLAG_COMPAT;
kono
parents:
diff changeset
300 /* Translate to new abi value. */
kono
parents:
diff changeset
301 cif->abi = FFI_LINUX | FFI_LINUX_LONG_DOUBLE_128;
kono
parents:
diff changeset
302 }
kono
parents:
diff changeset
303 #endif
kono
parents:
diff changeset
304 else
kono
parents:
diff changeset
305 return FFI_BAD_ABI;
kono
parents:
diff changeset
306 return ffi_prep_cif_linux64_core (cif);
kono
parents:
diff changeset
307 }
kono
parents:
diff changeset
308
kono
parents:
diff changeset
309 ffi_status FFI_HIDDEN
kono
parents:
diff changeset
310 ffi_prep_cif_linux64_var (ffi_cif *cif,
kono
parents:
diff changeset
311 unsigned int nfixedargs,
kono
parents:
diff changeset
312 unsigned int ntotalargs MAYBE_UNUSED)
kono
parents:
diff changeset
313 {
kono
parents:
diff changeset
314 if ((cif->abi & FFI_LINUX) != 0)
kono
parents:
diff changeset
315 cif->nfixedargs = nfixedargs;
kono
parents:
diff changeset
316 #if _CALL_ELF != 2
kono
parents:
diff changeset
317 else if (cif->abi == FFI_COMPAT_LINUX64)
kono
parents:
diff changeset
318 {
kono
parents:
diff changeset
319 /* This call is from old code. Don't touch cif->nfixedargs
kono
parents:
diff changeset
320 since old code will be using a smaller cif. */
kono
parents:
diff changeset
321 cif->flags |= FLAG_COMPAT;
kono
parents:
diff changeset
322 /* Translate to new abi value. */
kono
parents:
diff changeset
323 cif->abi = FFI_LINUX | FFI_LINUX_LONG_DOUBLE_128;
kono
parents:
diff changeset
324 }
kono
parents:
diff changeset
325 #endif
kono
parents:
diff changeset
326 else
kono
parents:
diff changeset
327 return FFI_BAD_ABI;
kono
parents:
diff changeset
328 #if _CALL_ELF == 2
kono
parents:
diff changeset
329 cif->flags |= FLAG_ARG_NEEDS_PSAVE;
kono
parents:
diff changeset
330 #endif
kono
parents:
diff changeset
331 return ffi_prep_cif_linux64_core (cif);
kono
parents:
diff changeset
332 }
kono
parents:
diff changeset
333
kono
parents:
diff changeset
334
kono
parents:
diff changeset
335 /* ffi_prep_args64 is called by the assembly routine once stack space
kono
parents:
diff changeset
336 has been allocated for the function's arguments.
kono
parents:
diff changeset
337
kono
parents:
diff changeset
338 The stack layout we want looks like this:
kono
parents:
diff changeset
339
kono
parents:
diff changeset
340 | Ret addr from ffi_call_LINUX64 8bytes | higher addresses
kono
parents:
diff changeset
341 |--------------------------------------------|
kono
parents:
diff changeset
342 | CR save area 8bytes |
kono
parents:
diff changeset
343 |--------------------------------------------|
kono
parents:
diff changeset
344 | Previous backchain pointer 8 | stack pointer here
kono
parents:
diff changeset
345 |--------------------------------------------|<+ <<< on entry to
kono
parents:
diff changeset
346 | Saved r28-r31 4*8 | | ffi_call_LINUX64
kono
parents:
diff changeset
347 |--------------------------------------------| |
kono
parents:
diff changeset
348 | GPR registers r3-r10 8*8 | |
kono
parents:
diff changeset
349 |--------------------------------------------| |
kono
parents:
diff changeset
350 | FPR registers f1-f13 (optional) 13*8 | |
kono
parents:
diff changeset
351 |--------------------------------------------| |
kono
parents:
diff changeset
352 | Parameter save area | |
kono
parents:
diff changeset
353 |--------------------------------------------| |
kono
parents:
diff changeset
354 | TOC save area 8 | |
kono
parents:
diff changeset
355 |--------------------------------------------| | stack |
kono
parents:
diff changeset
356 | Linker doubleword 8 | | grows |
kono
parents:
diff changeset
357 |--------------------------------------------| | down V
kono
parents:
diff changeset
358 | Compiler doubleword 8 | |
kono
parents:
diff changeset
359 |--------------------------------------------| | lower addresses
kono
parents:
diff changeset
360 | Space for callee's LR 8 | |
kono
parents:
diff changeset
361 |--------------------------------------------| |
kono
parents:
diff changeset
362 | CR save area 8 | |
kono
parents:
diff changeset
363 |--------------------------------------------| | stack pointer here
kono
parents:
diff changeset
364 | Current backchain pointer 8 |-/ during
kono
parents:
diff changeset
365 |--------------------------------------------| <<< ffi_call_LINUX64
kono
parents:
diff changeset
366
kono
parents:
diff changeset
367 */
kono
parents:
diff changeset
368
kono
parents:
diff changeset
369 void FFI_HIDDEN
kono
parents:
diff changeset
370 ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
kono
parents:
diff changeset
371 {
kono
parents:
diff changeset
372 const unsigned long bytes = ecif->cif->bytes;
kono
parents:
diff changeset
373 const unsigned long flags = ecif->cif->flags;
kono
parents:
diff changeset
374
kono
parents:
diff changeset
375 typedef union
kono
parents:
diff changeset
376 {
kono
parents:
diff changeset
377 char *c;
kono
parents:
diff changeset
378 unsigned long *ul;
kono
parents:
diff changeset
379 float *f;
kono
parents:
diff changeset
380 double *d;
kono
parents:
diff changeset
381 size_t p;
kono
parents:
diff changeset
382 } valp;
kono
parents:
diff changeset
383
kono
parents:
diff changeset
384 /* 'stacktop' points at the previous backchain pointer. */
kono
parents:
diff changeset
385 valp stacktop;
kono
parents:
diff changeset
386
kono
parents:
diff changeset
387 /* 'next_arg' points at the space for gpr3, and grows upwards as
kono
parents:
diff changeset
388 we use GPR registers, then continues at rest. */
kono
parents:
diff changeset
389 valp gpr_base;
kono
parents:
diff changeset
390 valp gpr_end;
kono
parents:
diff changeset
391 valp rest;
kono
parents:
diff changeset
392 valp next_arg;
kono
parents:
diff changeset
393
kono
parents:
diff changeset
394 /* 'fpr_base' points at the space for fpr3, and grows upwards as
kono
parents:
diff changeset
395 we use FPR registers. */
kono
parents:
diff changeset
396 valp fpr_base;
kono
parents:
diff changeset
397 unsigned int fparg_count;
kono
parents:
diff changeset
398
kono
parents:
diff changeset
399 unsigned int i, words, nargs, nfixedargs;
kono
parents:
diff changeset
400 ffi_type **ptr;
kono
parents:
diff changeset
401 double double_tmp;
kono
parents:
diff changeset
402 union
kono
parents:
diff changeset
403 {
kono
parents:
diff changeset
404 void **v;
kono
parents:
diff changeset
405 char **c;
kono
parents:
diff changeset
406 signed char **sc;
kono
parents:
diff changeset
407 unsigned char **uc;
kono
parents:
diff changeset
408 signed short **ss;
kono
parents:
diff changeset
409 unsigned short **us;
kono
parents:
diff changeset
410 signed int **si;
kono
parents:
diff changeset
411 unsigned int **ui;
kono
parents:
diff changeset
412 unsigned long **ul;
kono
parents:
diff changeset
413 float **f;
kono
parents:
diff changeset
414 double **d;
kono
parents:
diff changeset
415 } p_argv;
kono
parents:
diff changeset
416 unsigned long gprvalue;
kono
parents:
diff changeset
417 unsigned long align;
kono
parents:
diff changeset
418
kono
parents:
diff changeset
419 stacktop.c = (char *) stack + bytes;
kono
parents:
diff changeset
420 gpr_base.ul = stacktop.ul - ASM_NEEDS_REGISTERS64 - NUM_GPR_ARG_REGISTERS64;
kono
parents:
diff changeset
421 gpr_end.ul = gpr_base.ul + NUM_GPR_ARG_REGISTERS64;
kono
parents:
diff changeset
422 #if _CALL_ELF == 2
kono
parents:
diff changeset
423 rest.ul = stack + 4 + NUM_GPR_ARG_REGISTERS64;
kono
parents:
diff changeset
424 #else
kono
parents:
diff changeset
425 rest.ul = stack + 6 + NUM_GPR_ARG_REGISTERS64;
kono
parents:
diff changeset
426 #endif
kono
parents:
diff changeset
427 fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS64;
kono
parents:
diff changeset
428 fparg_count = 0;
kono
parents:
diff changeset
429 next_arg.ul = gpr_base.ul;
kono
parents:
diff changeset
430
kono
parents:
diff changeset
431 /* Check that everything starts aligned properly. */
kono
parents:
diff changeset
432 FFI_ASSERT (((unsigned long) (char *) stack & 0xF) == 0);
kono
parents:
diff changeset
433 FFI_ASSERT (((unsigned long) stacktop.c & 0xF) == 0);
kono
parents:
diff changeset
434 FFI_ASSERT ((bytes & 0xF) == 0);
kono
parents:
diff changeset
435
kono
parents:
diff changeset
436 /* Deal with return values that are actually pass-by-reference. */
kono
parents:
diff changeset
437 if (flags & FLAG_RETVAL_REFERENCE)
kono
parents:
diff changeset
438 *next_arg.ul++ = (unsigned long) (char *) ecif->rvalue;
kono
parents:
diff changeset
439
kono
parents:
diff changeset
440 /* Now for the arguments. */
kono
parents:
diff changeset
441 p_argv.v = ecif->avalue;
kono
parents:
diff changeset
442 nargs = ecif->cif->nargs;
kono
parents:
diff changeset
443 #if _CALL_ELF != 2
kono
parents:
diff changeset
444 nfixedargs = (unsigned) -1;
kono
parents:
diff changeset
445 if ((flags & FLAG_COMPAT) == 0)
kono
parents:
diff changeset
446 #endif
kono
parents:
diff changeset
447 nfixedargs = ecif->cif->nfixedargs;
kono
parents:
diff changeset
448 for (ptr = ecif->cif->arg_types, i = 0;
kono
parents:
diff changeset
449 i < nargs;
kono
parents:
diff changeset
450 i++, ptr++, p_argv.v++)
kono
parents:
diff changeset
451 {
kono
parents:
diff changeset
452 unsigned int elt, elnum;
kono
parents:
diff changeset
453
kono
parents:
diff changeset
454 switch ((*ptr)->type)
kono
parents:
diff changeset
455 {
kono
parents:
diff changeset
456 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
kono
parents:
diff changeset
457 case FFI_TYPE_LONGDOUBLE:
kono
parents:
diff changeset
458 if ((ecif->cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
kono
parents:
diff changeset
459 {
kono
parents:
diff changeset
460 double_tmp = (*p_argv.d)[0];
kono
parents:
diff changeset
461 if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
kono
parents:
diff changeset
462 {
kono
parents:
diff changeset
463 *fpr_base.d++ = double_tmp;
kono
parents:
diff changeset
464 # if _CALL_ELF != 2
kono
parents:
diff changeset
465 if ((flags & FLAG_COMPAT) != 0)
kono
parents:
diff changeset
466 *next_arg.d = double_tmp;
kono
parents:
diff changeset
467 # endif
kono
parents:
diff changeset
468 }
kono
parents:
diff changeset
469 else
kono
parents:
diff changeset
470 *next_arg.d = double_tmp;
kono
parents:
diff changeset
471 if (++next_arg.ul == gpr_end.ul)
kono
parents:
diff changeset
472 next_arg.ul = rest.ul;
kono
parents:
diff changeset
473 fparg_count++;
kono
parents:
diff changeset
474 double_tmp = (*p_argv.d)[1];
kono
parents:
diff changeset
475 if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
kono
parents:
diff changeset
476 {
kono
parents:
diff changeset
477 *fpr_base.d++ = double_tmp;
kono
parents:
diff changeset
478 # if _CALL_ELF != 2
kono
parents:
diff changeset
479 if ((flags & FLAG_COMPAT) != 0)
kono
parents:
diff changeset
480 *next_arg.d = double_tmp;
kono
parents:
diff changeset
481 # endif
kono
parents:
diff changeset
482 }
kono
parents:
diff changeset
483 else
kono
parents:
diff changeset
484 *next_arg.d = double_tmp;
kono
parents:
diff changeset
485 if (++next_arg.ul == gpr_end.ul)
kono
parents:
diff changeset
486 next_arg.ul = rest.ul;
kono
parents:
diff changeset
487 fparg_count++;
kono
parents:
diff changeset
488 FFI_ASSERT (__LDBL_MANT_DIG__ == 106);
kono
parents:
diff changeset
489 FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
kono
parents:
diff changeset
490 break;
kono
parents:
diff changeset
491 }
kono
parents:
diff changeset
492 /* Fall through. */
kono
parents:
diff changeset
493 #endif
kono
parents:
diff changeset
494 case FFI_TYPE_DOUBLE:
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
495 do_double:
111
kono
parents:
diff changeset
496 double_tmp = **p_argv.d;
kono
parents:
diff changeset
497 if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
kono
parents:
diff changeset
498 {
kono
parents:
diff changeset
499 *fpr_base.d++ = double_tmp;
kono
parents:
diff changeset
500 #if _CALL_ELF != 2
kono
parents:
diff changeset
501 if ((flags & FLAG_COMPAT) != 0)
kono
parents:
diff changeset
502 *next_arg.d = double_tmp;
kono
parents:
diff changeset
503 #endif
kono
parents:
diff changeset
504 }
kono
parents:
diff changeset
505 else
kono
parents:
diff changeset
506 *next_arg.d = double_tmp;
kono
parents:
diff changeset
507 if (++next_arg.ul == gpr_end.ul)
kono
parents:
diff changeset
508 next_arg.ul = rest.ul;
kono
parents:
diff changeset
509 fparg_count++;
kono
parents:
diff changeset
510 FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
kono
parents:
diff changeset
511 break;
kono
parents:
diff changeset
512
kono
parents:
diff changeset
513 case FFI_TYPE_FLOAT:
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
514 do_float:
111
kono
parents:
diff changeset
515 double_tmp = **p_argv.f;
kono
parents:
diff changeset
516 if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
kono
parents:
diff changeset
517 {
kono
parents:
diff changeset
518 *fpr_base.d++ = double_tmp;
kono
parents:
diff changeset
519 #if _CALL_ELF != 2
kono
parents:
diff changeset
520 if ((flags & FLAG_COMPAT) != 0)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
521 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
522 # ifndef __LITTLE_ENDIAN__
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
523 next_arg.f[1] = (float) double_tmp;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
524 # else
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
525 next_arg.f[0] = (float) double_tmp;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
526 # endif
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
527 }
111
kono
parents:
diff changeset
528 #endif
kono
parents:
diff changeset
529 }
kono
parents:
diff changeset
530 else
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
531 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
532 # ifndef __LITTLE_ENDIAN__
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
533 next_arg.f[1] = (float) double_tmp;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
534 # else
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
535 next_arg.f[0] = (float) double_tmp;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
536 # endif
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
537 }
111
kono
parents:
diff changeset
538 if (++next_arg.ul == gpr_end.ul)
kono
parents:
diff changeset
539 next_arg.ul = rest.ul;
kono
parents:
diff changeset
540 fparg_count++;
kono
parents:
diff changeset
541 FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
kono
parents:
diff changeset
542 break;
kono
parents:
diff changeset
543
kono
parents:
diff changeset
544 case FFI_TYPE_STRUCT:
kono
parents:
diff changeset
545 if ((ecif->cif->abi & FFI_LINUX_STRUCT_ALIGN) != 0)
kono
parents:
diff changeset
546 {
kono
parents:
diff changeset
547 align = (*ptr)->alignment;
kono
parents:
diff changeset
548 if (align > 16)
kono
parents:
diff changeset
549 align = 16;
kono
parents:
diff changeset
550 if (align > 1)
kono
parents:
diff changeset
551 next_arg.p = ALIGN (next_arg.p, align);
kono
parents:
diff changeset
552 }
kono
parents:
diff changeset
553 elt = discover_homogeneous_aggregate (*ptr, &elnum);
kono
parents:
diff changeset
554 if (elt)
kono
parents:
diff changeset
555 {
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
556 #if _CALL_ELF == 2
111
kono
parents:
diff changeset
557 union {
kono
parents:
diff changeset
558 void *v;
kono
parents:
diff changeset
559 float *f;
kono
parents:
diff changeset
560 double *d;
kono
parents:
diff changeset
561 } arg;
kono
parents:
diff changeset
562
kono
parents:
diff changeset
563 arg.v = *p_argv.v;
kono
parents:
diff changeset
564 if (elt == FFI_TYPE_FLOAT)
kono
parents:
diff changeset
565 {
kono
parents:
diff changeset
566 do
kono
parents:
diff changeset
567 {
kono
parents:
diff changeset
568 double_tmp = *arg.f++;
kono
parents:
diff changeset
569 if (fparg_count < NUM_FPR_ARG_REGISTERS64
kono
parents:
diff changeset
570 && i < nfixedargs)
kono
parents:
diff changeset
571 *fpr_base.d++ = double_tmp;
kono
parents:
diff changeset
572 else
kono
parents:
diff changeset
573 *next_arg.f = (float) double_tmp;
kono
parents:
diff changeset
574 if (++next_arg.f == gpr_end.f)
kono
parents:
diff changeset
575 next_arg.f = rest.f;
kono
parents:
diff changeset
576 fparg_count++;
kono
parents:
diff changeset
577 }
kono
parents:
diff changeset
578 while (--elnum != 0);
kono
parents:
diff changeset
579 if ((next_arg.p & 3) != 0)
kono
parents:
diff changeset
580 {
kono
parents:
diff changeset
581 if (++next_arg.f == gpr_end.f)
kono
parents:
diff changeset
582 next_arg.f = rest.f;
kono
parents:
diff changeset
583 }
kono
parents:
diff changeset
584 }
kono
parents:
diff changeset
585 else
kono
parents:
diff changeset
586 do
kono
parents:
diff changeset
587 {
kono
parents:
diff changeset
588 double_tmp = *arg.d++;
kono
parents:
diff changeset
589 if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
kono
parents:
diff changeset
590 *fpr_base.d++ = double_tmp;
kono
parents:
diff changeset
591 else
kono
parents:
diff changeset
592 *next_arg.d = double_tmp;
kono
parents:
diff changeset
593 if (++next_arg.d == gpr_end.d)
kono
parents:
diff changeset
594 next_arg.d = rest.d;
kono
parents:
diff changeset
595 fparg_count++;
kono
parents:
diff changeset
596 }
kono
parents:
diff changeset
597 while (--elnum != 0);
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
598 #else
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
599 if (elt == FFI_TYPE_FLOAT)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
600 goto do_float;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
601 else
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
602 goto do_double;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
603 #endif
111
kono
parents:
diff changeset
604 }
kono
parents:
diff changeset
605 else
kono
parents:
diff changeset
606 {
kono
parents:
diff changeset
607 words = ((*ptr)->size + 7) / 8;
kono
parents:
diff changeset
608 if (next_arg.ul >= gpr_base.ul && next_arg.ul + words > gpr_end.ul)
kono
parents:
diff changeset
609 {
kono
parents:
diff changeset
610 size_t first = gpr_end.c - next_arg.c;
kono
parents:
diff changeset
611 memcpy (next_arg.c, *p_argv.c, first);
kono
parents:
diff changeset
612 memcpy (rest.c, *p_argv.c + first, (*ptr)->size - first);
kono
parents:
diff changeset
613 next_arg.c = rest.c + words * 8 - first;
kono
parents:
diff changeset
614 }
kono
parents:
diff changeset
615 else
kono
parents:
diff changeset
616 {
kono
parents:
diff changeset
617 char *where = next_arg.c;
kono
parents:
diff changeset
618
kono
parents:
diff changeset
619 #ifndef __LITTLE_ENDIAN__
kono
parents:
diff changeset
620 /* Structures with size less than eight bytes are passed
kono
parents:
diff changeset
621 left-padded. */
kono
parents:
diff changeset
622 if ((*ptr)->size < 8)
kono
parents:
diff changeset
623 where += 8 - (*ptr)->size;
kono
parents:
diff changeset
624 #endif
kono
parents:
diff changeset
625 memcpy (where, *p_argv.c, (*ptr)->size);
kono
parents:
diff changeset
626 next_arg.ul += words;
kono
parents:
diff changeset
627 if (next_arg.ul == gpr_end.ul)
kono
parents:
diff changeset
628 next_arg.ul = rest.ul;
kono
parents:
diff changeset
629 }
kono
parents:
diff changeset
630 }
kono
parents:
diff changeset
631 break;
kono
parents:
diff changeset
632
kono
parents:
diff changeset
633 case FFI_TYPE_UINT8:
kono
parents:
diff changeset
634 gprvalue = **p_argv.uc;
kono
parents:
diff changeset
635 goto putgpr;
kono
parents:
diff changeset
636 case FFI_TYPE_SINT8:
kono
parents:
diff changeset
637 gprvalue = **p_argv.sc;
kono
parents:
diff changeset
638 goto putgpr;
kono
parents:
diff changeset
639 case FFI_TYPE_UINT16:
kono
parents:
diff changeset
640 gprvalue = **p_argv.us;
kono
parents:
diff changeset
641 goto putgpr;
kono
parents:
diff changeset
642 case FFI_TYPE_SINT16:
kono
parents:
diff changeset
643 gprvalue = **p_argv.ss;
kono
parents:
diff changeset
644 goto putgpr;
kono
parents:
diff changeset
645 case FFI_TYPE_UINT32:
kono
parents:
diff changeset
646 gprvalue = **p_argv.ui;
kono
parents:
diff changeset
647 goto putgpr;
kono
parents:
diff changeset
648 case FFI_TYPE_INT:
kono
parents:
diff changeset
649 case FFI_TYPE_SINT32:
kono
parents:
diff changeset
650 gprvalue = **p_argv.si;
kono
parents:
diff changeset
651 goto putgpr;
kono
parents:
diff changeset
652
kono
parents:
diff changeset
653 case FFI_TYPE_UINT64:
kono
parents:
diff changeset
654 case FFI_TYPE_SINT64:
kono
parents:
diff changeset
655 case FFI_TYPE_POINTER:
kono
parents:
diff changeset
656 gprvalue = **p_argv.ul;
kono
parents:
diff changeset
657 putgpr:
kono
parents:
diff changeset
658 *next_arg.ul++ = gprvalue;
kono
parents:
diff changeset
659 if (next_arg.ul == gpr_end.ul)
kono
parents:
diff changeset
660 next_arg.ul = rest.ul;
kono
parents:
diff changeset
661 break;
kono
parents:
diff changeset
662 }
kono
parents:
diff changeset
663 }
kono
parents:
diff changeset
664
kono
parents:
diff changeset
665 FFI_ASSERT (flags & FLAG_4_GPR_ARGUMENTS
kono
parents:
diff changeset
666 || (next_arg.ul >= gpr_base.ul
kono
parents:
diff changeset
667 && next_arg.ul <= gpr_base.ul + 4));
kono
parents:
diff changeset
668 }
kono
parents:
diff changeset
669
kono
parents:
diff changeset
670
kono
parents:
diff changeset
671 #if _CALL_ELF == 2
kono
parents:
diff changeset
672 #define MIN_CACHE_LINE_SIZE 8
kono
parents:
diff changeset
673
kono
parents:
diff changeset
674 static void
kono
parents:
diff changeset
675 flush_icache (char *wraddr, char *xaddr, int size)
kono
parents:
diff changeset
676 {
kono
parents:
diff changeset
677 int i;
kono
parents:
diff changeset
678 for (i = 0; i < size; i += MIN_CACHE_LINE_SIZE)
kono
parents:
diff changeset
679 __asm__ volatile ("icbi 0,%0;" "dcbf 0,%1;"
kono
parents:
diff changeset
680 : : "r" (xaddr + i), "r" (wraddr + i) : "memory");
kono
parents:
diff changeset
681 __asm__ volatile ("icbi 0,%0;" "dcbf 0,%1;" "sync;" "isync;"
kono
parents:
diff changeset
682 : : "r"(xaddr + size - 1), "r"(wraddr + size - 1)
kono
parents:
diff changeset
683 : "memory");
kono
parents:
diff changeset
684 }
kono
parents:
diff changeset
685 #endif
kono
parents:
diff changeset
686
kono
parents:
diff changeset
687
kono
parents:
diff changeset
688 ffi_status FFI_HIDDEN
kono
parents:
diff changeset
689 ffi_prep_closure_loc_linux64 (ffi_closure *closure,
kono
parents:
diff changeset
690 ffi_cif *cif,
kono
parents:
diff changeset
691 void (*fun) (ffi_cif *, void *, void **, void *),
kono
parents:
diff changeset
692 void *user_data,
kono
parents:
diff changeset
693 void *codeloc)
kono
parents:
diff changeset
694 {
kono
parents:
diff changeset
695 #if _CALL_ELF == 2
kono
parents:
diff changeset
696 unsigned int *tramp = (unsigned int *) &closure->tramp[0];
kono
parents:
diff changeset
697
kono
parents:
diff changeset
698 if (cif->abi < FFI_LINUX || cif->abi >= FFI_LAST_ABI)
kono
parents:
diff changeset
699 return FFI_BAD_ABI;
kono
parents:
diff changeset
700
kono
parents:
diff changeset
701 tramp[0] = 0xe96c0018; /* 0: ld 11,2f-0b(12) */
kono
parents:
diff changeset
702 tramp[1] = 0xe98c0010; /* ld 12,1f-0b(12) */
kono
parents:
diff changeset
703 tramp[2] = 0x7d8903a6; /* mtctr 12 */
kono
parents:
diff changeset
704 tramp[3] = 0x4e800420; /* bctr */
kono
parents:
diff changeset
705 /* 1: .quad function_addr */
kono
parents:
diff changeset
706 /* 2: .quad context */
kono
parents:
diff changeset
707 *(void **) &tramp[4] = (void *) ffi_closure_LINUX64;
kono
parents:
diff changeset
708 *(void **) &tramp[6] = codeloc;
kono
parents:
diff changeset
709 flush_icache ((char *) tramp, (char *) codeloc, 4 * 4);
kono
parents:
diff changeset
710 #else
kono
parents:
diff changeset
711 void **tramp = (void **) &closure->tramp[0];
kono
parents:
diff changeset
712
kono
parents:
diff changeset
713 if (cif->abi < FFI_LINUX || cif->abi >= FFI_LAST_ABI)
kono
parents:
diff changeset
714 return FFI_BAD_ABI;
kono
parents:
diff changeset
715
kono
parents:
diff changeset
716 /* Copy function address and TOC from ffi_closure_LINUX64 OPD. */
kono
parents:
diff changeset
717 memcpy (&tramp[0], (void **) ffi_closure_LINUX64, sizeof (void *));
kono
parents:
diff changeset
718 tramp[1] = codeloc;
kono
parents:
diff changeset
719 memcpy (&tramp[2], (void **) ffi_closure_LINUX64 + 1, sizeof (void *));
kono
parents:
diff changeset
720 #endif
kono
parents:
diff changeset
721
kono
parents:
diff changeset
722 closure->cif = cif;
kono
parents:
diff changeset
723 closure->fun = fun;
kono
parents:
diff changeset
724 closure->user_data = user_data;
kono
parents:
diff changeset
725
kono
parents:
diff changeset
726 return FFI_OK;
kono
parents:
diff changeset
727 }
kono
parents:
diff changeset
728
kono
parents:
diff changeset
729
kono
parents:
diff changeset
730 int FFI_HIDDEN
kono
parents:
diff changeset
731 ffi_closure_helper_LINUX64 (ffi_cif *cif,
kono
parents:
diff changeset
732 void (*fun) (ffi_cif *, void *, void **, void *),
kono
parents:
diff changeset
733 void *user_data,
kono
parents:
diff changeset
734 void *rvalue,
kono
parents:
diff changeset
735 unsigned long *pst,
kono
parents:
diff changeset
736 ffi_dblfl *pfr)
kono
parents:
diff changeset
737 {
kono
parents:
diff changeset
738 /* rvalue is the pointer to space for return value in closure assembly */
kono
parents:
diff changeset
739 /* pst is the pointer to parameter save area
kono
parents:
diff changeset
740 (r3-r10 are stored into its first 8 slots by ffi_closure_LINUX64) */
kono
parents:
diff changeset
741 /* pfr is the pointer to where f1-f13 are stored in ffi_closure_LINUX64 */
kono
parents:
diff changeset
742
kono
parents:
diff changeset
743 void **avalue;
kono
parents:
diff changeset
744 ffi_type **arg_types;
kono
parents:
diff changeset
745 unsigned long i, avn, nfixedargs;
kono
parents:
diff changeset
746 ffi_dblfl *end_pfr = pfr + NUM_FPR_ARG_REGISTERS64;
kono
parents:
diff changeset
747 unsigned long align;
kono
parents:
diff changeset
748
kono
parents:
diff changeset
749 avalue = alloca (cif->nargs * sizeof (void *));
kono
parents:
diff changeset
750
kono
parents:
diff changeset
751 /* Copy the caller's structure return value address so that the
kono
parents:
diff changeset
752 closure returns the data directly to the caller. */
kono
parents:
diff changeset
753 if (cif->rtype->type == FFI_TYPE_STRUCT
kono
parents:
diff changeset
754 && (cif->flags & FLAG_RETURNS_SMST) == 0)
kono
parents:
diff changeset
755 {
kono
parents:
diff changeset
756 rvalue = (void *) *pst;
kono
parents:
diff changeset
757 pst++;
kono
parents:
diff changeset
758 }
kono
parents:
diff changeset
759
kono
parents:
diff changeset
760 i = 0;
kono
parents:
diff changeset
761 avn = cif->nargs;
kono
parents:
diff changeset
762 #if _CALL_ELF != 2
kono
parents:
diff changeset
763 nfixedargs = (unsigned) -1;
kono
parents:
diff changeset
764 if ((cif->flags & FLAG_COMPAT) == 0)
kono
parents:
diff changeset
765 #endif
kono
parents:
diff changeset
766 nfixedargs = cif->nfixedargs;
kono
parents:
diff changeset
767 arg_types = cif->arg_types;
kono
parents:
diff changeset
768
kono
parents:
diff changeset
769 /* Grab the addresses of the arguments from the stack frame. */
kono
parents:
diff changeset
770 while (i < avn)
kono
parents:
diff changeset
771 {
kono
parents:
diff changeset
772 unsigned int elt, elnum;
kono
parents:
diff changeset
773
kono
parents:
diff changeset
774 switch (arg_types[i]->type)
kono
parents:
diff changeset
775 {
kono
parents:
diff changeset
776 case FFI_TYPE_SINT8:
kono
parents:
diff changeset
777 case FFI_TYPE_UINT8:
kono
parents:
diff changeset
778 #ifndef __LITTLE_ENDIAN__
kono
parents:
diff changeset
779 avalue[i] = (char *) pst + 7;
kono
parents:
diff changeset
780 pst++;
kono
parents:
diff changeset
781 break;
kono
parents:
diff changeset
782 #endif
kono
parents:
diff changeset
783
kono
parents:
diff changeset
784 case FFI_TYPE_SINT16:
kono
parents:
diff changeset
785 case FFI_TYPE_UINT16:
kono
parents:
diff changeset
786 #ifndef __LITTLE_ENDIAN__
kono
parents:
diff changeset
787 avalue[i] = (char *) pst + 6;
kono
parents:
diff changeset
788 pst++;
kono
parents:
diff changeset
789 break;
kono
parents:
diff changeset
790 #endif
kono
parents:
diff changeset
791
kono
parents:
diff changeset
792 case FFI_TYPE_SINT32:
kono
parents:
diff changeset
793 case FFI_TYPE_UINT32:
kono
parents:
diff changeset
794 #ifndef __LITTLE_ENDIAN__
kono
parents:
diff changeset
795 avalue[i] = (char *) pst + 4;
kono
parents:
diff changeset
796 pst++;
kono
parents:
diff changeset
797 break;
kono
parents:
diff changeset
798 #endif
kono
parents:
diff changeset
799
kono
parents:
diff changeset
800 case FFI_TYPE_SINT64:
kono
parents:
diff changeset
801 case FFI_TYPE_UINT64:
kono
parents:
diff changeset
802 case FFI_TYPE_POINTER:
kono
parents:
diff changeset
803 avalue[i] = pst;
kono
parents:
diff changeset
804 pst++;
kono
parents:
diff changeset
805 break;
kono
parents:
diff changeset
806
kono
parents:
diff changeset
807 case FFI_TYPE_STRUCT:
kono
parents:
diff changeset
808 if ((cif->abi & FFI_LINUX_STRUCT_ALIGN) != 0)
kono
parents:
diff changeset
809 {
kono
parents:
diff changeset
810 align = arg_types[i]->alignment;
kono
parents:
diff changeset
811 if (align > 16)
kono
parents:
diff changeset
812 align = 16;
kono
parents:
diff changeset
813 if (align > 1)
kono
parents:
diff changeset
814 pst = (unsigned long *) ALIGN ((size_t) pst, align);
kono
parents:
diff changeset
815 }
kono
parents:
diff changeset
816 elt = discover_homogeneous_aggregate (arg_types[i], &elnum);
kono
parents:
diff changeset
817 if (elt)
kono
parents:
diff changeset
818 {
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
819 #if _CALL_ELF == 2
111
kono
parents:
diff changeset
820 union {
kono
parents:
diff changeset
821 void *v;
kono
parents:
diff changeset
822 unsigned long *ul;
kono
parents:
diff changeset
823 float *f;
kono
parents:
diff changeset
824 double *d;
kono
parents:
diff changeset
825 size_t p;
kono
parents:
diff changeset
826 } to, from;
kono
parents:
diff changeset
827
kono
parents:
diff changeset
828 /* Repackage the aggregate from its parts. The
kono
parents:
diff changeset
829 aggregate size is not greater than the space taken by
kono
parents:
diff changeset
830 the registers so store back to the register/parameter
kono
parents:
diff changeset
831 save arrays. */
kono
parents:
diff changeset
832 if (pfr + elnum <= end_pfr)
kono
parents:
diff changeset
833 to.v = pfr;
kono
parents:
diff changeset
834 else
kono
parents:
diff changeset
835 to.v = pst;
kono
parents:
diff changeset
836
kono
parents:
diff changeset
837 avalue[i] = to.v;
kono
parents:
diff changeset
838 from.ul = pst;
kono
parents:
diff changeset
839 if (elt == FFI_TYPE_FLOAT)
kono
parents:
diff changeset
840 {
kono
parents:
diff changeset
841 do
kono
parents:
diff changeset
842 {
kono
parents:
diff changeset
843 if (pfr < end_pfr && i < nfixedargs)
kono
parents:
diff changeset
844 {
kono
parents:
diff changeset
845 *to.f = (float) pfr->d;
kono
parents:
diff changeset
846 pfr++;
kono
parents:
diff changeset
847 }
kono
parents:
diff changeset
848 else
kono
parents:
diff changeset
849 *to.f = *from.f;
kono
parents:
diff changeset
850 to.f++;
kono
parents:
diff changeset
851 from.f++;
kono
parents:
diff changeset
852 }
kono
parents:
diff changeset
853 while (--elnum != 0);
kono
parents:
diff changeset
854 }
kono
parents:
diff changeset
855 else
kono
parents:
diff changeset
856 {
kono
parents:
diff changeset
857 do
kono
parents:
diff changeset
858 {
kono
parents:
diff changeset
859 if (pfr < end_pfr && i < nfixedargs)
kono
parents:
diff changeset
860 {
kono
parents:
diff changeset
861 *to.d = pfr->d;
kono
parents:
diff changeset
862 pfr++;
kono
parents:
diff changeset
863 }
kono
parents:
diff changeset
864 else
kono
parents:
diff changeset
865 *to.d = *from.d;
kono
parents:
diff changeset
866 to.d++;
kono
parents:
diff changeset
867 from.d++;
kono
parents:
diff changeset
868 }
kono
parents:
diff changeset
869 while (--elnum != 0);
kono
parents:
diff changeset
870 }
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
871 #else
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
872 if (elt == FFI_TYPE_FLOAT)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
873 goto do_float;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
874 else
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
875 goto do_double;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
876 #endif
111
kono
parents:
diff changeset
877 }
kono
parents:
diff changeset
878 else
kono
parents:
diff changeset
879 {
kono
parents:
diff changeset
880 #ifndef __LITTLE_ENDIAN__
kono
parents:
diff changeset
881 /* Structures with size less than eight bytes are passed
kono
parents:
diff changeset
882 left-padded. */
kono
parents:
diff changeset
883 if (arg_types[i]->size < 8)
kono
parents:
diff changeset
884 avalue[i] = (char *) pst + 8 - arg_types[i]->size;
kono
parents:
diff changeset
885 else
kono
parents:
diff changeset
886 #endif
kono
parents:
diff changeset
887 avalue[i] = pst;
kono
parents:
diff changeset
888 }
kono
parents:
diff changeset
889 pst += (arg_types[i]->size + 7) / 8;
kono
parents:
diff changeset
890 break;
kono
parents:
diff changeset
891
kono
parents:
diff changeset
892 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
kono
parents:
diff changeset
893 case FFI_TYPE_LONGDOUBLE:
kono
parents:
diff changeset
894 if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
kono
parents:
diff changeset
895 {
kono
parents:
diff changeset
896 if (pfr + 1 < end_pfr && i + 1 < nfixedargs)
kono
parents:
diff changeset
897 {
kono
parents:
diff changeset
898 avalue[i] = pfr;
kono
parents:
diff changeset
899 pfr += 2;
kono
parents:
diff changeset
900 }
kono
parents:
diff changeset
901 else
kono
parents:
diff changeset
902 {
kono
parents:
diff changeset
903 if (pfr < end_pfr && i < nfixedargs)
kono
parents:
diff changeset
904 {
kono
parents:
diff changeset
905 /* Passed partly in f13 and partly on the stack.
kono
parents:
diff changeset
906 Move it all to the stack. */
kono
parents:
diff changeset
907 *pst = *(unsigned long *) pfr;
kono
parents:
diff changeset
908 pfr++;
kono
parents:
diff changeset
909 }
kono
parents:
diff changeset
910 avalue[i] = pst;
kono
parents:
diff changeset
911 }
kono
parents:
diff changeset
912 pst += 2;
kono
parents:
diff changeset
913 break;
kono
parents:
diff changeset
914 }
kono
parents:
diff changeset
915 /* Fall through. */
kono
parents:
diff changeset
916 #endif
kono
parents:
diff changeset
917 case FFI_TYPE_DOUBLE:
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
918 do_double:
111
kono
parents:
diff changeset
919 /* On the outgoing stack all values are aligned to 8 */
kono
parents:
diff changeset
920 /* there are 13 64bit floating point registers */
kono
parents:
diff changeset
921
kono
parents:
diff changeset
922 if (pfr < end_pfr && i < nfixedargs)
kono
parents:
diff changeset
923 {
kono
parents:
diff changeset
924 avalue[i] = pfr;
kono
parents:
diff changeset
925 pfr++;
kono
parents:
diff changeset
926 }
kono
parents:
diff changeset
927 else
kono
parents:
diff changeset
928 avalue[i] = pst;
kono
parents:
diff changeset
929 pst++;
kono
parents:
diff changeset
930 break;
kono
parents:
diff changeset
931
kono
parents:
diff changeset
932 case FFI_TYPE_FLOAT:
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
933 do_float:
111
kono
parents:
diff changeset
934 if (pfr < end_pfr && i < nfixedargs)
kono
parents:
diff changeset
935 {
kono
parents:
diff changeset
936 /* Float values are stored as doubles in the
kono
parents:
diff changeset
937 ffi_closure_LINUX64 code. Fix them here. */
kono
parents:
diff changeset
938 pfr->f = (float) pfr->d;
kono
parents:
diff changeset
939 avalue[i] = pfr;
kono
parents:
diff changeset
940 pfr++;
kono
parents:
diff changeset
941 }
kono
parents:
diff changeset
942 else
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
943 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
944 #ifndef __LITTLE_ENDIAN__
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
945 avalue[i] = (char *) pst + 4;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
946 #else
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
947 avalue[i] = pst;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
948 #endif
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
949 }
111
kono
parents:
diff changeset
950 pst++;
kono
parents:
diff changeset
951 break;
kono
parents:
diff changeset
952
kono
parents:
diff changeset
953 default:
kono
parents:
diff changeset
954 FFI_ASSERT (0);
kono
parents:
diff changeset
955 }
kono
parents:
diff changeset
956
kono
parents:
diff changeset
957 i++;
kono
parents:
diff changeset
958 }
kono
parents:
diff changeset
959
kono
parents:
diff changeset
960 (*fun) (cif, rvalue, avalue, user_data);
kono
parents:
diff changeset
961
kono
parents:
diff changeset
962 /* Tell ffi_closure_LINUX64 how to perform return type promotions. */
kono
parents:
diff changeset
963 if ((cif->flags & FLAG_RETURNS_SMST) != 0)
kono
parents:
diff changeset
964 {
kono
parents:
diff changeset
965 if ((cif->flags & FLAG_RETURNS_FP) == 0)
kono
parents:
diff changeset
966 return FFI_V2_TYPE_SMALL_STRUCT + cif->rtype->size - 1;
kono
parents:
diff changeset
967 else if ((cif->flags & FLAG_RETURNS_64BITS) != 0)
kono
parents:
diff changeset
968 return FFI_V2_TYPE_DOUBLE_HOMOG;
kono
parents:
diff changeset
969 else
kono
parents:
diff changeset
970 return FFI_V2_TYPE_FLOAT_HOMOG;
kono
parents:
diff changeset
971 }
kono
parents:
diff changeset
972 return cif->rtype->type;
kono
parents:
diff changeset
973 }
kono
parents:
diff changeset
974 #endif