]>
Commit | Line | Data |
---|---|---|
1 | /* ----------------------------------------------------------------------- | |
2 | ffi.c - Copyright (C) 2013 IBM | |
3 | Copyright (C) 2011 Anthony Green | |
4 | Copyright (C) 2011 Kyle Moffett | |
5 | Copyright (C) 2008 Red Hat, Inc | |
6 | Copyright (C) 2007, 2008 Free Software Foundation, Inc | |
7 | Copyright (c) 1998 Geoffrey Keating | |
8 | ||
9 | PowerPC Foreign Function Interface | |
10 | ||
11 | Permission is hereby granted, free of charge, to any person obtaining | |
12 | a copy of this software and associated documentation files (the | |
13 | ``Software''), to deal in the Software without restriction, including | |
14 | without limitation the rights to use, copy, modify, merge, publish, | |
15 | distribute, sublicense, and/or sell copies of the Software, and to | |
16 | permit persons to whom the Software is furnished to do so, subject to | |
17 | the following conditions: | |
18 | ||
19 | The above copyright notice and this permission notice shall be included | |
20 | in all copies or substantial portions of the Software. | |
21 | ||
22 | THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS | |
23 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
24 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
25 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
26 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
27 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
28 | OTHER DEALINGS IN THE SOFTWARE. | |
29 | ----------------------------------------------------------------------- */ | |
30 | ||
31 | #include "ffi.h" | |
32 | #include "ffi_common.h" | |
33 | #include "ffi_powerpc.h" | |
34 | ||
35 | #if HAVE_LONG_DOUBLE_VARIANT | |
36 | /* Adjust ffi_type_longdouble. */ | |
37 | void FFI_HIDDEN | |
38 | ffi_prep_types (ffi_abi abi) | |
39 | { | |
40 | # if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE | |
41 | # ifdef POWERPC64 | |
42 | ffi_prep_types_linux64 (abi); | |
43 | # else | |
44 | ffi_prep_types_sysv (abi); | |
45 | # endif | |
46 | # endif | |
47 | } | |
48 | #endif | |
49 | ||
50 | /* Perform machine dependent cif processing */ | |
51 | ffi_status FFI_HIDDEN | |
52 | ffi_prep_cif_machdep (ffi_cif *cif) | |
53 | { | |
54 | #ifdef POWERPC64 | |
55 | return ffi_prep_cif_linux64 (cif); | |
56 | #else | |
57 | return ffi_prep_cif_sysv (cif); | |
58 | #endif | |
59 | } | |
60 | ||
61 | ffi_status FFI_HIDDEN | |
62 | ffi_prep_cif_machdep_var (ffi_cif *cif, | |
63 | unsigned int nfixedargs MAYBE_UNUSED, | |
64 | unsigned int ntotalargs MAYBE_UNUSED) | |
65 | { | |
66 | #ifdef POWERPC64 | |
67 | return ffi_prep_cif_linux64_var (cif, nfixedargs, ntotalargs); | |
68 | #else | |
69 | return ffi_prep_cif_sysv (cif); | |
70 | #endif | |
71 | } | |
72 | ||
73 | static void | |
74 | ffi_call_int (ffi_cif *cif, | |
75 | void (*fn) (void), | |
76 | void *rvalue, | |
77 | void **avalue, | |
78 | void *closure) | |
79 | { | |
80 | /* The final SYSV ABI says that structures smaller or equal 8 bytes | |
81 | are returned in r3/r4. A draft ABI used by linux instead returns | |
82 | them in memory. | |
83 | ||
84 | We bounce-buffer SYSV small struct return values so that sysv.S | |
85 | can write r3 and r4 to memory without worrying about struct size. | |
86 | ||
87 | For ELFv2 ABI, use a bounce buffer for homogeneous structs too, | |
88 | for similar reasons. This bounce buffer must be aligned to 16 | |
89 | bytes for use with homogeneous structs of vectors (float128). */ | |
90 | float128 smst_buffer[8]; | |
91 | extended_cif ecif; | |
92 | ||
93 | ecif.cif = cif; | |
94 | ecif.avalue = avalue; | |
95 | ||
96 | ecif.rvalue = rvalue; | |
97 | if ((cif->flags & FLAG_RETURNS_SMST) != 0) | |
98 | ecif.rvalue = smst_buffer; | |
99 | /* Ensure that we have a valid struct return value. | |
100 | FIXME: Isn't this just papering over a user problem? */ | |
101 | else if (!rvalue && cif->rtype->type == FFI_TYPE_STRUCT) | |
102 | ecif.rvalue = alloca (cif->rtype->size); | |
103 | ||
104 | #ifdef POWERPC64 | |
105 | ffi_call_LINUX64 (&ecif, fn, ecif.rvalue, cif->flags, closure, | |
106 | -(long) cif->bytes); | |
107 | #else | |
108 | ffi_call_SYSV (&ecif, fn, ecif.rvalue, cif->flags, closure, -cif->bytes); | |
109 | #endif | |
110 | ||
111 | /* Check for a bounce-buffered return value */ | |
112 | if (rvalue && ecif.rvalue == smst_buffer) | |
113 | { | |
114 | unsigned int rsize = cif->rtype->size; | |
115 | #ifndef __LITTLE_ENDIAN__ | |
116 | /* The SYSV ABI returns a structure of up to 4 bytes in size | |
117 | left-padded in r3. */ | |
118 | # ifndef POWERPC64 | |
119 | if (rsize <= 4) | |
120 | memcpy (rvalue, (char *) smst_buffer + 4 - rsize, rsize); | |
121 | else | |
122 | # endif | |
123 | /* The SYSV ABI returns a structure of up to 8 bytes in size | |
124 | left-padded in r3/r4, and the ELFv2 ABI similarly returns a | |
125 | structure of up to 8 bytes in size left-padded in r3. But | |
126 | note that a structure of a single float is not paddded. */ | |
127 | if (rsize <= 8 && (cif->flags & FLAG_RETURNS_FP) == 0) | |
128 | memcpy (rvalue, (char *) smst_buffer + 8 - rsize, rsize); | |
129 | else | |
130 | #endif | |
131 | memcpy (rvalue, smst_buffer, rsize); | |
132 | } | |
133 | } | |
134 | ||
135 | void | |
136 | ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue) | |
137 | { | |
138 | ffi_call_int (cif, fn, rvalue, avalue, NULL); | |
139 | } | |
140 | ||
141 | void | |
142 | ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue, | |
143 | void *closure) | |
144 | { | |
145 | ffi_call_int (cif, fn, rvalue, avalue, closure); | |
146 | } | |
147 | ||
148 | ffi_status | |
149 | ffi_prep_closure_loc (ffi_closure *closure, | |
150 | ffi_cif *cif, | |
151 | void (*fun) (ffi_cif *, void *, void **, void *), | |
152 | void *user_data, | |
153 | void *codeloc) | |
154 | { | |
155 | #ifdef POWERPC64 | |
156 | return ffi_prep_closure_loc_linux64 (closure, cif, fun, user_data, codeloc); | |
157 | #else | |
158 | return ffi_prep_closure_loc_sysv (closure, cif, fun, user_data, codeloc); | |
159 | #endif | |
160 | } | |
161 | ||
162 | ffi_status | |
163 | ffi_prep_go_closure (ffi_go_closure *closure, | |
164 | ffi_cif *cif, | |
165 | void (*fun) (ffi_cif *, void *, void **, void *)) | |
166 | { | |
167 | #ifdef POWERPC64 | |
168 | closure->tramp = ffi_go_closure_linux64; | |
169 | #else | |
170 | closure->tramp = ffi_go_closure_sysv; | |
171 | #endif | |
172 | closure->cif = cif; | |
173 | closure->fun = fun; | |
174 | return FFI_OK; | |
175 | } |