Coverage Report

Created: 2026-06-07 08:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
/* n.b. ffi_call_unix64 will steal the alloca'd `stack` variable here for use
556
   _as its own stack_ - so we need to compile this function without ASAN */
557
FFI_ASAN_NO_SANITIZE
558
static void
559
ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
560
        void **avalue, void *closure)
561
0
{
562
0
  enum x86_64_reg_class classes[MAX_CLASSES];
563
0
  char *stack, *argp;
564
0
  ffi_type **arg_types;
565
0
  int gprcount, ssecount, ngpr, nsse, i, avn, flags;
566
0
  struct register_args *reg_args;
567
568
  /* Can't call 32-bit mode from 64-bit mode.  */
569
0
  FFI_ASSERT (cif->abi == FFI_UNIX64);
570
571
  /* If the return value is a struct and we don't have a return value
572
     address then we need to make one.  Otherwise we can ignore it.  */
573
0
  flags = cif->flags;
574
0
  if (rvalue == NULL)
575
0
    {
576
0
      if (flags & UNIX64_FLAG_RET_IN_MEM)
577
0
  rvalue = alloca (cif->rtype->size);
578
0
      else
579
0
  flags = UNIX64_RET_VOID;
580
0
    }
581
582
  /* Allocate the space for the arguments, plus 4 words of temp space.  */
583
0
  stack = alloca (sizeof (struct register_args) + cif->bytes + 4*8);
584
0
  reg_args = (struct register_args *) stack;
585
0
  argp = stack + sizeof (struct register_args);
586
587
0
  reg_args->r10 = (uintptr_t) closure;
588
589
0
  gprcount = ssecount = 0;
590
591
  /* If the return value is passed in memory, add the pointer as the
592
     first integer argument.  */
593
0
  if (flags & UNIX64_FLAG_RET_IN_MEM)
594
0
    reg_args->gpr[gprcount++] = (unsigned long) rvalue;
595
596
0
  avn = cif->nargs;
597
0
  arg_types = cif->arg_types;
598
599
0
  for (i = 0; i < avn; ++i)
600
0
    {
601
0
      size_t n, size = arg_types[i]->size;
602
603
0
      n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse);
604
0
      if (n == 0
605
0
    || gprcount + ngpr > MAX_GPR_REGS
606
0
    || ssecount + nsse > MAX_SSE_REGS)
607
0
  {
608
0
    long align = arg_types[i]->alignment;
609
610
    /* Stack arguments are *always* at least 8 byte aligned.  */
611
0
    if (align < 8)
612
0
      align = 8;
613
614
    /* Pass this argument in memory.  */
615
0
    argp = (void *) FFI_ALIGN (argp, align);
616
0
    memcpy (argp, avalue[i], size);
617
0
    argp += size;
618
0
  }
619
0
      else
620
0
  {
621
    /* The argument is passed entirely in registers.  */
622
0
    char *a = (char *) avalue[i];
623
0
    unsigned int j;
624
625
0
    for (j = 0; j < n; j++, a += 8, size -= 8)
626
0
      {
627
0
        switch (classes[j])
628
0
    {
629
0
    case X86_64_NO_CLASS:
630
0
    case X86_64_SSEUP_CLASS:
631
0
      break;
632
0
    case X86_64_INTEGER_CLASS:
633
0
    case X86_64_INTEGERSI_CLASS:
634
      /* Sign-extend integer arguments passed in general
635
         purpose registers, to cope with the fact that
636
         LLVM incorrectly assumes that this will be done
637
         (the x86-64 PS ABI does not specify this). */
638
0
      switch (arg_types[i]->type)
639
0
        {
640
0
        case FFI_TYPE_SINT8:
641
0
          reg_args->gpr[gprcount] = (SINT64) *((SINT8 *) a);
642
0
          break;
643
0
        case FFI_TYPE_SINT16:
644
0
          reg_args->gpr[gprcount] = (SINT64) *((SINT16 *) a);
645
0
          break;
646
0
        case FFI_TYPE_SINT32:
647
0
          reg_args->gpr[gprcount] = (SINT64) *((SINT32 *) a);
648
0
          break;
649
0
        default:
650
0
          reg_args->gpr[gprcount] = 0;
651
0
          memcpy (&reg_args->gpr[gprcount], a, size);
652
0
        }
653
0
      gprcount++;
654
0
      break;
655
0
    case X86_64_SSE_CLASS:
656
0
    case X86_64_SSEDF_CLASS:
657
0
      memcpy (&reg_args->sse[ssecount++].i64, a, sizeof(UINT64));
658
0
      break;
659
0
    case X86_64_SSESF_CLASS:
660
0
      memcpy (&reg_args->sse[ssecount++].i32, a, sizeof(UINT32));
661
0
      break;
662
0
    default:
663
0
      abort();
664
0
    }
665
0
      }
666
0
  }
667
0
    }
