]>
Commit | Line | Data |
---|---|---|
63e5e3e0 | 1 | /* ----------------------------------------------------------------------- |
e73d2479 AM |
2 | ffi.c - Copyright (C) 2013 IBM |
3 | Copyright (C) 2011 Anthony Green | |
34fa7690 AG |
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 | |
63e5e3e0 | 8 | |
16070e45 | 9 | PowerPC Foreign Function Interface |
63e5e3e0 AG |
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 | ||
e73d2479 AM |
31 | #include "ffi.h" |
32 | #include "ffi_common.h" | |
33 | #include "ffi_powerpc.h" | |
e9b84181 | 34 | |
e73d2479 AM |
35 | #if HAVE_LONG_DOUBLE_VARIANT |
36 | /* Adjust ffi_type_longdouble. */ | |
cd4241aa | 37 | void FFI_HIDDEN |
e73d2479 | 38 | ffi_prep_types (ffi_abi abi) |
e9b84181 | 39 | { |
e73d2479 AM |
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 | |
e9b84181 | 47 | } |
e73d2479 | 48 | #endif |
e9b84181 | 49 | |
63e5e3e0 | 50 | /* Perform machine dependent cif processing */ |
e73d2479 AM |
51 | ffi_status FFI_HIDDEN |
52 | ffi_prep_cif_machdep (ffi_cif *cif) | |
63e5e3e0 | 53 | { |
e73d2479 AM |
54 | #ifdef POWERPC64 |
55 | return ffi_prep_cif_linux64 (cif); | |
3521ba8b | 56 | #else |
e73d2479 | 57 | return ffi_prep_cif_sysv (cif); |
3521ba8b | 58 | #endif |
3521ba8b AM |
59 | } |
60 | ||
e73d2479 | 61 | ffi_status FFI_HIDDEN |
3521ba8b | 62 | ffi_prep_cif_machdep_var (ffi_cif *cif, |
e73d2479 | 63 | unsigned int nfixedargs MAYBE_UNUSED, |
3521ba8b AM |
64 | unsigned int ntotalargs MAYBE_UNUSED) |
65 | { | |
e73d2479 AM |
66 | #ifdef POWERPC64 |
67 | return ffi_prep_cif_linux64_var (cif, nfixedargs, ntotalargs); | |
68 | #else | |
69 | return ffi_prep_cif_sysv (cif); | |
3521ba8b | 70 | #endif |
3521ba8b AM |
71 | } |
72 | ||
b1760f7f RH |
73 | static void |
74 | ffi_call_int (ffi_cif *cif, | |
75 | void (*fn) (void), | |
76 | void *rvalue, | |
77 | void **avalue, | |
78 | void *closure) | |
63e5e3e0 | 79 | { |
e73d2479 AM |
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, | |
92456a4e L |
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]; | |
63e5e3e0 AG |
91 | extended_cif ecif; |
92 | ||
93 | ecif.cif = cif; | |
94 | ecif.avalue = avalue; | |
16070e45 | 95 | |
34fa7690 | 96 | ecif.rvalue = rvalue; |
3521ba8b AM |
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); | |
16070e45 | 103 | |
e73d2479 | 104 | #ifdef POWERPC64 |
b1760f7f RH |
105 | ffi_call_LINUX64 (&ecif, fn, ecif.rvalue, cif->flags, closure, |
106 | -(long) cif->bytes); | |
e9b84181 | 107 | #else |
b1760f7f | 108 | ffi_call_SYSV (&ecif, fn, ecif.rvalue, cif->flags, closure, -cif->bytes); |
e9b84181 | 109 | #endif |
34fa7690 AG |
110 | |
111 | /* Check for a bounce-buffered return value */ | |
112 | if (rvalue && ecif.rvalue == smst_buffer) | |
3521ba8b AM |
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. */ | |
e73d2479 AM |
118 | # ifndef POWERPC64 |
119 | if (rsize <= 4) | |
3521ba8b | 120 | memcpy (rvalue, (char *) smst_buffer + 4 - rsize, rsize); |
3521ba8b | 121 | else |
e73d2479 AM |
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 | |
92456a4e L |
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) | |
e73d2479 AM |
128 | memcpy (rvalue, (char *) smst_buffer + 8 - rsize, rsize); |
129 | else | |
3521ba8b | 130 | #endif |
e73d2479 | 131 | memcpy (rvalue, smst_buffer, rsize); |
3521ba8b | 132 | } |
63e5e3e0 | 133 | } |
cc4c8975 | 134 | |
b1760f7f RH |
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 | } | |
cc4c8975 | 147 | |
cc4c8975 | 148 | ffi_status |
18fa3240 AO |
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) | |
cc4c8975 | 154 | { |
e9b84181 | 155 | #ifdef POWERPC64 |
e73d2479 | 156 | return ffi_prep_closure_loc_linux64 (closure, cif, fun, user_data, codeloc); |
e9b84181 | 157 | #else |
e73d2479 | 158 | return ffi_prep_closure_loc_sysv (closure, cif, fun, user_data, codeloc); |
34fa7690 | 159 | #endif |
e9b84181 | 160 | } |
b1760f7f RH |
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 | } |