]>
Commit | Line | Data |
---|---|---|
63e5e3e0 | 1 | /* ----------------------------------------------------------------------- |
18fa3240 | 2 | ffi.c - Copyright (c) 1998, 2001, 2007 Red Hat, Inc. |
63e5e3e0 AG |
3 | |
4 | Alpha Foreign Function Interface | |
5 | ||
63e5e3e0 AG |
6 | Permission is hereby granted, free of charge, to any person obtaining |
7 | a copy of this software and associated documentation files (the | |
8 | ``Software''), to deal in the Software without restriction, including | |
9 | without limitation the rights to use, copy, modify, merge, publish, | |
10 | distribute, sublicense, and/or sell copies of the Software, and to | |
11 | permit persons to whom the Software is furnished to do so, subject to | |
12 | the following conditions: | |
13 | ||
14 | The above copyright notice and this permission notice shall be included | |
15 | in all copies or substantial portions of the Software. | |
16 | ||
17 | THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS | |
18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
20 | IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
23 | OTHER DEALINGS IN THE SOFTWARE. | |
24 | ----------------------------------------------------------------------- */ | |
25 | ||
26 | #include <ffi.h> | |
27 | #include <ffi_common.h> | |
28 | ||
29 | #include <stdlib.h> | |
30 | ||
29fe0479 RH |
31 | extern void ffi_call_osf(void *, unsigned long, unsigned, void *, void (*)()); |
32 | extern void ffi_closure_osf(void); | |
63e5e3e0 | 33 | |
29fe0479 RH |
34 | |
35 | ffi_status | |
36 | ffi_prep_cif_machdep(ffi_cif *cif) | |
63e5e3e0 | 37 | { |
29fe0479 RH |
38 | /* Adjust cif->bytes to represent a minimum 6 words for the temporary |
39 | register argument loading area. */ | |
1450eb7a AT |
40 | if (cif->bytes < 6*FFI_SIZEOF_ARG) |
41 | cif->bytes = 6*FFI_SIZEOF_ARG; | |
29fe0479 RH |
42 | |
43 | /* Set the return type flag */ | |
44 | switch (cif->rtype->type) | |
63e5e3e0 | 45 | { |
29fe0479 RH |
46 | case FFI_TYPE_STRUCT: |
47 | case FFI_TYPE_FLOAT: | |
48 | case FFI_TYPE_DOUBLE: | |
49 | cif->flags = cif->rtype->type; | |
50 | break; | |
51 | ||
52 | default: | |
53 | cif->flags = FFI_TYPE_INT; | |
54 | break; | |
63e5e3e0 | 55 | } |
29fe0479 RH |
56 | |
57 | return FFI_OK; | |
58 | } | |
59 | ||
60 | void | |
61 | ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue) | |
62 | { | |
63 | unsigned long *stack, *argp; | |
64 | long i, avn; | |
65 | ffi_type **arg_types; | |
66 | ||
67 | FFI_ASSERT (cif->abi == FFI_OSF); | |
68 | ||
69 | /* If the return value is a struct and we don't have a return | |
70 | value address then we need to make one. */ | |
3f67ba6e | 71 | if (rvalue == NULL && cif->flags == FFI_TYPE_STRUCT) |
29fe0479 RH |
72 | rvalue = alloca(cif->rtype->size); |
73 | ||
74 | /* Allocate the space for the arguments, plus 4 words of temp | |
75 | space for ffi_call_osf. */ | |
1450eb7a | 76 | argp = stack = alloca(cif->bytes + 4*FFI_SIZEOF_ARG); |
29fe0479 RH |
77 | |
78 | if (cif->flags == FFI_TYPE_STRUCT) | |
79 | *(void **) argp++ = rvalue; | |
63e5e3e0 AG |
80 | |
81 | i = 0; | |
29fe0479 RH |
82 | avn = cif->nargs; |
83 | arg_types = cif->arg_types; | |
84 | ||
63e5e3e0 AG |
85 | while (i < avn) |
86 | { | |
29fe0479 | 87 | switch ((*arg_types)->type) |
63e5e3e0 AG |
88 | { |
89 | case FFI_TYPE_SINT8: | |
29fe0479 | 90 | *(SINT64 *) argp = *(SINT8 *)(* avalue); |
63e5e3e0 AG |
91 | break; |
92 | ||
93 | case FFI_TYPE_UINT8: | |
29fe0479 | 94 | *(SINT64 *) argp = *(UINT8 *)(* avalue); |
63e5e3e0 AG |
95 | break; |
96 | ||
97 | case FFI_TYPE_SINT16: | |
29fe0479 | 98 | *(SINT64 *) argp = *(SINT16 *)(* avalue); |
63e5e3e0 AG |
99 | break; |
100 | ||
101 | case FFI_TYPE_UINT16: | |
29fe0479 | 102 | *(SINT64 *) argp = *(UINT16 *)(* avalue); |
63e5e3e0 AG |
103 | break; |
104 | ||
105 | case FFI_TYPE_SINT32: | |
63e5e3e0 | 106 | case FFI_TYPE_UINT32: |
29fe0479 RH |
107 | /* Note that unsigned 32-bit quantities are sign extended. */ |
108 | *(SINT64 *) argp = *(SINT32 *)(* avalue); | |
63e5e3e0 | 109 | break; |
29fe0479 | 110 | |
63e5e3e0 AG |
111 | case FFI_TYPE_SINT64: |
112 | case FFI_TYPE_UINT64: | |
113 | case FFI_TYPE_POINTER: | |
29fe0479 | 114 | *(UINT64 *) argp = *(UINT64 *)(* avalue); |
63e5e3e0 AG |
115 | break; |
116 | ||
117 | case FFI_TYPE_FLOAT: | |
29fe0479 | 118 | if (argp - stack < 6) |
63e5e3e0 AG |
119 | { |
120 | /* Note the conversion -- all the fp regs are loaded as | |
121 | doubles. The in-register format is the same. */ | |
29fe0479 | 122 | *(double *) argp = *(float *)(* avalue); |
63e5e3e0 AG |
123 | } |
124 | else | |
29fe0479 | 125 | *(float *) argp = *(float *)(* avalue); |
63e5e3e0 AG |
126 | break; |
127 | ||
128 | case FFI_TYPE_DOUBLE: | |
29fe0479 | 129 | *(double *) argp = *(double *)(* avalue); |
63e5e3e0 AG |
130 | break; |
131 | ||
132 | case FFI_TYPE_STRUCT: | |
29fe0479 | 133 | memcpy(argp, *avalue, (*arg_types)->size); |
63e5e3e0 AG |
134 | break; |
135 | ||
136 | default: | |
137 | FFI_ASSERT(0); | |
138 | } | |
139 | ||
1450eb7a | 140 | argp += ALIGN((*arg_types)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; |
29fe0479 | 141 | i++, arg_types++, avalue++; |
63e5e3e0 | 142 | } |
29fe0479 RH |
143 | |
144 | ffi_call_osf(stack, cif->bytes, cif->flags, rvalue, fn); | |
63e5e3e0 AG |
145 | } |
146 | ||
29fe0479 | 147 | |
63e5e3e0 | 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) | |
63e5e3e0 | 154 | { |
29fe0479 | 155 | unsigned int *tramp; |
63e5e3e0 | 156 | |
29fe0479 | 157 | FFI_ASSERT (cif->abi == FFI_OSF); |
63e5e3e0 | 158 | |
29fe0479 RH |
159 | tramp = (unsigned int *) &closure->tramp[0]; |
160 | tramp[0] = 0x47fb0401; /* mov $27,$1 */ | |
161 | tramp[1] = 0xa77b0010; /* ldq $27,16($27) */ | |
162 | tramp[2] = 0x6bfb0000; /* jmp $31,($27),0 */ | |
163 | tramp[3] = 0x47ff041f; /* nop */ | |
164 | *(void **) &tramp[4] = ffi_closure_osf; | |
63e5e3e0 | 165 | |
29fe0479 RH |
166 | closure->cif = cif; |
167 | closure->fun = fun; | |
168 | closure->user_data = user_data; | |
63e5e3e0 | 169 | |
92a0e6c6 RO |
170 | /* Flush the Icache. |
171 | ||
172 | Tru64 UNIX as doesn't understand the imb mnemonic, so use call_pal | |
173 | instead, since both Compaq as and gas can handle it. | |
174 | ||
175 | 0x86 is PAL_imb in Tru64 UNIX <alpha/pal.h>. */ | |
176 | asm volatile ("call_pal 0x86" : : : "memory"); | |
63e5e3e0 | 177 | |
63e5e3e0 AG |
178 | return FFI_OK; |
179 | } | |
180 | ||
29fe0479 RH |
181 | int |
182 | ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp) | |
63e5e3e0 | 183 | { |
29fe0479 RH |
184 | ffi_cif *cif; |
185 | void **avalue; | |
186 | ffi_type **arg_types; | |
187 | long i, avn, argn; | |
63e5e3e0 | 188 | |
29fe0479 RH |
189 | cif = closure->cif; |
190 | avalue = alloca(cif->nargs * sizeof(void *)); | |
191 | ||
192 | argn = 0; | |
193 | ||
194 | /* Copy the caller's structure return address to that the closure | |
195 | returns the data directly to the caller. */ | |
196 | if (cif->flags == FFI_TYPE_STRUCT) | |
197 | { | |
198 | rvalue = (void *) argp[0]; | |
199 | argn = 1; | |
200 | } | |
201 | ||
202 | i = 0; | |
203 | avn = cif->nargs; | |
204 | arg_types = cif->arg_types; | |
63e5e3e0 | 205 | |
29fe0479 RH |
206 | /* Grab the addresses of the arguments from the stack frame. */ |
207 | while (i < avn) | |
63e5e3e0 | 208 | { |
3f67ba6e | 209 | switch (arg_types[i]->type) |
29fe0479 RH |
210 | { |
211 | case FFI_TYPE_SINT8: | |
212 | case FFI_TYPE_UINT8: | |
213 | case FFI_TYPE_SINT16: | |
214 | case FFI_TYPE_UINT16: | |
215 | case FFI_TYPE_SINT32: | |
216 | case FFI_TYPE_UINT32: | |
217 | case FFI_TYPE_SINT64: | |
218 | case FFI_TYPE_UINT64: | |
219 | case FFI_TYPE_POINTER: | |
220 | case FFI_TYPE_STRUCT: | |
3f67ba6e | 221 | avalue[i] = &argp[argn]; |
29fe0479 | 222 | break; |
63e5e3e0 | 223 | |
29fe0479 RH |
224 | case FFI_TYPE_FLOAT: |
225 | if (argn < 6) | |
226 | { | |
227 | /* Floats coming from registers need conversion from double | |
228 | back to float format. */ | |
229 | *(float *)&argp[argn - 6] = *(double *)&argp[argn - 6]; | |
3f67ba6e | 230 | avalue[i] = &argp[argn - 6]; |
29fe0479 RH |
231 | } |
232 | else | |
3f67ba6e | 233 | avalue[i] = &argp[argn]; |
29fe0479 RH |
234 | break; |
235 | ||
236 | case FFI_TYPE_DOUBLE: | |
3f67ba6e | 237 | avalue[i] = &argp[argn - (argn < 6 ? 6 : 0)]; |
29fe0479 RH |
238 | break; |
239 | ||
240 | default: | |
241 | FFI_ASSERT(0); | |
242 | } | |
243 | ||
1450eb7a | 244 | argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; |
3f67ba6e | 245 | i++; |
63e5e3e0 | 246 | } |
29fe0479 RH |
247 | |
248 | /* Invoke the closure. */ | |
249 | (closure->fun) (cif, rvalue, avalue, closure->user_data); | |
250 | ||
3f67ba6e RH |
251 | /* Tell ffi_closure_osf how to perform return type promotions. */ |
252 | return cif->rtype->type; | |
63e5e3e0 | 253 | } |