668
0
  reg_args->rax = ssecount;
669
670
0
  ffi_call_unix64 (stack, cif->bytes + sizeof (struct register_args),
671
0
       flags, rvalue, fn);
672
0
}
673
674
#ifndef __ILP32__
675
extern void
676
ffi_call_efi64(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue);
677
#endif
678
679
void
680
ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
681
0
{
682
0
#ifndef __ILP32__
683
0
  if (cif->abi == FFI_EFI64)
684
0
    return ffi_call_efi64(cif, fn, rvalue, avalue);
685
0
#endif
686
0
  ffi_call_int (cif, fn, rvalue, avalue, NULL);
687
0
}
688
689
#ifndef __ILP32__
690
extern void
691
ffi_call_go_efi64(ffi_cif *cif, void (*fn)(void), void *rvalue,
692
      void **avalue, void *closure);
693
#endif
694
695
void
696
ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
697
       void **avalue, void *closure)
698
0
{
699
0
#ifndef __ILP32__
700
0
  if (cif->abi == FFI_EFI64)
701
0
    ffi_call_go_efi64(cif, fn, rvalue, avalue, closure);
702
0
#endif
703
0
  ffi_call_int (cif, fn, rvalue, avalue, closure);
704
0
}
705
706
707
extern void ffi_closure_unix64(void) FFI_HIDDEN;
708
extern void ffi_closure_unix64_sse(void) FFI_HIDDEN;
709
710
#ifndef __ILP32__
711
extern ffi_status
712
ffi_prep_closure_loc_efi64(ffi_closure* closure,
713
         ffi_cif* cif,
714
         void (*fun)(ffi_cif*, void*, void**, void*),
715
         void *user_data,
716
         void *codeloc);
717
#endif
718
719
ffi_status
720
ffi_prep_closure_loc (ffi_closure* closure,
721
          ffi_cif* cif,
722
          void (*fun)(ffi_cif*, void*, void**, void*),
723
          void *user_data,
724
          void *codeloc)
725
0
{
726
0
  static const unsigned char trampoline[16] = {
727
    /* leaq  -0x7(%rip),%r10   # 0x0  */
728
0
    0x4c, 0x8d, 0x15, 0xf9, 0xff, 0xff, 0xff,
729
    /* jmpq  *0x3(%rip)        # 0x10 */
730
0
    0xff, 0x25, 0x03, 0x00, 0x00, 0x00,
731
    /* nopl  (%rax) */
732
0
    0x0f, 0x1f, 0x00
733
0
  };
734
0
  void (*dest)(void);
735
0
  char *tramp = closure->tramp;
736
737
0
#ifndef __ILP32__
738
0
  if (cif->abi == FFI_EFI64)
739
0
    return ffi_prep_closure_loc_efi64(closure, cif, fun, user_data, codeloc);
740
0
#endif
741
0
  if (cif->abi != FFI_UNIX64)
742
0
    return FFI_BAD_ABI;
743
744
0
  if (cif->flags & UNIX64_FLAG_XMM_ARGS)
745
0
    dest = ffi_closure_unix64_sse;
746
0
  else
747
0
    dest = ffi_closure_unix64;
748
749
0
  memcpy (tramp, trampoline, sizeof(trampoline));
750
0
  *(UINT64 *)(tramp + 16) = (uintptr_t)dest;
751
752
0
  closure->cif = cif;
753
0
  closure->fun = fun;
754
0
  closure->user_data = user_data;
755
756
0
  return FFI_OK;
757
0
}
758
759
int FFI_HIDDEN
760
ffi_closure_unix64_inner(ffi_cif *cif,
761
       void (*fun)(ffi_cif*, void*, void**, void*),
762
       void *user_data,
763
       void *rvalue,
764
       struct register_args *reg_args,
765
       char *argp)
