/src/glib-2.80.0/subprojects/libffi/src/x86/ffi64.c
Line | Count | Source |
1 | | /* ----------------------------------------------------------------------- |
2 | | ffi64.c - Copyright (c) 2013 The Written Word, Inc. |
3 | | Copyright (c) 2011 Anthony Green |
4 | | Copyright (c) 2008, 2010 Red Hat, Inc. |
5 | | Copyright (c) 2002, 2007 Bo Thorsen <bo@suse.de> |
6 | | |
7 | | x86-64 Foreign Function Interface |
8 | | |
9 | | Permission is hereby granted, free of charge, to any person obtaining |
10 | | a copy of this software and associated documentation files (the |
11 | | ``Software''), to deal in the Software without restriction, including |
12 | | without limitation the rights to use, copy, modify, merge, publish, |
13 | | distribute, sublicense, and/or sell copies of the Software, and to |
14 | | permit persons to whom the Software is furnished to do so, subject to |
15 | | the following conditions: |
16 | | |
17 | | The above copyright notice and this permission notice shall be included |
18 | | in all copies or substantial portions of the Software. |
19 | | |
20 | | THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, |
21 | | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
22 | | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
23 | | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
24 | | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
25 | | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
26 | | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
27 | | DEALINGS IN THE SOFTWARE. |
28 | | ----------------------------------------------------------------------- */ |
29 | | |
30 | | #include <ffi.h> |
31 | | #include <ffi_common.h> |
32 | | |
33 | | #include <stdlib.h> |
34 | | #include <stdarg.h> |
35 | | #include <stdint.h> |
36 | | #include "internal64.h" |
37 | | |
38 | | #ifdef __x86_64__ |
39 | | |
40 | 0 | #define MAX_GPR_REGS 6 |
41 | 0 | #define MAX_SSE_REGS 8 |
42 | | |
43 | | #if defined(__INTEL_COMPILER) |
44 | | #include "xmmintrin.h" |
45 | | #define UINT128 __m128 |
46 | | #else |
47 | | #if defined(__SUNPRO_C) |
48 | | #include <sunmedia_types.h> |
49 | | #define UINT128 __m128i |
50 | | #else |
51 | | #define UINT128 __int128_t |
52 | | #endif |
53 | | #endif |
54 | | |
55 | | union big_int_union |
56 | | { |
57 | | UINT32 i32; |
58 | | UINT64 i64; |
59 | | UINT128 i128; |
60 | | }; |
61 | | |
62 | | struct register_args |
63 | | { |
64 | | /* Registers for argument passing. */ |
65 | | UINT64 gpr[MAX_GPR_REGS]; |
66 | | union big_int_union sse[MAX_SSE_REGS]; |
67 | | UINT64 rax; /* ssecount */ |
68 | | UINT64 r10; /* static chain */ |
69 | | }; |
70 | | |
71 | | extern void ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags, |
72 | | void *raddr, void (*fnaddr)(void)) FFI_HIDDEN; |
73 | | |
74 | | /* All reference to register classes here is identical to the code in |
75 | | gcc/config/i386/i386.c. Do *not* change one without the other. */ |
76 | | |
77 | | /* Register class used for passing given 64bit part of the argument. |
78 | | These represent classes as documented by the PS ABI, with the |
79 | | exception of SSESF, SSEDF classes, that are basically SSE class, |
80 | | just gcc will use SF or DFmode move instead of DImode to avoid |
81 | | reformatting penalties. |
82 | | |
83 | | Similary we play games with INTEGERSI_CLASS to use cheaper SImode moves |
84 | | whenever possible (upper half does contain padding). */ |
85 | | enum x86_64_reg_class |
86 | | { |
87 | | X86_64_NO_CLASS, |
88 | | X86_64_INTEGER_CLASS, |
89 | | X86_64_INTEGERSI_CLASS, |
90 | | X86_64_SSE_CLASS, |
91 | | X86_64_SSESF_CLASS, |
92 | | X86_64_SSEDF_CLASS, |
93 | | X86_64_SSEUP_CLASS, |
94 | | X86_64_X87_CLASS, |
95 | | X86_64_X87UP_CLASS, |
96 | | X86_64_COMPLEX_X87_CLASS, |
97 | | X86_64_MEMORY_CLASS |
98 | | }; |
99 | | |
100 | | #define MAX_CLASSES 4 |
101 | | |
102 | 0 | #define SSE_CLASS_P(X) ((X) >= X86_64_SSE_CLASS && X <= X86_64_SSEUP_CLASS) |
103 | | |
104 | | /* x86-64 register passing implementation. See x86-64 ABI for details. Goal |
105 | | of this code is to classify each 8bytes of incoming argument by the register |
106 | | class and assign registers accordingly. */ |
107 | | |
108 | | /* Return the union class of CLASS1 and CLASS2. |
109 | | See the x86-64 PS ABI for details. */ |
110 | | |
111 | | static enum x86_64_reg_class |
112 | | merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2) |
113 | 0 | { |
114 | | /* Rule #1: If both classes are equal, this is the resulting class. */ |
115 | 0 | if (class1 == class2) |
116 | 0 | return class1; |
117 | | |
118 | | /* Rule #2: If one of the classes is NO_CLASS, the resulting class is |
119 | | the other class. */ |
120 | 0 | if (class1 == X86_64_NO_CLASS) |
121 | 0 | return class2; |
122 | 0 | if (class2 == X86_64_NO_CLASS) |
123 | 0 | return class1; |
124 | | |
125 | | /* Rule #3: If one of the classes is MEMORY, the result is MEMORY. */ |
126 | 0 | if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS) |
127 | 0 | return X86_64_MEMORY_CLASS; |
128 | | |
129 | | /* Rule #4: If one of the classes is INTEGER, the result is INTEGER. */ |
130 | 0 | if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS) |
131 | 0 | || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS)) |
132 | 0 | return X86_64_INTEGERSI_CLASS; |
133 | 0 | if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS |
134 | 0 | || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS) |
135 | 0 | return X86_64_INTEGER_CLASS; |
136 | | |
137 | | /* Rule #5: If one of the classes is X87, X87UP, or COMPLEX_X87 class, |
138 | | MEMORY is used. */ |
139 | 0 | if (class1 == X86_64_X87_CLASS |
140 | 0 | || class1 == X86_64_X87UP_CLASS |
141 | 0 | || class1 == X86_64_COMPLEX_X87_CLASS |
142 | 0 | || class2 == X86_64_X87_CLASS |
143 | 0 | || class2 == X86_64_X87UP_CLASS |
144 | 0 | || class2 == X86_64_COMPLEX_X87_CLASS) |
145 | 0 | return X86_64_MEMORY_CLASS; |
146 | | |
147 | | /* Rule #6: Otherwise class SSE is used. */ |
148 | 0 | return X86_64_SSE_CLASS; |
149 | 0 | } |
150 | | |
151 | | /* Classify the argument of type TYPE and mode MODE. |
152 | | CLASSES will be filled by the register class used to pass each word |
153 | | of the operand. The number of words is returned. In case the parameter |
154 | | should be passed in memory, 0 is returned. As a special case for zero |
155 | | sized containers, classes[0] will be NO_CLASS and 1 is returned. |
156 | | |
157 | | See the x86-64 PS ABI for details. |
158 | | */ |
159 | | static size_t |
160 | | classify_argument (ffi_type *type, enum x86_64_reg_class classes[], |
161 | | size_t byte_offset) |
162 | 0 | { |
163 | 0 | switch (type->type) |
164 | 0 | { |
165 | 0 | case FFI_TYPE_UINT8: |
166 | 0 | case FFI_TYPE_SINT8: |
167 | 0 | case FFI_TYPE_UINT16: |
168 | 0 | case FFI_TYPE_SINT16: |
169 | 0 | case FFI_TYPE_UINT32: |
170 | 0 | case FFI_TYPE_SINT32: |
171 | 0 | case FFI_TYPE_UINT64: |
172 | 0 | case FFI_TYPE_SINT64: |
173 | 0 | case FFI_TYPE_POINTER: |
174 | 0 | do_integer: |
175 | 0 | { |
176 | 0 | size_t size = byte_offset + type->size; |
177 | |
|
178 | 0 | if (size <= 4) |
179 | 0 | { |
180 | 0 | classes[0] = X86_64_INTEGERSI_CLASS; |
181 | 0 | return 1; |
182 | 0 | } |
183 | 0 | else if (size <= 8) |
184 | 0 | { |
185 | 0 | classes[0] = X86_64_INTEGER_CLASS; |
186 | 0 | return 1; |
187 | 0 | } |
188 | 0 | else if (size <= 12) |
189 | 0 | { |
190 | 0 | classes[0] = X86_64_INTEGER_CLASS; |
191 | 0 | classes[1] = X86_64_INTEGERSI_CLASS; |
192 | 0 | return 2; |
193 | 0 | } |
194 | 0 | else if (size <= 16) |
195 | 0 | { |
196 | 0 | classes[0] = classes[1] = X86_64_INTEGER_CLASS; |
197 | 0 | return 2; |
198 | 0 | } |
199 | 0 | else |
200 | 0 | FFI_ASSERT (0); |
201 | 0 | } |
202 | 0 | case FFI_TYPE_FLOAT: |
203 | 0 | if (!(byte_offset % 8)) |
204 | 0 | classes[0] = X86_64_SSESF_CLASS; |
205 | 0 | else |
206 | 0 | classes[0] = X86_64_SSE_CLASS; |
207 | 0 | return 1; |
208 | 0 | case FFI_TYPE_DOUBLE: |
209 | 0 | classes[0] = X86_64_SSEDF_CLASS; |
210 | 0 | return 1; |
211 | 0 | #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE |
212 | 0 | case FFI_TYPE_LONGDOUBLE: |
213 | 0 | classes[0] = X86_64_X87_CLASS; |
214 | 0 | classes[1] = X86_64_X87UP_CLASS; |
215 | 0 | return 2; |
216 | 0 | #endif |
217 | 0 | case FFI_TYPE_STRUCT: |
218 | 0 | { |
219 | 0 | const size_t UNITS_PER_WORD = 8; |
220 | 0 | size_t words = (type->size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; |
221 | 0 | ffi_type **ptr; |
222 | 0 | unsigned int i; |
223 | 0 | enum x86_64_reg_class subclasses[MAX_CLASSES]; |
224 | | |
225 | | /* If the struct is larger than 32 bytes, pass it on the stack. */ |
226 | 0 | if (type->size > 32) |
227 | 0 | return 0; |
228 | | |
229 | 0 | for (i = 0; i < words; i++) |
230 | 0 | classes[i] = X86_64_NO_CLASS; |
231 | | |
232 | | /* Zero sized arrays or structures are NO_CLASS. We return 0 to |
233 | | signalize memory class, so handle it as special case. */ |
234 | 0 | if (!words) |
235 | 0 | { |
236 | 0 | case FFI_TYPE_VOID: |
237 | 0 | classes[0] = X86_64_NO_CLASS; |
238 | 0 | return 1; |
239 | 0 | } |
240 | | |
241 | | /* Merge the fields of structure. */ |
242 | 0 | for (ptr = type->elements; *ptr != NULL; ptr++) |
243 | 0 | { |
244 | 0 | size_t num; |
245 | |
|
246 | 0 | byte_offset = FFI_ALIGN (byte_offset, (*ptr)->alignment); |
247 | |
|
248 | 0 | num = classify_argument (*ptr, subclasses, byte_offset % 8); |
249 | 0 | if (num == 0) |
250 | 0 | return 0; |
251 | 0 | for (i = 0; i < num; i++) |
252 | 0 | { |
253 | 0 | size_t pos = byte_offset / 8; |
254 | 0 | classes[i + pos] = |
255 | 0 | merge_classes (subclasses[i], classes[i + pos]); |
256 | 0 | } |
257 | |
|
258 | 0 | byte_offset += (*ptr)->size; |
259 | 0 | } |
260 | | |
261 | 0 | if (words > 2) |
262 | 0 | { |
263 | | /* When size > 16 bytes, if the first one isn't |
264 | | X86_64_SSE_CLASS or any other ones aren't |
265 | | X86_64_SSEUP_CLASS, everything should be passed in |
266 | | memory. */ |
267 | 0 | if (classes[0] != X86_64_SSE_CLASS) |
268 | 0 | return 0; |
269 | | |
270 | 0 | for (i = 1; i < words; i++) |
271 | 0 | if (classes[i] != X86_64_SSEUP_CLASS) |
272 | 0 | return 0; |
273 | 0 | } |
274 | | |
275 | | /* Final merger cleanup. */ |
276 | 0 | for (i = 0; i < words; i++) |
277 | 0 | { |
278 | | /* If one class is MEMORY, everything should be passed in |
279 | | memory. */ |
280 | 0 | if (classes[i] == X86_64_MEMORY_CLASS) |
281 | 0 | return 0; |
282 | | |
283 | | /* The X86_64_SSEUP_CLASS should be always preceded by |
284 | | X86_64_SSE_CLASS or X86_64_SSEUP_CLASS. */ |
285 | 0 | if (classes[i] == X86_64_SSEUP_CLASS |
286 | 0 | && classes[i - 1] != X86_64_SSE_CLASS |
287 | 0 | && classes[i - 1] != X86_64_SSEUP_CLASS) |
288 | 0 | { |
289 | | /* The first one should never be X86_64_SSEUP_CLASS. */ |
290 | 0 | FFI_ASSERT (i != 0); |
291 | 0 | classes[i] = X86_64_SSE_CLASS; |
292 | 0 | } |
293 | | |
294 | | /* If X86_64_X87UP_CLASS isn't preceded by X86_64_X87_CLASS, |
295 | | everything should be passed in memory. */ |
296 | 0 | if (classes[i] == X86_64_X87UP_CLASS |
297 | 0 | && (classes[i - 1] != X86_64_X87_CLASS)) |
298 | 0 | { |
299 | | /* The first one should never be X86_64_X87UP_CLASS. */ |
300 | 0 | FFI_ASSERT (i != 0); |
301 | 0 | return 0; |
302 | 0 | } |
303 | 0 | } |
304 | 0 | return words; |
305 | 0 | } |
306 | 0 | case FFI_TYPE_COMPLEX: |
307 | 0 | { |
308 | 0 | ffi_type *inner = type->elements[0]; |
309 | 0 | switch (inner->type) |
310 | 0 | { |
311 | 0 | case FFI_TYPE_INT: |
312 | 0 | case FFI_TYPE_UINT8: |
313 | 0 | case FFI_TYPE_SINT8: |
314 | 0 | case FFI_TYPE_UINT16: |
315 | 0 | case FFI_TYPE_SINT16: |
316 | 0 | case FFI_TYPE_UINT32: |
317 | 0 | case FFI_TYPE_SINT32: |
318 | 0 | case FFI_TYPE_UINT64: |
319 | 0 | case FFI_TYPE_SINT64: |
320 | 0 | goto do_integer; |
321 | | |
322 | 0 | case FFI_TYPE_FLOAT: |
323 | 0 | classes[0] = X86_64_SSE_CLASS; |
324 | 0 | if (byte_offset % 8) |
325 | 0 | { |
326 | 0 | classes[1] = X86_64_SSESF_CLASS; |
327 | 0 | return 2; |
328 | 0 | } |
329 | 0 | return 1; |
330 | 0 | case FFI_TYPE_DOUBLE: |
331 | 0 | classes[0] = classes[1] = X86_64_SSEDF_CLASS; |
332 | 0 | return 2; |
333 | 0 | #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE |
334 | 0 | case FFI_TYPE_LONGDOUBLE: |
335 | 0 | classes[0] = X86_64_COMPLEX_X87_CLASS; |
336 | 0 | return 1; |
337 | 0 | #endif |
338 | 0 | } |
339 | 0 | } |
340 | 0 | } |
341 | 0 | abort(); |
342 | 0 | } |
343 | | |
344 | | /* Examine the argument and return set number of register required in each |
345 | | class. Return zero iff parameter should be passed in memory, otherwise |
346 | | the number of registers. */ |
347 | | |
348 | | static size_t |
349 | | examine_argument (ffi_type *type, enum x86_64_reg_class classes[MAX_CLASSES], |
350 | | _Bool in_return, int *pngpr, int *pnsse) |
351 | 0 | { |
352 | 0 | size_t n; |
353 | 0 | unsigned int i; |
354 | 0 | int ngpr, nsse; |
355 | |
|
356 | 0 | n = classify_argument (type, classes, 0); |
357 | 0 | if (n == 0) |
358 | 0 | return 0; |
359 | | |
360 | 0 | ngpr = nsse = 0; |
361 | 0 | for (i = 0; i < n; ++i) |
362 | 0 | switch (classes[i]) |
363 | 0 | { |
364 | 0 | case X86_64_INTEGER_CLASS: |
365 | 0 | case X86_64_INTEGERSI_CLASS: |
366 | 0 | ngpr++; |
367 | 0 | break; |
368 | 0 | case X86_64_SSE_CLASS: |
369 | 0 | case X86_64_SSESF_CLASS: |
370 | 0 | case X86_64_SSEDF_CLASS: |
371 | 0 | nsse++; |
372 | 0 | break; |
373 | 0 | case X86_64_NO_CLASS: |
374 | 0 | case X86_64_SSEUP_CLASS: |
375 | 0 | break; |
376 | 0 | case X86_64_X87_CLASS: |
377 | 0 | case X86_64_X87UP_CLASS: |
378 | 0 | case X86_64_COMPLEX_X87_CLASS: |
379 | 0 | return in_return != 0; |
380 | 0 | default: |
381 | 0 | abort (); |
382 | 0 | } |
383 | | |
384 | 0 | *pngpr = ngpr; |
385 | 0 | *pnsse = nsse; |
386 | |
|
387 | 0 | return n; |
388 | 0 | } |
389 | | |
390 | | /* Perform machine dependent cif processing. */ |
391 | | |
392 | | #ifndef __ILP32__ |
393 | | extern ffi_status |
394 | | ffi_prep_cif_machdep_efi64(ffi_cif *cif); |
395 | | #endif |
396 | | |
397 | | ffi_status |
398 | | ffi_prep_cif_machdep (ffi_cif *cif) |
399 | 0 | { |
400 | 0 | int gprcount, ssecount, i, avn, ngpr, nsse; |
401 | 0 | unsigned flags; |
402 | 0 | enum x86_64_reg_class classes[MAX_CLASSES]; |
403 | 0 | size_t bytes, n, rtype_size; |
404 | 0 | ffi_type *rtype; |
405 | |
|
406 | 0 | #ifndef __ILP32__ |
407 | 0 | if (cif->abi == FFI_EFI64) |
408 | 0 | return ffi_prep_cif_machdep_efi64(cif); |
409 | 0 | #endif |
410 | 0 | if (cif->abi != FFI_UNIX64) |
411 | 0 | return FFI_BAD_ABI; |
412 | | |
413 | 0 | gprcount = ssecount = 0; |
414 | |
|
415 | 0 | rtype = cif->rtype; |
416 | 0 | rtype_size = rtype->size; |
417 | 0 | switch (rtype->type) |
418 | 0 | { |
419 | 0 | case FFI_TYPE_VOID: |
420 | 0 | flags = UNIX64_RET_VOID; |
421 | 0 | break; |
422 | 0 | case FFI_TYPE_UINT8: |
423 | 0 | flags = UNIX64_RET_UINT8; |
424 | 0 | break; |
425 | 0 | case FFI_TYPE_SINT8: |
426 | 0 | flags = UNIX64_RET_SINT8; |
427 | 0 | break; |
428 | 0 | case FFI_TYPE_UINT16: |
429 | 0 | flags = UNIX64_RET_UINT16; |
430 | 0 | break; |
431 | 0 | case FFI_TYPE_SINT16: |
432 | 0 | flags = UNIX64_RET_SINT16; |
433 | 0 | break; |
434 | 0 | case FFI_TYPE_UINT32: |
435 | 0 | flags = UNIX64_RET_UINT32; |
436 | 0 | break; |
437 | 0 | case FFI_TYPE_INT: |
438 | 0 | case FFI_TYPE_SINT32: |
439 | 0 | flags = UNIX64_RET_SINT32; |
440 | 0 | break; |
441 | 0 | case FFI_TYPE_UINT64: |
442 | 0 | case FFI_TYPE_SINT64: |
443 | 0 | flags = UNIX64_RET_INT64; |
444 | 0 | break; |
445 | 0 | case FFI_TYPE_POINTER: |
446 | 0 | flags = (sizeof(void *) == 4 ? UNIX64_RET_UINT32 : UNIX64_RET_INT64); |
447 | 0 | break; |
448 | 0 | case FFI_TYPE_FLOAT: |
449 | 0 | flags = UNIX64_RET_XMM32; |
450 | 0 | break; |
451 | 0 | case FFI_TYPE_DOUBLE: |
452 | 0 | flags = UNIX64_RET_XMM64; |
453 | 0 | break; |
454 | 0 | case FFI_TYPE_LONGDOUBLE: |
455 | 0 | flags = UNIX64_RET_X87; |
456 | 0 | break; |
457 | 0 | case FFI_TYPE_STRUCT: |
458 | 0 | n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse); |
459 | 0 | if (n == 0) |
460 | 0 | { |
461 | | /* The return value is passed in memory. A pointer to that |
462 | | memory is the first argument. Allocate a register for it. */ |
463 | 0 | gprcount++; |
464 | | /* We don't have to do anything in asm for the return. */ |
465 | 0 | flags = UNIX64_RET_VOID | UNIX64_FLAG_RET_IN_MEM; |
466 | 0 | } |
467 | 0 | else |
468 | 0 | { |
469 | 0 | _Bool sse0 = SSE_CLASS_P (classes[0]); |
470 | |
|
471 | 0 | if (rtype_size == 4 && sse0) |
472 | 0 | flags = UNIX64_RET_XMM32; |
473 | 0 | else if (rtype_size == 8) |
474 | 0 | flags = sse0 ? UNIX64_RET_XMM64 : UNIX64_RET_INT64; |
475 | 0 | else |
476 | 0 | { |
477 | 0 | _Bool sse1 = n == 2 && SSE_CLASS_P (classes[1]); |
478 | 0 | if (sse0 && sse1) |
479 | 0 | flags = UNIX64_RET_ST_XMM0_XMM1; |
480 | 0 | else if (sse0) |
481 | 0 | flags = UNIX64_RET_ST_XMM0_RAX; |
482 | 0 | else if (sse1) |
483 | 0 | flags = UNIX64_RET_ST_RAX_XMM0; |
484 | 0 | else |
485 | 0 | flags = UNIX64_RET_ST_RAX_RDX; |
486 | 0 | flags |= rtype_size << UNIX64_SIZE_SHIFT; |
487 | 0 | } |
488 | 0 | } |
489 | 0 | break; |
490 | 0 | case FFI_TYPE_COMPLEX: |
491 | 0 | switch (rtype->elements[0]->type) |
492 | 0 | { |
493 | 0 | case FFI_TYPE_UINT8: |
494 | 0 | case FFI_TYPE_SINT8: |
495 | 0 | case FFI_TYPE_UINT16: |
496 | 0 | case FFI_TYPE_SINT16: |
497 | 0 | case FFI_TYPE_INT: |
498 | 0 | case FFI_TYPE_UINT32: |
499 | 0 | case FFI_TYPE_SINT32: |
500 | 0 | case FFI_TYPE_UINT64: |
501 | 0 | case FFI_TYPE_SINT64: |
502 | 0 | flags = UNIX64_RET_ST_RAX_RDX | ((unsigned) rtype_size << UNIX64_SIZE_SHIFT); |
503 | 0 | break; |
504 | 0 | case FFI_TYPE_FLOAT: |
505 | 0 | flags = UNIX64_RET_XMM64; |
506 | 0 | break; |
507 | 0 | case FFI_TYPE_DOUBLE: |
508 | 0 | flags = UNIX64_RET_ST_XMM0_XMM1 | (16 << UNIX64_SIZE_SHIFT); |
509 | 0 | break; |
510 | 0 | #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE |
511 | 0 | case FFI_TYPE_LONGDOUBLE: |
512 | 0 | flags = UNIX64_RET_X87_2; |
513 | 0 | break; |
514 | 0 | #endif |
515 | 0 | default: |
516 | 0 | return FFI_BAD_TYPEDEF; |
517 | 0 | } |
518 | 0 | break; |
519 | 0 | default: |
520 | 0 | return FFI_BAD_TYPEDEF; |
521 | 0 | } |
522 | | |
523 | | /* Go over all arguments and determine the way they should be passed. |
524 | | If it's in a register and there is space for it, let that be so. If |
525 | | not, add it's size to the stack byte count. */ |
526 | 0 | for (bytes = 0, i = 0, avn = cif->nargs; i < avn; i++) |
527 | 0 | { |
528 | 0 | if (examine_argument (cif->arg_types[i], classes, 0, &ngpr, &nsse) == 0 |
529 | 0 | || gprcount + ngpr > MAX_GPR_REGS |
530 | 0 | || ssecount + nsse > MAX_SSE_REGS) |
531 | 0 | { |
532 | 0 | long align = cif->arg_types[i]->alignment; |
533 | |
|
534 | 0 | if (align < 8) |
535 | 0 | align = 8; |
536 | |
|
537 | 0 | bytes = FFI_ALIGN (bytes, align); |
538 | 0 | bytes += cif->arg_types[i]->size; |
539 | 0 | } |
540 | 0 | else |
541 | 0 | { |
542 | 0 | gprcount += ngpr; |
543 | 0 | ssecount += nsse; |
544 | 0 | } |
545 | 0 | } |
546 | 0 | if (ssecount) |
547 | 0 | flags |= UNIX64_FLAG_XMM_ARGS; |
548 | |
|
549 | 0 | cif->flags = flags; |
550 | 0 | cif->bytes = (unsigned) FFI_ALIGN (bytes, 8); |
551 | |
|
552 | 0 | return FFI_OK; |
553 | 0 | } |
554 | | |
555 | | static void |
556 | | ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue, |
557 | | void **avalue, void *closure) |
558 | 0 | { |
559 | 0 | enum x86_64_reg_class classes[MAX_CLASSES]; |
560 | 0 | char *stack, *argp; |
561 | 0 | ffi_type **arg_types; |
562 | 0 | int gprcount, ssecount, ngpr, nsse, i, avn, flags; |
563 | 0 | struct register_args *reg_args; |
564 | | |
565 | | /* Can't call 32-bit mode from 64-bit mode. */ |
566 | 0 | FFI_ASSERT (cif->abi == FFI_UNIX64); |
567 | | |
568 | | /* If the return value is a struct and we don't have a return value |
569 | | address then we need to make one. Otherwise we can ignore it. */ |
570 | 0 | flags = cif->flags; |
571 | 0 | if (rvalue == NULL) |
572 | 0 | { |
573 | 0 | if (flags & UNIX64_FLAG_RET_IN_MEM) |
574 | 0 | rvalue = alloca (cif->rtype->size); |
575 | 0 | else |
576 | 0 | flags = UNIX64_RET_VOID; |
577 | 0 | } |
578 | | |
579 | | /* Allocate the space for the arguments, plus 4 words of temp space. */ |
580 | 0 | stack = alloca (sizeof (struct register_args) + cif->bytes + 4*8); |
581 | 0 | reg_args = (struct register_args *) stack; |
582 | 0 | argp = stack + sizeof (struct register_args); |
583 | |
|
584 | 0 | reg_args->r10 = (uintptr_t) closure; |
585 | |
|
586 | 0 | gprcount = ssecount = 0; |
587 | | |
588 | | /* If the return value is passed in memory, add the pointer as the |
589 | | first integer argument. */ |
590 | 0 | if (flags & UNIX64_FLAG_RET_IN_MEM) |
591 | 0 | reg_args->gpr[gprcount++] = (unsigned long) rvalue; |
592 | |
|
593 | 0 | avn = cif->nargs; |
594 | 0 | arg_types = cif->arg_types; |
595 | |
|
596 | 0 | for (i = 0; i < avn; ++i) |
597 | 0 | { |
598 | 0 | size_t n, size = arg_types[i]->size; |
599 | |
|
600 | 0 | n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse); |
601 | 0 | if (n == 0 |
602 | 0 | || gprcount + ngpr > MAX_GPR_REGS |
603 | 0 | || ssecount + nsse > MAX_SSE_REGS) |
604 | 0 | { |
605 | 0 | long align = arg_types[i]->alignment; |
606 | | |
607 | | /* Stack arguments are *always* at least 8 byte aligned. */ |
608 | 0 | if (align < 8) |
609 | 0 | align = 8; |
610 | | |
611 | | /* Pass this argument in memory. */ |
612 | 0 | argp = (void *) FFI_ALIGN (argp, align); |
613 | 0 | memcpy (argp, avalue[i], size); |
614 | 0 | argp += size; |
615 | 0 | } |
616 | 0 | else |
617 | 0 | { |
618 | | /* The argument is passed entirely in registers. */ |
619 | 0 | char *a = (char *) avalue[i]; |
620 | 0 | unsigned int j; |
621 | |
|
622 | 0 | for (j = 0; j < n; j++, a += 8, size -= 8) |
623 | 0 | { |
624 | 0 | switch (classes[j]) |
625 | 0 | { |
626 | 0 | case X86_64_NO_CLASS: |
627 | 0 | case X86_64_SSEUP_CLASS: |
628 | 0 | break; |
629 | 0 | case X86_64_INTEGER_CLASS: |
630 | 0 | case X86_64_INTEGERSI_CLASS: |
631 | | /* Sign-extend integer arguments passed in general |
632 | | purpose registers, to cope with the fact that |
633 | | LLVM incorrectly assumes that this will be done |
634 | | (the x86-64 PS ABI does not specify this). */ |
635 | 0 | switch (arg_types[i]->type) |
636 | 0 | { |
637 | 0 | case FFI_TYPE_SINT8: |
638 | 0 | reg_args->gpr[gprcount] = (SINT64) *((SINT8 *) a); |
639 | 0 | break; |
640 | 0 | case FFI_TYPE_SINT16: |
641 | 0 | reg_args->gpr[gprcount] = (SINT64) *((SINT16 *) a); |
642 | 0 | break; |
643 | 0 | case FFI_TYPE_SINT32: |
644 | 0 | reg_args->gpr[gprcount] = (SINT64) *((SINT32 *) a); |
645 | 0 | break; |
646 | 0 | default: |
647 | 0 | reg_args->gpr[gprcount] = 0; |
648 | 0 | memcpy (®_args->gpr[gprcount], a, size); |
649 | 0 | } |
650 | 0 | gprcount++; |
651 | 0 | break; |
652 | 0 | case X86_64_SSE_CLASS: |
653 | 0 | case X86_64_SSEDF_CLASS: |
654 | 0 | memcpy (®_args->sse[ssecount++].i64, a, sizeof(UINT64)); |
655 | 0 | break; |
656 | 0 | case X86_64_SSESF_CLASS: |
657 | 0 | memcpy (®_args->sse[ssecount++].i32, a, sizeof(UINT32)); |
658 | 0 | break; |
659 | 0 | default: |
660 | 0 | abort(); |
661 | 0 | } |
662 | 0 | } |
663 | 0 | } |
664 | 0 | } |
665 | 0 | reg_args->rax = ssecount; |
666 | |
|
667 | 0 | ffi_call_unix64 (stack, cif->bytes + sizeof (struct register_args), |
668 | 0 | flags, rvalue, fn); |
669 | 0 | } |
670 | | |
671 | | #ifndef __ILP32__ |
672 | | extern void |
673 | | ffi_call_efi64(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue); |
674 | | #endif |
675 | | |
676 | | void |
677 | | ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) |
678 | 0 | { |
679 | 0 | #ifndef __ILP32__ |
680 | 0 | if (cif->abi == FFI_EFI64) |
681 | 0 | return ffi_call_efi64(cif, fn, rvalue, avalue); |
682 | 0 | #endif |
683 | 0 | ffi_call_int (cif, fn, rvalue, avalue, NULL); |
684 | 0 | } |
685 | | |
686 | | #ifndef __ILP32__ |
687 | | extern void |
688 | | ffi_call_go_efi64(ffi_cif *cif, void (*fn)(void), void *rvalue, |
689 | | void **avalue, void *closure); |
690 | | #endif |
691 | | |
692 | | void |
693 | | ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue, |
694 | | void **avalue, void *closure) |
695 | 0 | { |
696 | 0 | #ifndef __ILP32__ |
697 | 0 | if (cif->abi == FFI_EFI64) |
698 | 0 | ffi_call_go_efi64(cif, fn, rvalue, avalue, closure); |
699 | 0 | #endif |
700 | 0 | ffi_call_int (cif, fn, rvalue, avalue, closure); |
701 | 0 | } |
702 | | |
703 | | |
704 | | extern void ffi_closure_unix64(void) FFI_HIDDEN; |
705 | | extern void ffi_closure_unix64_sse(void) FFI_HIDDEN; |
706 | | |
707 | | #ifndef __ILP32__ |
708 | | extern ffi_status |
709 | | ffi_prep_closure_loc_efi64(ffi_closure* closure, |
710 | | ffi_cif* cif, |
711 | | void (*fun)(ffi_cif*, void*, void**, void*), |
712 | | void *user_data, |
713 | | void *codeloc); |
714 | | #endif |
715 | | |
716 | | ffi_status |
717 | | ffi_prep_closure_loc (ffi_closure* closure, |
718 | | ffi_cif* cif, |
719 | | void (*fun)(ffi_cif*, void*, void**, void*), |
720 | | void *user_data, |
721 | | void *codeloc) |
722 | 0 | { |
723 | 0 | static const unsigned char trampoline[16] = { |
724 | | /* leaq -0x7(%rip),%r10 # 0x0 */ |
725 | 0 | 0x4c, 0x8d, 0x15, 0xf9, 0xff, 0xff, 0xff, |
726 | | /* jmpq *0x3(%rip) # 0x10 */ |
727 | 0 | 0xff, 0x25, 0x03, 0x00, 0x00, 0x00, |
728 | | /* nopl (%rax) */ |
729 | 0 | 0x0f, 0x1f, 0x00 |
730 | 0 | }; |
731 | 0 | void (*dest)(void); |
732 | 0 | char *tramp = closure->tramp; |
733 | |
|
734 | 0 | #ifndef __ILP32__ |
735 | 0 | if (cif->abi == FFI_EFI64) |
736 | 0 | return ffi_prep_closure_loc_efi64(closure, cif, fun, user_data, codeloc); |
737 | 0 | #endif |
738 | 0 | if (cif->abi != FFI_UNIX64) |
739 | 0 | return FFI_BAD_ABI; |
740 | | |
741 | 0 | if (cif->flags & UNIX64_FLAG_XMM_ARGS) |
742 | 0 | dest = ffi_closure_unix64_sse; |
743 | 0 | else |
744 | 0 | dest = ffi_closure_unix64; |
745 | |
|
746 | 0 | memcpy (tramp, trampoline, sizeof(trampoline)); |
747 | 0 | *(UINT64 *)(tramp + 16) = (uintptr_t)dest; |
748 | |
|
749 | 0 | closure->cif = cif; |
750 | 0 | closure->fun = fun; |
751 | 0 | closure->user_data = user_data; |
752 | |
|
753 | 0 | return FFI_OK; |
754 | 0 | } |
755 | | |
756 | | int FFI_HIDDEN |
757 | | ffi_closure_unix64_inner(ffi_cif *cif, |
758 | | void (*fun)(ffi_cif*, void*, void**, void*), |
759 | | void *user_data, |
760 | | void *rvalue, |
761 | | struct register_args *reg_args, |
762 | | char *argp) |
763 | 0 | { |
764 | 0 | void **avalue; |
765 | 0 | ffi_type **arg_types; |
766 | 0 | long i, avn; |
767 | 0 | int gprcount, ssecount, ngpr, nsse; |
768 | 0 | int flags; |
769 | |
|
770 | 0 | avn = cif->nargs; |
771 | 0 | flags = cif->flags; |
772 | 0 | avalue = alloca(avn * sizeof(void *)); |
773 | 0 | gprcount = ssecount = 0; |
774 | |
|
775 | 0 | if (flags & UNIX64_FLAG_RET_IN_MEM) |
776 | 0 | { |
777 | | /* On return, %rax will contain the address that was passed |
778 | | by the caller in %rdi. */ |
779 | 0 | void *r = (void *)(uintptr_t)reg_args->gpr[gprcount++]; |
780 | 0 | *(void **)rvalue = r; |
781 | 0 | rvalue = r; |
782 | 0 | flags = (sizeof(void *) == 4 ? UNIX64_RET_UINT32 : UNIX64_RET_INT64); |
783 | 0 | } |
784 | |
|
785 | 0 | arg_types = cif->arg_types; |
786 | 0 | for (i = 0; i < avn; ++i) |
787 | 0 | { |
788 | 0 | enum x86_64_reg_class classes[MAX_CLASSES]; |
789 | 0 | size_t n; |
790 | |
|
791 | 0 | n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse); |
792 | 0 | if (n == 0 |
793 | 0 | || gprcount + ngpr > MAX_GPR_REGS |
794 | 0 | || ssecount + nsse > MAX_SSE_REGS) |
795 | 0 | { |
796 | 0 | long align = arg_types[i]->alignment; |
797 | | |
798 | | /* Stack arguments are *always* at least 8 byte aligned. */ |
799 | 0 | if (align < 8) |
800 | 0 | align = 8; |
801 | | |
802 | | /* Pass this argument in memory. */ |
803 | 0 | argp = (void *) FFI_ALIGN (argp, align); |
804 | 0 | avalue[i] = argp; |
805 | 0 | argp += arg_types[i]->size; |
806 | 0 | } |
807 | | /* If the argument is in a single register, or two consecutive |
808 | | integer registers, then we can use that address directly. */ |
809 | 0 | else if (n == 1 |
810 | 0 | || (n == 2 && !(SSE_CLASS_P (classes[0]) |
811 | 0 | || SSE_CLASS_P (classes[1])))) |
812 | 0 | { |
813 | | /* The argument is in a single register. */ |
814 | 0 | if (SSE_CLASS_P (classes[0])) |
815 | 0 | { |
816 | 0 | avalue[i] = ®_args->sse[ssecount]; |
817 | 0 | ssecount += n; |
818 | 0 | } |
819 | 0 | else |
820 | 0 | { |
821 | 0 | avalue[i] = ®_args->gpr[gprcount]; |
822 | 0 | gprcount += n; |
823 | 0 | } |
824 | 0 | } |
825 | | /* Otherwise, allocate space to make them consecutive. */ |
826 | 0 | else |
827 | 0 | { |
828 | 0 | char *a = alloca (16); |
829 | 0 | unsigned int j; |
830 | |
|
831 | 0 | avalue[i] = a; |
832 | 0 | for (j = 0; j < n; j++, a += 8) |
833 | 0 | { |
834 | 0 | if (SSE_CLASS_P (classes[j])) |
835 | 0 | memcpy (a, ®_args->sse[ssecount++], 8); |
836 | 0 | else |
837 | 0 | memcpy (a, ®_args->gpr[gprcount++], 8); |
838 | 0 | } |
839 | 0 | } |
840 | 0 | } |
841 | | |
842 | | /* Invoke the closure. */ |
843 | 0 | fun (cif, rvalue, avalue, user_data); |
844 | | |
845 | | /* Tell assembly how to perform return type promotions. */ |
846 | 0 | return flags; |
847 | 0 | } |
848 | | |
849 | | extern void ffi_go_closure_unix64(void) FFI_HIDDEN; |
850 | | extern void ffi_go_closure_unix64_sse(void) FFI_HIDDEN; |
851 | | |
852 | | #ifndef __ILP32__ |
853 | | extern ffi_status |
854 | | ffi_prep_go_closure_efi64(ffi_go_closure* closure, ffi_cif* cif, |
855 | | void (*fun)(ffi_cif*, void*, void**, void*)); |
856 | | #endif |
857 | | |
858 | | ffi_status |
859 | | ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif, |
860 | | void (*fun)(ffi_cif*, void*, void**, void*)) |
861 | 0 | { |
862 | 0 | #ifndef __ILP32__ |
863 | 0 | if (cif->abi == FFI_EFI64) |
864 | 0 | return ffi_prep_go_closure_efi64(closure, cif, fun); |
865 | 0 | #endif |
866 | 0 | if (cif->abi != FFI_UNIX64) |
867 | 0 | return FFI_BAD_ABI; |
868 | | |
869 | 0 | closure->tramp = (cif->flags & UNIX64_FLAG_XMM_ARGS |
870 | 0 | ? ffi_go_closure_unix64_sse |
871 | 0 | : ffi_go_closure_unix64); |
872 | 0 | closure->cif = cif; |
873 | 0 | closure->fun = fun; |
874 | |
|
875 | 0 | return FFI_OK; |
876 | 0 | } |
877 | | |
878 | | #endif /* __x86_64__ */ |