1 | /* -----------------------------------------------------------------------
|
---|
2 | ffi.c - Copyright (c) 1998, 2001 Cygnus Solutions
|
---|
3 |
|
---|
4 | Alpha Foreign Function Interface
|
---|
5 |
|
---|
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 |
|
---|
31 | extern void ffi_call_osf(void *, unsigned long, unsigned, void *, void (*)());
|
---|
32 | extern void ffi_closure_osf(void);
|
---|
33 |
|
---|
34 |
|
---|
35 | ffi_status
|
---|
36 | ffi_prep_cif_machdep(ffi_cif *cif)
|
---|
37 | {
|
---|
38 | /* Adjust cif->bytes to represent a minimum 6 words for the temporary
|
---|
39 | register argument loading area. */
|
---|
40 | if (cif->bytes < 6*SIZEOF_ARG)
|
---|
41 | cif->bytes = 6*SIZEOF_ARG;
|
---|
42 |
|
---|
43 | /* Set the return type flag */
|
---|
44 | switch (cif->rtype->type)
|
---|
45 | {
|
---|
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;
|
---|
55 | }
|
---|
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. */
|
---|
71 | if (rvalue == NULL && cif->flags == FFI_TYPE_STRUCT)
|
---|
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. */
|
---|
76 | argp = stack = alloca(cif->bytes + 4*SIZEOF_ARG);
|
---|
77 |
|
---|
78 | if (cif->flags == FFI_TYPE_STRUCT)
|
---|
79 | *(void **) argp++ = rvalue;
|
---|
80 |
|
---|
81 | i = 0;
|
---|
82 | avn = cif->nargs;
|
---|
83 | arg_types = cif->arg_types;
|
---|
84 |
|
---|
85 | while (i < avn)
|
---|
86 | {
|
---|
87 | switch ((*arg_types)->type)
|
---|
88 | {
|
---|
89 | case FFI_TYPE_SINT8:
|
---|
90 | *(SINT64 *) argp = *(SINT8 *)(* avalue);
|
---|
91 | break;
|
---|
92 |
|
---|
93 | case FFI_TYPE_UINT8:
|
---|
94 | *(SINT64 *) argp = *(UINT8 *)(* avalue);
|
---|
95 | break;
|
---|
96 |
|
---|
97 | case FFI_TYPE_SINT16:
|
---|
98 | *(SINT64 *) argp = *(SINT16 *)(* avalue);
|
---|
99 | break;
|
---|
100 |
|
---|
101 | case FFI_TYPE_UINT16:
|
---|
102 | *(SINT64 *) argp = *(UINT16 *)(* avalue);
|
---|
103 | break;
|
---|
104 |
|
---|
105 | case FFI_TYPE_SINT32:
|
---|
106 | case FFI_TYPE_UINT32:
|
---|
107 | /* Note that unsigned 32-bit quantities are sign extended. */
|
---|
108 | *(SINT64 *) argp = *(SINT32 *)(* avalue);
|
---|
109 | break;
|
---|
110 |
|
---|
111 | case FFI_TYPE_SINT64:
|
---|
112 | case FFI_TYPE_UINT64:
|
---|
113 | case FFI_TYPE_POINTER:
|
---|
114 | *(UINT64 *) argp = *(UINT64 *)(* avalue);
|
---|
115 | break;
|
---|
116 |
|
---|
117 | case FFI_TYPE_FLOAT:
|
---|
118 | if (argp - stack < 6)
|
---|
119 | {
|
---|
120 | /* Note the conversion -- all the fp regs are loaded as
|
---|
121 | doubles. The in-register format is the same. */
|
---|
122 | *(double *) argp = *(float *)(* avalue);
|
---|
123 | }
|
---|
124 | else
|
---|
125 | *(float *) argp = *(float *)(* avalue);
|
---|
126 | break;
|
---|
127 |
|
---|
128 | case FFI_TYPE_DOUBLE:
|
---|
129 | *(double *) argp = *(double *)(* avalue);
|
---|
130 | break;
|
---|
131 |
|
---|
132 | case FFI_TYPE_STRUCT:
|
---|
133 | memcpy(argp, *avalue, (*arg_types)->size);
|
---|
134 | break;
|
---|
135 |
|
---|
136 | default:
|
---|
137 | FFI_ASSERT(0);
|
---|
138 | }
|
---|
139 |
|
---|
140 | argp += ALIGN((*arg_types)->size, SIZEOF_ARG) / SIZEOF_ARG;
|
---|
141 | i++, arg_types++, avalue++;
|
---|
142 | }
|
---|
143 |
|
---|
144 | ffi_call_osf(stack, cif->bytes, cif->flags, rvalue, fn);
|
---|
145 | }
|
---|
146 |
|
---|
147 |
|
---|
148 | ffi_status
|
---|
149 | ffi_prep_closure (ffi_closure* closure,
|
---|
150 | ffi_cif* cif,
|
---|
151 | void (*fun)(ffi_cif*, void*, void**, void*),
|
---|
152 | void *user_data)
|
---|
153 | {
|
---|
154 | unsigned int *tramp;
|
---|
155 |
|
---|
156 | FFI_ASSERT (cif->abi == FFI_OSF);
|
---|
157 |
|
---|
158 | tramp = (unsigned int *) &closure->tramp[0];
|
---|
159 | tramp[0] = 0x47fb0401; /* mov $27,$1 */
|
---|
160 | tramp[1] = 0xa77b0010; /* ldq $27,16($27) */
|
---|
161 | tramp[2] = 0x6bfb0000; /* jmp $31,($27),0 */
|
---|
162 | tramp[3] = 0x47ff041f; /* nop */
|
---|
163 | *(void **) &tramp[4] = ffi_closure_osf;
|
---|
164 |
|
---|
165 | closure->cif = cif;
|
---|
166 | closure->fun = fun;
|
---|
167 | closure->user_data = user_data;
|
---|
168 |
|
---|
169 | /* Flush the Icache.
|
---|
170 |
|
---|
171 | Tru64 UNIX as doesn't understand the imb mnemonic, so use call_pal
|
---|
172 | instead, since both Compaq as and gas can handle it.
|
---|
173 |
|
---|
174 | 0x86 is PAL_imb in Tru64 UNIX <alpha/pal.h>. */
|
---|
175 | asm volatile ("call_pal 0x86" : : : "memory");
|
---|
176 |
|
---|
177 | return FFI_OK;
|
---|
178 | }
|
---|
179 |
|
---|
180 | int
|
---|
181 | ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
|
---|
182 | {
|
---|
183 | ffi_cif *cif;
|
---|
184 | void **avalue;
|
---|
185 | ffi_type **arg_types;
|
---|
186 | long i, avn, argn;
|
---|
187 |
|
---|
188 | cif = closure->cif;
|
---|
189 | avalue = alloca(cif->nargs * sizeof(void *));
|
---|
190 |
|
---|
191 | argn = 0;
|
---|
192 |
|
---|
193 | /* Copy the caller's structure return address to that the closure
|
---|
194 | returns the data directly to the caller. */
|
---|
195 | if (cif->flags == FFI_TYPE_STRUCT)
|
---|
196 | {
|
---|
197 | rvalue = (void *) argp[0];
|
---|
198 | argn = 1;
|
---|
199 | }
|
---|
200 |
|
---|
201 | i = 0;
|
---|
202 | avn = cif->nargs;
|
---|
203 | arg_types = cif->arg_types;
|
---|
204 |
|
---|
205 | /* Grab the addresses of the arguments from the stack frame. */
|
---|
206 | while (i < avn)
|
---|
207 | {
|
---|
208 | switch (arg_types[i]->type)
|
---|
209 | {
|
---|
210 | case FFI_TYPE_SINT8:
|
---|
211 | case FFI_TYPE_UINT8:
|
---|
212 | case FFI_TYPE_SINT16:
|
---|
213 | case FFI_TYPE_UINT16:
|
---|
214 | case FFI_TYPE_SINT32:
|
---|
215 | case FFI_TYPE_UINT32:
|
---|
216 | case FFI_TYPE_SINT64:
|
---|
217 | case FFI_TYPE_UINT64:
|
---|
218 | case FFI_TYPE_POINTER:
|
---|
219 | case FFI_TYPE_STRUCT:
|
---|
220 | avalue[i] = &argp[argn];
|
---|
221 | break;
|
---|
222 |
|
---|
223 | case FFI_TYPE_FLOAT:
|
---|
224 | if (argn < 6)
|
---|
225 | {
|
---|
226 | /* Floats coming from registers need conversion from double
|
---|
227 | back to float format. */
|
---|
228 | *(float *)&argp[argn - 6] = *(double *)&argp[argn - 6];
|
---|
229 | avalue[i] = &argp[argn - 6];
|
---|
230 | }
|
---|
231 | else
|
---|
232 | avalue[i] = &argp[argn];
|
---|
233 | break;
|
---|
234 |
|
---|
235 | case FFI_TYPE_DOUBLE:
|
---|
236 | avalue[i] = &argp[argn - (argn < 6 ? 6 : 0)];
|
---|
237 | break;
|
---|
238 |
|
---|
239 | default:
|
---|
240 | FFI_ASSERT(0);
|
---|
241 | }
|
---|
242 |
|
---|
243 | argn += ALIGN(arg_types[i]->size, SIZEOF_ARG) / SIZEOF_ARG;
|
---|
244 | i++;
|
---|
245 | }
|
---|
246 |
|
---|
247 | /* Invoke the closure. */
|
---|
248 | (closure->fun) (cif, rvalue, avalue, closure->user_data);
|
---|
249 |
|
---|
250 | /* Tell ffi_closure_osf how to perform return type promotions. */
|
---|
251 | return cif->rtype->type;
|
---|
252 | }
|
---|