diff options
| author | Raghuram Subramani <raghus2247@gmail.com> | 2022-06-19 19:47:51 +0530 | 
|---|---|---|
| committer | Raghuram Subramani <raghus2247@gmail.com> | 2022-06-19 19:47:51 +0530 | 
| commit | 4fd287655a72b9aea14cdac715ad5b90ed082ed2 (patch) | |
| tree | 65d393bc0e699dd12d05b29ba568e04cea666207 /circuitpython/lib/libffi/src/x86/ffi.c | |
| parent | 0150f70ce9c39e9e6dd878766c0620c85e47bed0 (diff) | |
add circuitpython code
Diffstat (limited to 'circuitpython/lib/libffi/src/x86/ffi.c')
| -rw-r--r-- | circuitpython/lib/libffi/src/x86/ffi.c | 729 | 
1 files changed, 729 insertions, 0 deletions
| diff --git a/circuitpython/lib/libffi/src/x86/ffi.c b/circuitpython/lib/libffi/src/x86/ffi.c new file mode 100644 index 0000000..feb5cbb --- /dev/null +++ b/circuitpython/lib/libffi/src/x86/ffi.c @@ -0,0 +1,729 @@ +/* ----------------------------------------------------------------------- +   ffi.c - Copyright (c) 1996, 1998, 1999, 2001, 2007, 2008  Red Hat, Inc. +           Copyright (c) 2002  Ranjit Mathew +           Copyright (c) 2002  Bo Thorsen +           Copyright (c) 2002  Roger Sayle +           Copyright (C) 2008, 2010  Free Software Foundation, Inc. + +   x86 Foreign Function Interface + +   Permission is hereby granted, free of charge, to any person obtaining +   a copy of this software and associated documentation files (the +   ``Software''), to deal in the Software without restriction, including +   without limitation the rights to use, copy, modify, merge, publish, +   distribute, sublicense, and/or sell copies of the Software, and to +   permit persons to whom the Software is furnished to do so, subject to +   the following conditions: + +   The above copyright notice and this permission notice shall be included +   in all copies or substantial portions of the Software. + +   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, +   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +   DEALINGS IN THE SOFTWARE. +   ----------------------------------------------------------------------- */ + +#ifndef __x86_64__ +#include <ffi.h> +#include <ffi_common.h> +#include <stdlib.h> +#include "internal.h" + +/* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE; +   all further uses in this file will refer to the 80-bit type.  */ +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE +# if FFI_TYPE_LONGDOUBLE != 4 +#  error FFI_TYPE_LONGDOUBLE out of date +# endif +#else +# undef FFI_TYPE_LONGDOUBLE +# define FFI_TYPE_LONGDOUBLE 4 +#endif + +#if defined(__GNUC__) && !defined(__declspec) +# define __declspec(x)  __attribute__((x)) +#endif + +/* Perform machine dependent cif processing.  */ +ffi_status FFI_HIDDEN +ffi_prep_cif_machdep(ffi_cif *cif) +{ +  size_t bytes = 0; +  int i, n, flags, cabi = cif->abi; + +  switch (cabi) +    { +    case FFI_SYSV: +    case FFI_STDCALL: +    case FFI_THISCALL: +    case FFI_FASTCALL: +    case FFI_MS_CDECL: +    case FFI_PASCAL: +    case FFI_REGISTER: +      break; +    default: +      return FFI_BAD_ABI; +    } + +  switch (cif->rtype->type) +    { +    case FFI_TYPE_VOID: +      flags = X86_RET_VOID; +      break; +    case FFI_TYPE_FLOAT: +      flags = X86_RET_FLOAT; +      break; +    case FFI_TYPE_DOUBLE: +      flags = X86_RET_DOUBLE; +      break; +    case FFI_TYPE_LONGDOUBLE: +      flags = X86_RET_LDOUBLE; +      break; +    case FFI_TYPE_UINT8: +      flags = X86_RET_UINT8; +      break; +    case FFI_TYPE_UINT16: +      flags = X86_RET_UINT16; +      break; +    case FFI_TYPE_SINT8: +      flags = X86_RET_SINT8; +      break; +    case FFI_TYPE_SINT16: +      flags = X86_RET_SINT16; +      break; +    case FFI_TYPE_INT: +    case FFI_TYPE_SINT32: +    case FFI_TYPE_UINT32: +    case FFI_TYPE_POINTER: +      flags = X86_RET_INT32; +      break; +    case FFI_TYPE_SINT64: +    case FFI_TYPE_UINT64: +      flags = X86_RET_INT64; +      break; +    case FFI_TYPE_STRUCT: +#ifndef X86 +      /* ??? This should be a different ABI rather than an ifdef.  */ +      if (cif->rtype->size == 1) +	flags = X86_RET_STRUCT_1B; +      else if (cif->rtype->size == 2) +	flags = X86_RET_STRUCT_2B; +      else if (cif->rtype->size == 4) +	flags = X86_RET_INT32; +      else if (cif->rtype->size == 8) +	flags = X86_RET_INT64; +      else +#endif +	{ +	do_struct: +	  switch (cabi) +	    { +	    case FFI_THISCALL: +	    case FFI_FASTCALL: +	    case FFI_STDCALL: +	    case FFI_MS_CDECL: +	      flags = X86_RET_STRUCTARG; +	      break; +	    default: +	      flags = X86_RET_STRUCTPOP; +	      break; +	    } +	  /* Allocate space for return value pointer.  */ +	  bytes += ALIGN (sizeof(void*), FFI_SIZEOF_ARG); +	} +      break; +    case FFI_TYPE_COMPLEX: +      switch (cif->rtype->elements[0]->type) +	{ +	case FFI_TYPE_DOUBLE: +	case FFI_TYPE_LONGDOUBLE: +	case FFI_TYPE_SINT64: +	case FFI_TYPE_UINT64: +	  goto do_struct; +	case FFI_TYPE_FLOAT: +	case FFI_TYPE_INT: +	case FFI_TYPE_SINT32: +	case FFI_TYPE_UINT32: +	  flags = X86_RET_INT64; +	  break; +	case FFI_TYPE_SINT16: +	case FFI_TYPE_UINT16: +	  flags = X86_RET_INT32; +	  break; +	case FFI_TYPE_SINT8: +	case FFI_TYPE_UINT8: +	  flags = X86_RET_STRUCT_2B; +	  break; +	default: +	  return FFI_BAD_TYPEDEF; +	} +      break; +    default: +      return FFI_BAD_TYPEDEF; +    } +  cif->flags = flags; + +  for (i = 0, n = cif->nargs; i < n; i++) +    { +      ffi_type *t = cif->arg_types[i]; + +      bytes = ALIGN (bytes, t->alignment); +      bytes += ALIGN (t->size, FFI_SIZEOF_ARG); +    } +  cif->bytes = ALIGN (bytes, 16); + +  return FFI_OK; +} + +static ffi_arg +extend_basic_type(void *arg, int type) +{ +  switch (type) +    { +    case FFI_TYPE_SINT8: +      return *(SINT8 *)arg; +    case FFI_TYPE_UINT8: +      return *(UINT8 *)arg; +    case FFI_TYPE_SINT16: +      return *(SINT16 *)arg; +    case FFI_TYPE_UINT16: +      return *(UINT16 *)arg; + +    case FFI_TYPE_SINT32: +    case FFI_TYPE_UINT32: +    case FFI_TYPE_POINTER: +    case FFI_TYPE_FLOAT: +      return *(UINT32 *)arg; + +    default: +      abort(); +    } +} + +struct call_frame +{ +  void *ebp;		/* 0 */ +  void *retaddr;	/* 4 */ +  void (*fn)(void);	/* 8 */ +  int flags;		/* 12 */ +  void *rvalue;		/* 16 */ +  unsigned regs[3];	/* 20-28 */ +}; + +struct abi_params +{ +  int dir;		/* parameter growth direction */ +  int static_chain;	/* the static chain register used by gcc */ +  int nregs;		/* number of register parameters */ +  int regs[3]; +}; + +static const struct abi_params abi_params[FFI_LAST_ABI] = { +  [FFI_SYSV] = { 1, R_ECX, 0 }, +  [FFI_THISCALL] = { 1, R_EAX, 1, { R_ECX } }, +  [FFI_FASTCALL] = { 1, R_EAX, 2, { R_ECX, R_EDX } }, +  [FFI_STDCALL] = { 1, R_ECX, 0 }, +  [FFI_PASCAL] = { -1, R_ECX, 0 }, +  /* ??? No defined static chain; gcc does not support REGISTER.  */ +  [FFI_REGISTER] = { -1, R_ECX, 3, { R_EAX, R_EDX, R_ECX } }, +  [FFI_MS_CDECL] = { 1, R_ECX, 0 } +}; + +extern void ffi_call_i386(struct call_frame *, char *) +#if HAVE_FASTCALL +	__declspec(fastcall) +#endif +	FFI_HIDDEN; + +static void +ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue, +	      void **avalue, void *closure) +{ +  size_t rsize, bytes; +  struct call_frame *frame; +  char *stack, *argp; +  ffi_type **arg_types; +  int flags, cabi, i, n, dir, narg_reg; +  const struct abi_params *pabi; + +  flags = cif->flags; +  cabi = cif->abi; +  pabi = &abi_params[cabi]; +  dir = pabi->dir; + +  rsize = 0; +  if (rvalue == NULL) +    { +      switch (flags) +	{ +	case X86_RET_FLOAT: +	case X86_RET_DOUBLE: +	case X86_RET_LDOUBLE: +	case X86_RET_STRUCTPOP: +	case X86_RET_STRUCTARG: +	  /* The float cases need to pop the 387 stack. +	     The struct cases need to pass a valid pointer to the callee.  */ +	  rsize = cif->rtype->size; +	  break; +	default: +	  /* We can pretend that the callee returns nothing.  */ +	  flags = X86_RET_VOID; +	  break; +	} +    } + +  bytes = cif->bytes; +  stack = alloca(bytes + sizeof(*frame) + rsize); +  argp = (dir < 0 ? stack + bytes : stack); +  frame = (struct call_frame *)(stack + bytes); +  if (rsize) +    rvalue = frame + 1; + +  frame->fn = fn; +  frame->flags = flags; +  frame->rvalue = rvalue; +  frame->regs[pabi->static_chain] = (unsigned)closure; + +  narg_reg = 0; +  switch (flags) +    { +    case X86_RET_STRUCTARG: +      /* The pointer is passed as the first argument.  */ +      if (pabi->nregs > 0) +	{ +	  frame->regs[pabi->regs[0]] = (unsigned)rvalue; +	  narg_reg = 1; +	  break; +	} +      /* fallthru */ +    case X86_RET_STRUCTPOP: +      *(void **)argp = rvalue; +      argp += sizeof(void *); +      break; +    } + +  arg_types = cif->arg_types; +  for (i = 0, n = cif->nargs; i < n; i++) +    { +      ffi_type *ty = arg_types[i]; +      void *valp = avalue[i]; +      size_t z = ty->size; +      int t = ty->type; + +      if (z <= FFI_SIZEOF_ARG && t != FFI_TYPE_STRUCT) +        { +	  ffi_arg val = extend_basic_type (valp, t); + +	  if (t != FFI_TYPE_FLOAT && narg_reg < pabi->nregs) +	    frame->regs[pabi->regs[narg_reg++]] = val; +	  else if (dir < 0) +	    { +	      argp -= 4; +	      *(ffi_arg *)argp = val; +	    } +	  else +	    { +	      *(ffi_arg *)argp = val; +	      argp += 4; +	    } +	} +      else +	{ +	  size_t za = ALIGN (z, FFI_SIZEOF_ARG); +	  size_t align = FFI_SIZEOF_ARG; + +	  /* Alignment rules for arguments are quite complex.  Vectors and +	     structures with 16 byte alignment get it.  Note that long double +	     on Darwin does have 16 byte alignment, and does not get this +	     alignment if passed directly; a structure with a long double +	     inside, however, would get 16 byte alignment.  Since libffi does +	     not support vectors, we need non concern ourselves with other +	     cases.  */ +	  if (t == FFI_TYPE_STRUCT && ty->alignment >= 16) +	    align = 16; +	     +	  if (dir < 0) +	    { +	      /* ??? These reverse argument ABIs are probably too old +		 to have cared about alignment.  Someone should check.  */ +	      argp -= za; +	      memcpy (argp, valp, z); +	    } +	  else +	    { +	      argp = (char *)ALIGN (argp, align); +	      memcpy (argp, valp, z); +	      argp += za; +	    } +	} +    } +  FFI_ASSERT (dir > 0 || argp == stack); + +  ffi_call_i386 (frame, stack); +} + +void +ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +{ +  ffi_call_int (cif, fn, rvalue, avalue, NULL); +} + +void +ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue, +	     void **avalue, void *closure) +{ +  ffi_call_int (cif, fn, rvalue, avalue, closure); +} + +/** private members **/ + +void FFI_HIDDEN ffi_closure_i386(void); +void FFI_HIDDEN ffi_closure_STDCALL(void); +void FFI_HIDDEN ffi_closure_REGISTER(void); + +struct closure_frame +{ +  unsigned rettemp[4];				/* 0 */ +  unsigned regs[3];				/* 16-24 */ +  ffi_cif *cif;					/* 28 */ +  void (*fun)(ffi_cif*,void*,void**,void*);	/* 32 */ +  void *user_data;				/* 36 */ +}; + +int FFI_HIDDEN +#if HAVE_FASTCALL +__declspec(fastcall) +#endif +ffi_closure_inner (struct closure_frame *frame, char *stack) +{ +  ffi_cif *cif = frame->cif; +  int cabi, i, n, flags, dir, narg_reg; +  const struct abi_params *pabi; +  ffi_type **arg_types; +  char *argp; +  void *rvalue; +  void **avalue; + +  cabi = cif->abi; +  flags = cif->flags; +  narg_reg = 0; +  rvalue = frame->rettemp; +  pabi = &abi_params[cabi]; +  dir = pabi->dir; +  argp = (dir < 0 ? stack + cif->bytes : stack); + +  switch (flags) +    { +    case X86_RET_STRUCTARG: +      if (pabi->nregs > 0) +	{ +	  rvalue = (void *)frame->regs[pabi->regs[0]]; +	  narg_reg = 1; +	  frame->rettemp[0] = (unsigned)rvalue; +	  break; +	} +      /* fallthru */ +    case X86_RET_STRUCTPOP: +      rvalue = *(void **)argp; +      argp += sizeof(void *); +      frame->rettemp[0] = (unsigned)rvalue; +      break; +    } + +  n = cif->nargs; +  avalue = alloca(sizeof(void *) * n); + +  arg_types = cif->arg_types; +  for (i = 0; i < n; ++i) +    { +      ffi_type *ty = arg_types[i]; +      size_t z = ty->size; +      int t = ty->type; +      void *valp; + +      if (z <= FFI_SIZEOF_ARG && t != FFI_TYPE_STRUCT) +	{ +	  if (t != FFI_TYPE_FLOAT && narg_reg < pabi->nregs) +	    valp = &frame->regs[pabi->regs[narg_reg++]]; +	  else if (dir < 0) +	    { +	      argp -= 4; +	      valp = argp; +	    } +	  else +	    { +	      valp = argp; +	      argp += 4; +	    } +	} +      else +	{ +	  size_t za = ALIGN (z, FFI_SIZEOF_ARG); +	  size_t align = FFI_SIZEOF_ARG; + +	  /* See the comment in ffi_call_int.  */ +	  if (t == FFI_TYPE_STRUCT && ty->alignment >= 16) +	    align = 16; + +	  if (dir < 0) +	    { +	      /* ??? These reverse argument ABIs are probably too old +		 to have cared about alignment.  Someone should check.  */ +	      argp -= za; +	      valp = argp; +	    } +	  else +	    { +	      argp = (char *)ALIGN (argp, align); +	      valp = argp; +	      argp += za; +	    } +	} + +      avalue[i] = valp; +    } + +  frame->fun (cif, rvalue, avalue, frame->user_data); + +  if (cabi == FFI_STDCALL) +    return flags + (cif->bytes << X86_RET_POP_SHIFT); +  else +    return flags; +} + +ffi_status +ffi_prep_closure_loc (ffi_closure* closure, +                      ffi_cif* cif, +                      void (*fun)(ffi_cif*,void*,void**,void*), +                      void *user_data, +                      void *codeloc) +{ +  char *tramp = closure->tramp; +  void (*dest)(void); +  int op = 0xb8;  /* movl imm, %eax */ + +  switch (cif->abi) +    { +    case FFI_SYSV: +    case FFI_THISCALL: +    case FFI_FASTCALL: +    case FFI_MS_CDECL: +      dest = ffi_closure_i386; +      break; +    case FFI_STDCALL: +    case FFI_PASCAL: +      dest = ffi_closure_STDCALL; +      break; +    case FFI_REGISTER: +      dest = ffi_closure_REGISTER; +      op = 0x68;  /* pushl imm */ +    default: +      return FFI_BAD_ABI; +    } + +  /* movl or pushl immediate.  */ +  tramp[0] = op; +  *(void **)(tramp + 1) = codeloc; + +  /* jmp dest */ +  tramp[5] = 0xe9; +  *(unsigned *)(tramp + 6) = (unsigned)dest - ((unsigned)codeloc + 10); + +  closure->cif = cif; +  closure->fun = fun; +  closure->user_data = user_data; + +  return FFI_OK; +} + +void FFI_HIDDEN ffi_go_closure_EAX(void); +void FFI_HIDDEN ffi_go_closure_ECX(void); +void FFI_HIDDEN ffi_go_closure_STDCALL(void); + +ffi_status +ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif, +		     void (*fun)(ffi_cif*,void*,void**,void*)) +{ +  void (*dest)(void); + +  switch (cif->abi) +    { +    case FFI_SYSV: +    case FFI_MS_CDECL: +      dest = ffi_go_closure_ECX; +      break; +    case FFI_THISCALL: +    case FFI_FASTCALL: +      dest = ffi_go_closure_EAX; +      break; +    case FFI_STDCALL: +    case FFI_PASCAL: +      dest = ffi_go_closure_STDCALL; +      break; +    case FFI_REGISTER: +    default: +      return FFI_BAD_ABI; +    } + +  closure->tramp = dest; +  closure->cif = cif; +  closure->fun = fun; + +  return FFI_OK; +} + +/* ------- Native raw API support -------------------------------- */ + +#if !FFI_NO_RAW_API + +void FFI_HIDDEN ffi_closure_raw_SYSV(void); +void FFI_HIDDEN ffi_closure_raw_THISCALL(void); + +ffi_status +ffi_prep_raw_closure_loc (ffi_raw_closure *closure, +                          ffi_cif *cif, +                          void (*fun)(ffi_cif*,void*,ffi_raw*,void*), +                          void *user_data, +                          void *codeloc) +{ +  char *tramp = closure->tramp; +  void (*dest)(void); +  int i; + +  /* We currently don't support certain kinds of arguments for raw +     closures.  This should be implemented by a separate assembly +     language routine, since it would require argument processing, +     something we don't do now for performance.  */ +  for (i = cif->nargs-1; i >= 0; i--) +    switch (cif->arg_types[i]->type) +      { +      case FFI_TYPE_STRUCT: +      case FFI_TYPE_LONGDOUBLE: +	return FFI_BAD_TYPEDEF; +      } + +  switch (cif->abi) +    { +    case FFI_THISCALL: +      dest = ffi_closure_raw_THISCALL; +      break; +    case FFI_SYSV: +      dest = ffi_closure_raw_SYSV; +      break; +    default: +      return FFI_BAD_ABI; +    } + +  /* movl imm, %eax.  */ +  tramp[0] = 0xb8; +  *(void **)(tramp + 1) = codeloc; + +  /* jmp dest */ +  tramp[5] = 0xe9; +  *(unsigned *)(tramp + 6) = (unsigned)dest - ((unsigned)codeloc + 10); + +  closure->cif = cif; +  closure->fun = fun; +  closure->user_data = user_data; + +  return FFI_OK; +} + +void +ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *avalue) +{ +  size_t rsize, bytes; +  struct call_frame *frame; +  char *stack, *argp; +  ffi_type **arg_types; +  int flags, cabi, i, n, narg_reg; +  const struct abi_params *pabi; + +  flags = cif->flags; +  cabi = cif->abi; +  pabi = &abi_params[cabi]; + +  rsize = 0; +  if (rvalue == NULL) +    { +      switch (flags) +	{ +	case X86_RET_FLOAT: +	case X86_RET_DOUBLE: +	case X86_RET_LDOUBLE: +	case X86_RET_STRUCTPOP: +	case X86_RET_STRUCTARG: +	  /* The float cases need to pop the 387 stack. +	     The struct cases need to pass a valid pointer to the callee.  */ +	  rsize = cif->rtype->size; +	  break; +	default: +	  /* We can pretend that the callee returns nothing.  */ +	  flags = X86_RET_VOID; +	  break; +	} +    } + +  bytes = cif->bytes; +  argp = stack = alloca(bytes + sizeof(*frame) + rsize); +  frame = (struct call_frame *)(stack + bytes); +  if (rsize) +    rvalue = frame + 1; + +  frame->fn = fn; +  frame->flags = flags; +  frame->rvalue = rvalue; + +  narg_reg = 0; +  switch (flags) +    { +    case X86_RET_STRUCTARG: +      /* The pointer is passed as the first argument.  */ +      if (pabi->nregs > 0) +	{ +	  frame->regs[pabi->regs[0]] = (unsigned)rvalue; +	  narg_reg = 1; +	  break; +	} +      /* fallthru */ +    case X86_RET_STRUCTPOP: +      *(void **)argp = rvalue; +      argp += sizeof(void *); +      bytes -= sizeof(void *); +      break; +    } + +  arg_types = cif->arg_types; +  for (i = 0, n = cif->nargs; narg_reg < pabi->nregs && i < n; i++) +    { +      ffi_type *ty = arg_types[i]; +      size_t z = ty->size; +      int t = ty->type; + +      if (z <= FFI_SIZEOF_ARG && t != FFI_TYPE_STRUCT && t != FFI_TYPE_FLOAT) +	{ +	  ffi_arg val = extend_basic_type (avalue, t); +	  frame->regs[pabi->regs[narg_reg++]] = val; +	  z = FFI_SIZEOF_ARG; +	} +      else +	{ +	  memcpy (argp, avalue, z); +	  z = ALIGN (z, FFI_SIZEOF_ARG); +	  argp += z; +	} +      avalue += z; +      bytes -= z; +    } +  if (i < n) +    memcpy (argp, avalue, bytes); + +  ffi_call_i386 (frame, stack); +} +#endif /* !FFI_NO_RAW_API */ +#endif /* !__x86_64__ */ | 
