Coverage Report

Created: 2026-02-24 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gstreamer/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
2.65M
#define MAX_GPR_REGS 6
41
1.32M
#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
1.32M
{
163
1.32M
  switch (type->type)
164
1.32M
    {
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
9.30k
    case FFI_TYPE_UINT32:
170
9.30k
    case FFI_TYPE_SINT32:
171
9.30k
    case FFI_TYPE_UINT64:
172
9.30k
    case FFI_TYPE_SINT64:
173
1.32M
    case FFI_TYPE_POINTER:
174
1.32M
    do_integer:
175
1.32M
      {
176
1.32M
  size_t size = byte_offset + type->size;
177
178
1.32M
  if (size <= 4)
179
9.30k
    {
180
9.30k
      classes[0] = X86_64_INTEGERSI_CLASS;
181
9.30k
      return 1;
182
9.30k
    }
183
1.31M
  else if (size <= 8)
184
1.31M
    {
185
1.31M
      classes[0] = X86_64_INTEGER_CLASS;
186
1.31M
      return 1;
187
1.31M
    }
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
1.32M
      }
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
1.32M
    }
341
0
  abort();
342
1.32M
}
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
1.32M
{
352
1.32M
  size_t n;
353
1.32M
  unsigned int i;
354
1.32M
  int ngpr, nsse;
355
356
1.32M
  n = classify_argument (type, classes, 0);
357
1.32M
  if (n == 0)
358
0
    return 0;
359
360
1.32M
  ngpr = nsse = 0;
361
2.65M
  for (i = 0; i < n; ++i)
362
1.32M
    switch (classes[i])
363
1.32M
      {
364
1.31M
      case X86_64_INTEGER_CLASS:
365
1.32M
      case X86_64_INTEGERSI_CLASS:
366
1.32M
  ngpr++;
367
1.32M
  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
1.32M
      }
383
384
1.32M
  *pngpr = ngpr;
385
1.32M
  *pnsse = nsse;
386
387
1.32M
  return n;
388
1.32M
}
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
170k
{
400
170k
  int gprcount, ssecount, i, avn, ngpr, nsse;
401
170k
  unsigned flags;
402
170k
  enum x86_64_reg_class classes[MAX_CLASSES];
403
170k
  size_t bytes, n, rtype_size;
404
170k
  ffi_type *rtype;
405
406
170k
#ifndef __ILP32__
407
170k
  if (cif->abi == FFI_EFI64)
408
0
    return ffi_prep_cif_machdep_efi64(cif);
409
170k
#endif
410
170k
  if (cif->abi != FFI_UNIX64)
411
0
    return FFI_BAD_ABI;
412
413
170k
  gprcount = ssecount = 0;
414
415
170k
  rtype = cif->rtype;
416
170k
  rtype_size = rtype->size;
417
170k
  switch (rtype->type)
418
170k
    {
419
147k
    case FFI_TYPE_VOID:
420
147k
      flags = UNIX64_RET_VOID;
421
147k
      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
16.9k
    case FFI_TYPE_SINT32:
439
16.9k
      flags = UNIX64_RET_SINT32;
440
16.9k
      break;
441
0
    case FFI_TYPE_UINT64:
442
0
    case FFI_TYPE_SINT64:
443
0
      flags = UNIX64_RET_INT64;
444
0
      break;
445
5.99k
    case FFI_TYPE_POINTER:
446
5.99k
      flags = (sizeof(void *) == 4 ? UNIX64_RET_UINT32 : UNIX64_RET_INT64);
447
5.99k
      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
170k
    }
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
833k
  for (bytes = 0, i = 0, avn = cif->nargs; i < avn; i++)
527
663k
    {
528
663k
      if (examine_argument (cif->arg_types[i], classes, 0, &ngpr, &nsse) == 0
529
663k
    || gprcount + ngpr > MAX_GPR_REGS
530
663k
    || 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
663k
      else
541
663k
  {
542
663k
    gprcount += ngpr;
543
663k
    ssecount += nsse;
544
663k
  }
545
663k
    }
546
170k
  if (ssecount)
547
0
    flags |= UNIX64_FLAG_XMM_ARGS;
548
549
170k
  cif->flags = flags;
550
170k
  cif->bytes = (unsigned) FFI_ALIGN (bytes, 8);
551
552
170k
  return FFI_OK;
553
170k
}
554
555
static void
556
ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
557
        void **avalue, void *closure)
