(root)/
gcc-13.2.0/
libffi/
src/
x86/
ffi.c
       1  /* -----------------------------------------------------------------------
       2     ffi.c - Copyright (c) 2017  Anthony Green
       3             Copyright (c) 1996, 1998, 1999, 2001, 2007, 2008  Red Hat, Inc.
       4             Copyright (c) 2002  Ranjit Mathew
       5             Copyright (c) 2002  Bo Thorsen
       6             Copyright (c) 2002  Roger Sayle
       7             Copyright (C) 2008, 2010  Free Software Foundation, Inc.
       8  
       9     x86 Foreign Function Interface
      10  
      11     Permission is hereby granted, free of charge, to any person obtaining
      12     a copy of this software and associated documentation files (the
      13     ``Software''), to deal in the Software without restriction, including
      14     without limitation the rights to use, copy, modify, merge, publish,
      15     distribute, sublicense, and/or sell copies of the Software, and to
      16     permit persons to whom the Software is furnished to do so, subject to
      17     the following conditions:
      18  
      19     The above copyright notice and this permission notice shall be included
      20     in all copies or substantial portions of the Software.
      21  
      22     THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
      23     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      24     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
      25     NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
      26     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
      27     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      28     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      29     DEALINGS IN THE SOFTWARE.
      30     ----------------------------------------------------------------------- */
      31  
      32  #if defined(__i386__) || defined(_M_IX86)
      33  #include <ffi.h>
      34  #include <ffi_common.h>
      35  #include <stdint.h>
      36  #include <stdlib.h>
      37  #include <tramp.h>
      38  #include "internal.h"
      39  
      40  /* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
      41     all further uses in this file will refer to the 80-bit type.  */
      42  #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
      43  # if FFI_TYPE_LONGDOUBLE != 4
      44  #  error FFI_TYPE_LONGDOUBLE out of date
      45  # endif
      46  #else
      47  # undef FFI_TYPE_LONGDOUBLE
      48  # define FFI_TYPE_LONGDOUBLE 4
      49  #endif
      50  
      51  #if defined(__GNUC__) && !defined(__declspec)
      52  # define __declspec(x)  __attribute__((x))
      53  #endif
      54  
      55  #if defined(_MSC_VER) && defined(_M_IX86)
      56  /* Stack is not 16-byte aligned on Windows.  */
      57  #define STACK_ALIGN(bytes) (bytes)
      58  #else
      59  #define STACK_ALIGN(bytes) FFI_ALIGN (bytes, 16)
      60  #endif
      61  
      62  /* Perform machine dependent cif processing.  */
      63  ffi_status FFI_HIDDEN
      64  ffi_prep_cif_machdep(ffi_cif *cif)
      65  {
      66    size_t bytes = 0;
      67    int i, n, flags, cabi = cif->abi;
      68  
      69    switch (cabi)
      70      {
      71      case FFI_SYSV:
      72      case FFI_STDCALL:
      73      case FFI_THISCALL:
      74      case FFI_FASTCALL:
      75      case FFI_MS_CDECL:
      76      case FFI_PASCAL:
      77      case FFI_REGISTER:
      78        break;
      79      default:
      80        return FFI_BAD_ABI;
      81      }
      82  
      83    switch (cif->rtype->type)
      84      {
      85      case FFI_TYPE_VOID:
      86        flags = X86_RET_VOID;
      87        break;
      88      case FFI_TYPE_FLOAT:
      89        flags = X86_RET_FLOAT;
      90        break;
      91      case FFI_TYPE_DOUBLE:
      92        flags = X86_RET_DOUBLE;
      93        break;
      94      case FFI_TYPE_LONGDOUBLE:
      95        flags = X86_RET_LDOUBLE;
      96        break;
      97      case FFI_TYPE_UINT8:
      98        flags = X86_RET_UINT8;
      99        break;
     100      case FFI_TYPE_UINT16:
     101        flags = X86_RET_UINT16;
     102        break;
     103      case FFI_TYPE_SINT8:
     104        flags = X86_RET_SINT8;
     105        break;
     106      case FFI_TYPE_SINT16:
     107        flags = X86_RET_SINT16;
     108        break;
     109      case FFI_TYPE_INT:
     110      case FFI_TYPE_SINT32:
     111      case FFI_TYPE_UINT32:
     112      case FFI_TYPE_POINTER:
     113        flags = X86_RET_INT32;
     114        break;
     115      case FFI_TYPE_SINT64:
     116      case FFI_TYPE_UINT64:
     117        flags = X86_RET_INT64;
     118        break;
     119      case FFI_TYPE_STRUCT:
     120  #ifndef X86
     121        /* ??? This should be a different ABI rather than an ifdef.  */
     122        if (cif->rtype->size == 1)
     123  	flags = X86_RET_STRUCT_1B;
     124        else if (cif->rtype->size == 2)
     125  	flags = X86_RET_STRUCT_2B;
     126        else if (cif->rtype->size == 4)
     127  	flags = X86_RET_INT32;
     128        else if (cif->rtype->size == 8)
     129  	flags = X86_RET_INT64;
     130        else
     131  #endif
     132  	{
     133  	do_struct:
     134  	  switch (cabi)
     135  	    {
     136  	    case FFI_THISCALL:
     137  	    case FFI_FASTCALL:
     138  	    case FFI_STDCALL:
     139  	    case FFI_MS_CDECL:
     140  	      flags = X86_RET_STRUCTARG;
     141  	      break;
     142  	    default:
     143  	      flags = X86_RET_STRUCTPOP;
     144  	      break;
     145  	    }
     146  	  /* Allocate space for return value pointer.  */
     147  	  bytes += FFI_ALIGN (sizeof(void*), FFI_SIZEOF_ARG);
     148  	}
     149        break;
     150      case FFI_TYPE_COMPLEX:
     151        switch (cif->rtype->elements[0]->type)
     152  	{
     153  	case FFI_TYPE_DOUBLE:
     154  	case FFI_TYPE_LONGDOUBLE:
     155  	case FFI_TYPE_SINT64:
     156  	case FFI_TYPE_UINT64:
     157  	  goto do_struct;
     158  	case FFI_TYPE_FLOAT:
     159  	case FFI_TYPE_INT:
     160  	case FFI_TYPE_SINT32:
     161  	case FFI_TYPE_UINT32:
     162  	  flags = X86_RET_INT64;
     163  	  break;
     164  	case FFI_TYPE_SINT16:
     165  	case FFI_TYPE_UINT16:
     166  	  flags = X86_RET_INT32;
     167  	  break;
     168  	case FFI_TYPE_SINT8:
     169  	case FFI_TYPE_UINT8:
     170  	  flags = X86_RET_STRUCT_2B;
     171  	  break;
     172  	default:
     173  	  return FFI_BAD_TYPEDEF;
     174  	}
     175        break;
     176      default:
     177        return FFI_BAD_TYPEDEF;
     178      }
     179    cif->flags = flags;
     180  
     181    for (i = 0, n = cif->nargs; i < n; i++)
     182      {
     183        ffi_type *t = cif->arg_types[i];
     184  
     185        bytes = FFI_ALIGN (bytes, t->alignment);
     186        bytes += FFI_ALIGN (t->size, FFI_SIZEOF_ARG);
     187      }
     188    cif->bytes = bytes;
     189  
     190    return FFI_OK;
     191  }
     192  
     193  static ffi_arg
     194  extend_basic_type(void *arg, int type)
     195  {
     196    switch (type)
     197      {
     198      case FFI_TYPE_SINT8:
     199        return *(SINT8 *)arg;
     200      case FFI_TYPE_UINT8:
     201        return *(UINT8 *)arg;
     202      case FFI_TYPE_SINT16:
     203        return *(SINT16 *)arg;
     204      case FFI_TYPE_UINT16:
     205        return *(UINT16 *)arg;
     206  
     207      case FFI_TYPE_SINT32:
     208      case FFI_TYPE_UINT32:
     209      case FFI_TYPE_POINTER:
     210      case FFI_TYPE_FLOAT:
     211        return *(UINT32 *)arg;
     212  
     213      default:
     214        abort();
     215      }
     216  }
     217  
     218  struct call_frame
     219  {
     220    void *ebp;		/* 0 */
     221    void *retaddr;	/* 4 */
     222    void (*fn)(void);	/* 8 */
     223    int flags;		/* 12 */
     224    void *rvalue;		/* 16 */
     225    unsigned regs[3];	/* 20-28 */
     226  };
     227  
     228  struct abi_params
     229  {
     230    int dir;		/* parameter growth direction */
     231    int static_chain;	/* the static chain register used by gcc */
     232    int nregs;		/* number of register parameters */
     233    int regs[3];
     234  };
     235  
     236  static const struct abi_params abi_params[FFI_LAST_ABI] = {
     237    [FFI_SYSV] = { 1, R_ECX, 0 },
     238    [FFI_THISCALL] = { 1, R_EAX, 1, { R_ECX } },
     239    [FFI_FASTCALL] = { 1, R_EAX, 2, { R_ECX, R_EDX } },
     240    [FFI_STDCALL] = { 1, R_ECX, 0 },
     241    [FFI_PASCAL] = { -1, R_ECX, 0 },
     242    /* ??? No defined static chain; gcc does not support REGISTER.  */
     243    [FFI_REGISTER] = { -1, R_ECX, 3, { R_EAX, R_EDX, R_ECX } },
     244    [FFI_MS_CDECL] = { 1, R_ECX, 0 }
     245  };
     246  
     247  #ifdef HAVE_FASTCALL
     248    #ifdef _MSC_VER
     249      #define FFI_DECLARE_FASTCALL __fastcall
     250    #else
     251      #define FFI_DECLARE_FASTCALL __declspec(fastcall)
     252    #endif
     253  #else
     254    #define FFI_DECLARE_FASTCALL
     255  #endif
     256  
     257  extern void FFI_DECLARE_FASTCALL ffi_call_i386(struct call_frame *, char *) FFI_HIDDEN;
     258  
     259  /* We perform some black magic here to use some of the parent's stack frame in
     260   * ffi_call_i386() that breaks with the MSVC compiler with the /RTCs or /GZ
     261   * flags.  Disable the 'Stack frame run time error checking' for this function
     262   * so we don't hit weird exceptions in debug builds. */
     263  #if defined(_MSC_VER)
     264  #pragma runtime_checks("s", off)
     265  #endif
     266  static void
     267  ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
     268  	      void **avalue, void *closure)
     269  {
     270    size_t rsize, bytes;
     271    struct call_frame *frame;
     272    char *stack, *argp;
     273    ffi_type **arg_types;
     274    int flags, cabi, i, n, dir, narg_reg;
     275    const struct abi_params *pabi;
     276  
     277    flags = cif->flags;
     278    cabi = cif->abi;
     279    pabi = &abi_params[cabi];
     280    dir = pabi->dir;
     281  
     282    rsize = 0;
     283    if (rvalue == NULL)
     284      {
     285        switch (flags)
     286  	{
     287  	case X86_RET_FLOAT:
     288  	case X86_RET_DOUBLE:
     289  	case X86_RET_LDOUBLE:
     290  	case X86_RET_STRUCTPOP:
     291  	case X86_RET_STRUCTARG:
     292  	  /* The float cases need to pop the 387 stack.
     293  	     The struct cases need to pass a valid pointer to the callee.  */
     294  	  rsize = cif->rtype->size;
     295  	  break;
     296  	default:
     297  	  /* We can pretend that the callee returns nothing.  */
     298  	  flags = X86_RET_VOID;
     299  	  break;
     300  	}
     301      }
     302  
     303    bytes = STACK_ALIGN (cif->bytes);
     304    stack = alloca(bytes + sizeof(*frame) + rsize);
     305    argp = (dir < 0 ? stack + bytes : stack);
     306    frame = (struct call_frame *)(stack + bytes);
     307    if (rsize)
     308      rvalue = frame + 1;
     309  
     310    frame->fn = fn;
     311    frame->flags = flags;
     312    frame->rvalue = rvalue;
     313    frame->regs[pabi->static_chain] = (unsigned)closure;
     314  
     315    narg_reg = 0;
     316    switch (flags)
     317      {
     318      case X86_RET_STRUCTARG:
     319        /* The pointer is passed as the first argument.  */
     320        if (pabi->nregs > 0)
     321  	{
     322  	  frame->regs[pabi->regs[0]] = (unsigned)rvalue;
     323  	  narg_reg = 1;
     324  	  break;
     325  	}
     326        /* fallthru */
     327      case X86_RET_STRUCTPOP:
     328        *(void **)argp = rvalue;
     329        argp += sizeof(void *);
     330        break;
     331      }
     332  
     333    arg_types = cif->arg_types;
     334    for (i = 0, n = cif->nargs; i < n; i++)
     335      {
     336        ffi_type *ty = arg_types[i];
     337        void *valp = avalue[i];
     338        size_t z = ty->size;
     339        int t = ty->type;
     340  
     341        if (z <= FFI_SIZEOF_ARG && t != FFI_TYPE_STRUCT)
     342          {
     343  	  ffi_arg val = extend_basic_type (valp, t);
     344  
     345  	  if (t != FFI_TYPE_FLOAT && narg_reg < pabi->nregs)
     346  	    frame->regs[pabi->regs[narg_reg++]] = val;
     347  	  else if (dir < 0)
     348  	    {
     349  	      argp -= 4;
     350  	      *(ffi_arg *)argp = val;
     351  	    }
     352  	  else
     353  	    {
     354  	      *(ffi_arg *)argp = val;
     355  	      argp += 4;
     356  	    }
     357  	}
     358        else
     359  	{
     360  	  size_t za = FFI_ALIGN (z, FFI_SIZEOF_ARG);
     361  	  size_t align = FFI_SIZEOF_ARG;
     362  
     363  	  /* Issue 434: For thiscall and fastcall, if the paramter passed
     364  	     as 64-bit integer or struct, all following integer parameters
     365  	     will be passed on stack.  */
     366  	  if ((cabi == FFI_THISCALL || cabi == FFI_FASTCALL)
     367  	      && (t == FFI_TYPE_SINT64
     368  		  || t == FFI_TYPE_UINT64
     369  		  || t == FFI_TYPE_STRUCT))
     370  	    narg_reg = 2;
     371  
     372  	  /* Alignment rules for arguments are quite complex.  Vectors and
     373  	     structures with 16 byte alignment get it.  Note that long double
     374  	     on Darwin does have 16 byte alignment, and does not get this
     375  	     alignment if passed directly; a structure with a long double
     376  	     inside, however, would get 16 byte alignment.  Since libffi does
     377  	     not support vectors, we need non concern ourselves with other
     378  	     cases.  */
     379  	  if (t == FFI_TYPE_STRUCT && ty->alignment >= 16)
     380  	    align = 16;
     381  	    
     382  	  if (dir < 0)
     383  	    {
     384  	      /* ??? These reverse argument ABIs are probably too old
     385  		 to have cared about alignment.  Someone should check.  */
     386  	      argp -= za;
     387  	      memcpy (argp, valp, z);
     388  	    }
     389  	  else
     390  	    {
     391  	      argp = (char *)FFI_ALIGN (argp, align);
     392  	      memcpy (argp, valp, z);
     393  	      argp += za;
     394  	    }
     395  	}
     396      }
     397    FFI_ASSERT (dir > 0 || argp == stack);
     398  
     399    ffi_call_i386 (frame, stack);
     400  }
     401  #if defined(_MSC_VER)
     402  #pragma runtime_checks("s", restore)
     403  #endif
     404  
     405  void
     406  ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
     407  {
     408    ffi_call_int (cif, fn, rvalue, avalue, NULL);
     409  }
     410  
     411  #ifdef FFI_GO_CLOSURES
     412  void
     413  ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
     414  	     void **avalue, void *closure)
     415  {
     416    ffi_call_int (cif, fn, rvalue, avalue, closure);
     417  }
     418  #endif
     419  
     420  /** private members **/
     421  
     422  void FFI_HIDDEN ffi_closure_i386(void);
     423  void FFI_HIDDEN ffi_closure_STDCALL(void);
     424  void FFI_HIDDEN ffi_closure_REGISTER(void);
     425  #if defined(FFI_EXEC_STATIC_TRAMP)
     426  void FFI_HIDDEN ffi_closure_i386_alt(void);
     427  void FFI_HIDDEN ffi_closure_STDCALL_alt(void);
     428  void FFI_HIDDEN ffi_closure_REGISTER_alt(void);
     429  #endif
     430  
     431  struct closure_frame
     432  {
     433    unsigned rettemp[4];				/* 0 */
     434    unsigned regs[3];				/* 16-24 */
     435    ffi_cif *cif;					/* 28 */
     436    void (*fun)(ffi_cif*,void*,void**,void*);	/* 32 */
     437    void *user_data;				/* 36 */
     438  };
     439  
     440  int FFI_HIDDEN FFI_DECLARE_FASTCALL
     441  ffi_closure_inner (struct closure_frame *frame, char *stack)
     442  {
     443    ffi_cif *cif = frame->cif;
     444    int cabi, i, n, flags, dir, narg_reg;
     445    const struct abi_params *pabi;
     446    ffi_type **arg_types;
     447    char *argp;
     448    void *rvalue;
     449    void **avalue;
     450  
     451    cabi = cif->abi;
     452    flags = cif->flags;
     453    narg_reg = 0;
     454    rvalue = frame->rettemp;
     455    pabi = &abi_params[cabi];
     456    dir = pabi->dir;
     457    argp = (dir < 0 ? stack + STACK_ALIGN (cif->bytes) : stack);
     458  
     459    switch (flags)
     460      {
     461      case X86_RET_STRUCTARG:
     462        if (pabi->nregs > 0)
     463  	{
     464  	  rvalue = (void *)frame->regs[pabi->regs[0]];
     465  	  narg_reg = 1;
     466  	  frame->rettemp[0] = (unsigned)rvalue;
     467  	  break;
     468  	}
     469        /* fallthru */
     470      case X86_RET_STRUCTPOP:
     471        rvalue = *(void **)argp;
     472        argp += sizeof(void *);
     473        frame->rettemp[0] = (unsigned)rvalue;
     474        break;
     475      }
     476  
     477    n = cif->nargs;
     478    avalue = alloca(sizeof(void *) * n);
     479  
     480    arg_types = cif->arg_types;
     481    for (i = 0; i < n; ++i)
     482      {
     483        ffi_type *ty = arg_types[i];
     484        size_t z = ty->size;
     485        int t = ty->type;
     486        void *valp;
     487  
     488        if (z <= FFI_SIZEOF_ARG && t != FFI_TYPE_STRUCT)
     489  	{
     490  	  if (t != FFI_TYPE_FLOAT && narg_reg < pabi->nregs)
     491  	    valp = &frame->regs[pabi->regs[narg_reg++]];
     492  	  else if (dir < 0)
     493  	    {
     494  	      argp -= 4;
     495  	      valp = argp;
     496  	    }
     497  	  else
     498  	    {
     499  	      valp = argp;
     500  	      argp += 4;
     501  	    }
     502  	}
     503        else
     504  	{
     505  	  size_t za = FFI_ALIGN (z, FFI_SIZEOF_ARG);
     506  	  size_t align = FFI_SIZEOF_ARG;
     507  
     508  	  /* See the comment in ffi_call_int.  */
     509  	  if (t == FFI_TYPE_STRUCT && ty->alignment >= 16)
     510  	    align = 16;
     511  
     512  	  /* Issue 434: For thiscall and fastcall, if the paramter passed
     513  	     as 64-bit integer or struct, all following integer parameters
     514  	     will be passed on stack.  */
     515  	  if ((cabi == FFI_THISCALL || cabi == FFI_FASTCALL)
     516  	      && (t == FFI_TYPE_SINT64
     517  		  || t == FFI_TYPE_UINT64
     518  		  || t == FFI_TYPE_STRUCT))
     519  	    narg_reg = 2;
     520  
     521  	  if (dir < 0)
     522  	    {
     523  	      /* ??? These reverse argument ABIs are probably too old
     524  		 to have cared about alignment.  Someone should check.  */
     525  	      argp -= za;
     526  	      valp = argp;
     527  	    }
     528  	  else
     529  	    {
     530  	      argp = (char *)FFI_ALIGN (argp, align);
     531  	      valp = argp;
     532  	      argp += za;
     533  	    }
     534  	}
     535  
     536        avalue[i] = valp;
     537      }
     538  
     539    frame->fun (cif, rvalue, avalue, frame->user_data);
     540  
     541    switch (cabi)
     542      {
     543      case FFI_STDCALL:
     544        return flags | (cif->bytes << X86_RET_POP_SHIFT);
     545      case FFI_THISCALL:
     546      case FFI_FASTCALL:
     547        return flags | ((cif->bytes - (narg_reg * FFI_SIZEOF_ARG))
     548            << X86_RET_POP_SHIFT);
     549      default:
     550        return flags;
     551      }
     552  }
     553  
     554  ffi_status
     555  ffi_prep_closure_loc (ffi_closure* closure,
     556                        ffi_cif* cif,
     557                        void (*fun)(ffi_cif*,void*,void**,void*),
     558                        void *user_data,
     559                        void *codeloc)
     560  {
     561    char *tramp = closure->tramp;
     562    void (*dest)(void);
     563    int op = 0xb8;  /* movl imm, %eax */
     564  
     565    switch (cif->abi)
     566      {
     567      case FFI_SYSV:
     568      case FFI_MS_CDECL:
     569        dest = ffi_closure_i386;
     570        break;
     571      case FFI_STDCALL:
     572      case FFI_THISCALL:
     573      case FFI_FASTCALL:
     574      case FFI_PASCAL:
     575        dest = ffi_closure_STDCALL;
     576        break;
     577      case FFI_REGISTER:
     578        dest = ffi_closure_REGISTER;
     579        op = 0x68;  /* pushl imm */
     580        break;
     581      default:
     582        return FFI_BAD_ABI;
     583      }
     584  
     585  #if defined(FFI_EXEC_STATIC_TRAMP)
     586    if (ffi_tramp_is_present(closure))
     587      {
     588        /* Initialize the static trampoline's parameters. */
     589        if (dest == ffi_closure_i386)
     590          dest = ffi_closure_i386_alt;
     591        else if (dest == ffi_closure_STDCALL)
     592          dest = ffi_closure_STDCALL_alt;
     593        else
     594          dest = ffi_closure_REGISTER_alt;
     595        ffi_tramp_set_parms (closure->ftramp, dest, closure);
     596        goto out;
     597      }
     598  #endif
     599  
     600    /* Initialize the dynamic trampoline. */
     601    /* endbr32.  */
     602    *(UINT32 *) tramp = 0xfb1e0ff3;
     603  
     604    /* movl or pushl immediate.  */
     605    tramp[4] = op;
     606    *(void **)(tramp + 5) = codeloc;
     607  
     608    /* jmp dest */
     609    tramp[9] = 0xe9;
     610    *(unsigned *)(tramp + 10) = (unsigned)dest - ((unsigned)codeloc + 14);
     611  
     612  out:
     613    closure->cif = cif;
     614    closure->fun = fun;
     615    closure->user_data = user_data;
     616  
     617    return FFI_OK;
     618  }
     619  
     620  #ifdef FFI_GO_CLOSURES
     621  
     622  void FFI_HIDDEN ffi_go_closure_EAX(void);
     623  void FFI_HIDDEN ffi_go_closure_ECX(void);
     624  void FFI_HIDDEN ffi_go_closure_STDCALL(void);
     625  
     626  ffi_status
     627  ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif,
     628  		     void (*fun)(ffi_cif*,void*,void**,void*))
     629  {
     630    void (*dest)(void);
     631  
     632    switch (cif->abi)
     633      {
     634      case FFI_SYSV:
     635      case FFI_MS_CDECL:
     636        dest = ffi_go_closure_ECX;
     637        break;
     638      case FFI_THISCALL:
     639      case FFI_FASTCALL:
     640        dest = ffi_go_closure_EAX;
     641        break;
     642      case FFI_STDCALL:
     643      case FFI_PASCAL:
     644        dest = ffi_go_closure_STDCALL;
     645        break;
     646      case FFI_REGISTER:
     647      default:
     648        return FFI_BAD_ABI;
     649      }
     650  
     651    closure->tramp = dest;
     652    closure->cif = cif;
     653    closure->fun = fun;
     654  
     655    return FFI_OK;
     656  }
     657  
     658  #endif /* FFI_GO_CLOSURES */
     659  
     660  /* ------- Native raw API support -------------------------------- */
     661  
     662  #if !FFI_NO_RAW_API
     663  
     664  void FFI_HIDDEN ffi_closure_raw_SYSV(void);
     665  void FFI_HIDDEN ffi_closure_raw_THISCALL(void);
     666  
     667  ffi_status
     668  ffi_prep_raw_closure_loc (ffi_raw_closure *closure,
     669                            ffi_cif *cif,
     670                            void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
     671                            void *user_data,
     672                            void *codeloc)
     673  {
     674    char *tramp = closure->tramp;
     675    void (*dest)(void);
     676    int i;
     677  
     678    /* We currently don't support certain kinds of arguments for raw
     679       closures.  This should be implemented by a separate assembly
     680       language routine, since it would require argument processing,
     681       something we don't do now for performance.  */
     682    for (i = cif->nargs-1; i >= 0; i--)
     683      switch (cif->arg_types[i]->type)
     684        {
     685        case FFI_TYPE_STRUCT:
     686        case FFI_TYPE_LONGDOUBLE:
     687  	return FFI_BAD_TYPEDEF;
     688        }
     689  
     690    switch (cif->abi)
     691      {
     692      case FFI_THISCALL:
     693        dest = ffi_closure_raw_THISCALL;
     694        break;
     695      case FFI_SYSV:
     696        dest = ffi_closure_raw_SYSV;
     697        break;
     698      default:
     699        return FFI_BAD_ABI;
     700      }
     701  
     702    /* movl imm, %eax.  */
     703    tramp[0] = 0xb8;
     704    *(void **)(tramp + 1) = codeloc;
     705  
     706    /* jmp dest */
     707    tramp[5] = 0xe9;
     708    *(unsigned *)(tramp + 6) = (unsigned)dest - ((unsigned)codeloc + 10);
     709  
     710    closure->cif = cif;
     711    closure->fun = fun;
     712    closure->user_data = user_data;
     713  
     714    return FFI_OK;
     715  }
     716  
     717  void
     718  ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *avalue)
     719  {
     720    size_t rsize, bytes;
     721    struct call_frame *frame;
     722    char *stack, *argp;
     723    ffi_type **arg_types;
     724    int flags, cabi, i, n, narg_reg;
     725    const struct abi_params *pabi;
     726  
     727    flags = cif->flags;
     728    cabi = cif->abi;
     729    pabi = &abi_params[cabi];
     730  
     731    rsize = 0;
     732    if (rvalue == NULL)
     733      {
     734        switch (flags)
     735  	{
     736  	case X86_RET_FLOAT:
     737  	case X86_RET_DOUBLE:
     738  	case X86_RET_LDOUBLE:
     739  	case X86_RET_STRUCTPOP:
     740  	case X86_RET_STRUCTARG:
     741  	  /* The float cases need to pop the 387 stack.
     742  	     The struct cases need to pass a valid pointer to the callee.  */
     743  	  rsize = cif->rtype->size;
     744  	  break;
     745  	default:
     746  	  /* We can pretend that the callee returns nothing.  */
     747  	  flags = X86_RET_VOID;
     748  	  break;
     749  	}
     750      }
     751  
     752    bytes = STACK_ALIGN (cif->bytes);
     753    argp = stack =
     754        (void *)((uintptr_t)alloca(bytes + sizeof(*frame) + rsize + 15) & ~16);
     755    frame = (struct call_frame *)(stack + bytes);
     756    if (rsize)
     757      rvalue = frame + 1;
     758  
     759    frame->fn = fn;
     760    frame->flags = flags;
     761    frame->rvalue = rvalue;
     762  
     763    narg_reg = 0;
     764    switch (flags)
     765      {
     766      case X86_RET_STRUCTARG:
     767        /* The pointer is passed as the first argument.  */
     768        if (pabi->nregs > 0)
     769  	{
     770  	  frame->regs[pabi->regs[0]] = (unsigned)rvalue;
     771  	  narg_reg = 1;
     772  	  break;
     773  	}
     774        /* fallthru */
     775      case X86_RET_STRUCTPOP:
     776        *(void **)argp = rvalue;
     777        argp += sizeof(void *);
     778        bytes -= sizeof(void *);
     779        break;
     780      }
     781  
     782    arg_types = cif->arg_types;
     783    for (i = 0, n = cif->nargs; narg_reg < pabi->nregs && i < n; i++)
     784      {
     785        ffi_type *ty = arg_types[i];
     786        size_t z = ty->size;
     787        int t = ty->type;
     788  
     789        if (z <= FFI_SIZEOF_ARG && t != FFI_TYPE_STRUCT && t != FFI_TYPE_FLOAT)
     790  	{
     791  	  ffi_arg val = extend_basic_type (avalue, t);
     792  	  frame->regs[pabi->regs[narg_reg++]] = val;
     793  	  z = FFI_SIZEOF_ARG;
     794  	}
     795        else
     796  	{
     797  	  memcpy (argp, avalue, z);
     798  	  z = FFI_ALIGN (z, FFI_SIZEOF_ARG);
     799  	  argp += z;
     800  	}
     801        avalue += z;
     802        bytes -= z;
     803      }
     804    if (i < n)
     805      memcpy (argp, avalue, bytes);
     806  
     807    ffi_call_i386 (frame, stack);
     808  }
     809  #endif /* !FFI_NO_RAW_API */
     810  
     811  #if defined(FFI_EXEC_STATIC_TRAMP)
     812  void *
     813  ffi_tramp_arch (size_t *tramp_size, size_t *map_size)
     814  {
     815    extern void *trampoline_code_table;
     816  
     817    *map_size = X86_TRAMP_MAP_SIZE;
     818    *tramp_size = X86_TRAMP_SIZE;
     819    return &trampoline_code_table;
     820  }
     821  #endif
     822  
     823  #endif /* __i386__ */