Coverage Report

Created: 2025-09-27 07:50

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
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 (&reg_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 (&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
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] = &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__ */