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