766
0
{
767
0
  void **avalue;
768
0
  ffi_type **arg_types;
769
0
  long i, avn;
770
0
  int gprcount, ssecount, ngpr, nsse;
771
0
  int flags;
772
773
0
  avn = cif->nargs;
774
0
  flags = cif->flags;
775
0
  avalue = alloca(avn * sizeof(void *));
776
0
  gprcount = ssecount = 0;
777
778
0
  if (flags & UNIX64_FLAG_RET_IN_MEM)
779
0
    {
780
      /* On return, %rax will contain the address that was passed
781
   by the caller in %rdi.  */
782
0
      void *r = (void *)(uintptr_t)reg_args->gpr[gprcount++];
783
0
      *(void **)rvalue = r;
784
0
      rvalue = r;
785
0
      flags = (sizeof(void *) == 4 ? UNIX64_RET_UINT32 : UNIX64_RET_INT64);
786
0
    }
787
788
0
  arg_types = cif->arg_types;
789
0
  for (i = 0; i < avn; ++i)
790
0
    {
791
0
      enum x86_64_reg_class classes[MAX_CLASSES];
792
0
      size_t n;
793
794
0
      n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse);
795
0
      if (n == 0
796
0
    || gprcount + ngpr > MAX_GPR_REGS
797
0
    || ssecount + nsse > MAX_SSE_REGS)
798
0
  {
799
0
    long align = arg_types[i]->alignment;
800
801
    /* Stack arguments are *always* at least 8 byte aligned.  */
802
0
    if (align < 8)
803
0
      align = 8;
804
805
    /* Pass this argument in memory.  */
806
0
    argp = (void *) FFI_ALIGN (argp, align);
807
0
    avalue[i] = argp;
808
0
    argp += arg_types[i]->size;
809
0
  }
810
      /* If the argument is in a single register, or two consecutive
811
   integer registers, then we can use that address directly.  */
812
0
      else if (n == 1
813
0
         || (n == 2 && !(SSE_CLASS_P (classes[0])
814
0
             || SSE_CLASS_P (classes[1]))))
815
0
  {
816
    /* The argument is in a single register.  */
817
0
    if (SSE_CLASS_P (classes[0]))
818
0
      {
819
0
        avalue[i] = &reg_args->sse[ssecount];
820
0
        ssecount += n;
821
0
      }
822
0
    else
823
0
      {
824
0
        avalue[i] = &reg_args->gpr[gprcount];
825
0
        gprcount += n;
826
0
      }
827
0
  }
828
      /* Otherwise, allocate space to make them consecutive.  */
829
0
      else
830
0
  {
831
0
    char *a = alloca (16);
832
0
    unsigned int j;
833
834
0
    avalue[i] = a;
835
0
    for (j = 0; j < n; j++, a += 8)
836
0
      {
837
0
        if (SSE_CLASS_P (classes[j]))
838
0
    memcpy (a, &reg_args->sse[ssecount++], 8);
839
0
        else
840
0
    memcpy (a, &reg_args->gpr[gprcount++], 8);
841
0
      }
842
0
  }
843
0
    }
844
845
  /* Invoke the closure.  */
846
0
  fun (cif, rvalue, avalue, user_data);
847
848
  /* Tell assembly how to perform return type promotions.  */
849
0
  return flags;
850
0
}
851
852
extern void ffi_go_closure_unix64(void) FFI_HIDDEN;
853
extern void ffi_go_closure_unix64_sse(void) FFI_HIDDEN;
854
855
#ifndef __ILP32__
856
extern ffi_status
857
ffi_prep_go_closure_efi64(ffi_go_closure* closure, ffi_cif* cif,
858
        void (*fun)(ffi_cif*, void*, void**, void*));
859
#endif
860
861
ffi_status
862
ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif,
863
         void (*fun)(ffi_cif*, void*, void**, void*))
864
0
{
865
0
#ifndef __ILP32__
866
0
  if (cif->abi == FFI_EFI64)
867
0
    return ffi_prep_go_closure_efi64(closure, cif, fun);
868
0
#endif
869
0
  if (cif->abi != FFI_UNIX64)
870
0
    return FFI_BAD_ABI;
871
872
0
  closure->tramp = (cif->flags & UNIX64_FLAG_XMM_ARGS
873
0
        ? ffi_go_closure_unix64_sse
874
0
        : ffi_go_closure_unix64);
875
0
  closure->cif = cif;
876
0
  closure->fun = fun;
877
878
0
  return FFI_OK;
879
0
}
880
881
#endif /* __x86_64__ */