Coverage Report

Created: 2026-10-14 08:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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 (&reg_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 (&reg_args->sse[ssecount++].i64, a, sizeof(UINT64));
664
0
      break;
665
0
    case X86_64_SSESF_CLASS:
666
0
      memcpy (&reg_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] = &reg_args->sse[ssecount];
876
0
        ssecount += n;
877
0
      }
878
0
    else
879
0
      {
880
0
        avalue[i] = &reg_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, &reg_args->sse[ssecount++], 8);
895
0
        else
896
0
    memcpy (a, &reg_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__ */