ยปCore Development>Code coverage>Modules/_ctypes/libffi/src/powerpc/ffi_linux64.c

Python code coverage for Modules/_ctypes/libffi/src/powerpc/ffi_linux64.c

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