558
170k
{
559
170k
  enum x86_64_reg_class classes[MAX_CLASSES];
560
170k
  char *stack, *argp;
561
170k
  ffi_type **arg_types;
562
170k
  int gprcount, ssecount, ngpr, nsse, i, avn, flags;
563
170k
  struct register_args *reg_args;
564
565
  /* Can't call 32-bit mode from 64-bit mode.  */
566
170k
  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
170k
  flags = cif->flags;
571
170k
  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
170k
  stack = alloca (sizeof (struct register_args) + cif->bytes + 4*8);
581
170k
  reg_args = (struct register_args *) stack;
582
170k
  argp = stack + sizeof (struct register_args);
583
584
170k
  reg_args->r10 = (uintptr_t) closure;
585
586
170k
  gprcount = ssecount = 0;
587
588
  /* If the return value is passed in memory, add the pointer as the
589
     first integer argument.  */
590
170k
  if (flags & UNIX64_FLAG_RET_IN_MEM)
591
0
    reg_args->gpr[gprcount++] = (unsigned long) rvalue;
592
593
170k
  avn = cif->nargs;
594
170k
  arg_types = cif->arg_types;
595
596
833k
  for (i = 0; i < avn; ++i)
597
663k
    {
598
663k
      size_t n, size = arg_types[i]->size;
599
600
663k
      n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse);
601
663k
      if (n == 0
602
663k
    || gprcount + ngpr > MAX_GPR_REGS
603
663k
    || 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
663k
      else
617
663k
  {
618
    /* The argument is passed entirely in registers.  */
619
663k
    char *a = (char *) avalue[i];
620
663k
    unsigned int j;
621
622
1.32M
    for (j = 0; j < n; j++, a += 8, size -= 8)
623
663k
      {
624
663k
        switch (classes[j])
625
663k
    {
626
0
    case X86_64_NO_CLASS:
627
0
    case X86_64_SSEUP_CLASS:
628
0
      break;
629
658k
    case X86_64_INTEGER_CLASS:
630
663k
    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
663k
      switch (arg_types[i]->type)
636
663k
        {
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
663k
        default:
647
663k
          reg_args->gpr[gprcount] = 0;
648
663k
          memcpy (&reg_args->gpr[gprcount], a, size);
649
663k
        }
650
663k
      gprcount++;
651
663k
      break;
652
0
    case X86_64_SSE_CLASS:
653
0
    case X86_64_SSEDF_CLASS:
654
0
      memcpy (&reg_args->sse[ssecount++].i64, a, sizeof(UINT64));
655
0
      break;
656
0
    case X86_64_SSESF_CLASS:
657
0
      memcpy (&reg_args->sse[ssecount++].i32, a, sizeof(UINT32));
658
0
      break;
659
0
    default:
660
0
      abort();
661
663k
    }
662
663k
      }
663
663k
  }
664
663k
    }
665
170k
  reg_args->rax = ssecount;
666
667
170k
  ffi_call_unix64 (stack, cif->bytes + sizeof (struct register_args),
668
170k
       flags, rvalue, fn);
669
170k
}
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
170k
{
679
170k
#ifndef __ILP32__
680
170k
  if (cif->abi == FFI_EFI64)
681
0
    return ffi_call_efi64(cif, fn, rvalue, avalue);
682
170k
#endif
683
170k
  ffi_call_int (cif, fn, rvalue, avalue, NULL);
684
170k
}
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] = &reg_args->sse[ssecount];
817
0
        ssecount += n;
818
0
      }
819
0
    else
820
0
      {
821
0
        avalue[i] = &reg_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, &reg_args->sse[ssecount++], 8);
836
0
        else
837
0
    memcpy (a, &reg_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__ */