⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ffi.c

📁 this gcc-g++-3.3.1.tar.gz is a source file of gcc, you can learn more about gcc through this codes f
💻 C
📖 第 1 页 / 共 2 页
字号:
        } else {          cif->flags = FFI_TYPE_STRUCT;	}      }      break;    case FFI_TYPE_FLOAT:      is_simple = FALSE;      cif->flags = FFI_TYPE_FLOAT;      break;    case FFI_TYPE_DOUBLE:      is_simple = FALSE;      cif->flags = FFI_TYPE_DOUBLE;      break;    default:      cif->flags = FFI_TYPE_INT;      /* This seems to depend on little endian mode, and the fact that	*/      /* the return pointer always points to at least 8 bytes.  But 	*/      /* that also seems to be true for other platforms.		*/      break;    }    if (is_simple) cif -> flags |= simple_flag;  return FFI_OK;}extern int ffi_call_unix(bool (*)(struct ia64_args *, extended_cif *, int), 			 extended_cif *, unsigned, 			 unsigned, unsigned *, void (*)());voidffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue){  extended_cif ecif;  long simple = cif -> flags & FFI_SIMPLE;  /* Should this also check for Unix ABI? */  /* This is almost, but not quite, machine independent.  Note that	*/  /* we can get away with not caring about length of the result because	*/  /* we assume we are little endian, and the result buffer is large 	*/  /* enough.								*/  /* This needs work for HP/UX.						*/  if (simple) {    long (*lfn)() = (long (*)())fn;    long result;    switch(simple) {      case FFI_SIMPLE_V:	result = lfn();	break;      case FFI_SIMPLE_I:	result = lfn(*(int *)avalue[0]);	break;      case FFI_SIMPLE_L:	result = lfn(*(long *)avalue[0]);	break;      case FFI_SIMPLE_II:	result = lfn(*(int *)avalue[0], *(int *)avalue[1]);	break;      case FFI_SIMPLE_IL:	result = lfn(*(int *)avalue[0], *(long *)avalue[1]);	break;      case FFI_SIMPLE_LI:	result = lfn(*(long *)avalue[0], *(int *)avalue[1]);	break;      case FFI_SIMPLE_LL:	result = lfn(*(long *)avalue[0], *(long *)avalue[1]);	break;    }    if ((cif->flags & ~FFI_SIMPLE) != FFI_TYPE_VOID && 0 != rvalue) {      * (long *)rvalue = result;    }    return;  }  ecif.cif = cif;  ecif.avalue = avalue;    /* If the return value is a struct and we don't have a return     value address then we need to make one.  */    if (rvalue == NULL && cif->rtype->type == FFI_TYPE_STRUCT)    ecif.rvalue = alloca(cif->rtype->size);  else    ecif.rvalue = rvalue;      switch (cif->abi)     {    case FFI_UNIX:      ffi_call_unix(ffi_prep_args, &ecif, cif->bytes,		    cif->flags, rvalue, fn);      break;    default:      FFI_ASSERT(0);      break;    }}/* * Closures represent a pair consisting of a function pointer, and * some user data.  A closure is invoked by reinterpreting the closure * as a function pointer, and branching to it.  Thus we can make an * interpreted function callable as a C function:  We turn the interpreter * itself, together with a pointer specifying the interpreted procedure, * into a closure. * On X86, the first few words of the closure structure actually contain code, * which will do the right thing.  On most other architectures, this * would raise some Icache/Dcache coherence issues (which can be solved, but * often not cheaply). * For IA64, function pointer are already pairs consisting of a code * pointer, and a gp pointer.  The latter is needed to access global variables. * Here we set up such a pair as the first two words of the closure (in * the "trampoline" area), but we replace the gp pointer with a pointer * to the closure itself.  We also add the real gp pointer to the * closure.  This allows the function entry code to both retrieve the * user data, and to restire the correct gp pointer. */static void ffi_prep_incoming_args_UNIX(struct ia64_args *args, void **rvalue,			    void **avalue, ffi_cif *cif);/* This function is entered with the doctored gp (r1) value. * This code is extremely gcc specific.  There is some argument that * it should really be written in assembly code, since it depends on * gcc properties that might change over time. *//* ffi_closure_UNIX is an assembly routine, which copies the register 	*//* state into a struct ia64_args, and then invokes			*//* ffi_closure_UNIX_inner.  It also recovers the closure pointer	*//* from its fake gp pointer.						*/void ffi_closure_UNIX();#ifndef __GNUC__#   error This requires gcc#endifvoidffi_closure_UNIX_inner (ffi_closure *closure, struct ia64_args * args)/* Hopefully declaring this as a varargs function will force all args	*//* to memory.								*/{  // this is our return value storage  long double    res;  // our various things...  ffi_cif       *cif;  unsigned short rtype;  void          *resp;  void		**arg_area;  resp = (void*)&res;  cif         = closure->cif;  arg_area    = (void**) alloca (cif->nargs * sizeof (void*));    /* this call will initialize ARG_AREA, such that each   * element in that array points to the corresponding    * value on the stack; and if the function returns   * a structure, it will re-set RESP to point to the   * structure return address.  */  ffi_prep_incoming_args_UNIX(args, (void**)&resp, arg_area, cif);    (closure->fun) (cif, resp, arg_area, closure->user_data);  rtype = cif->flags;  /* now, do a generic return based on the value of rtype */  if (rtype == FFI_TYPE_INT)    {      asm volatile ("ld8 r8=[%0]" : : "r" (resp) : "r8");    }  else if (rtype == FFI_TYPE_FLOAT)    {      asm volatile ("ldfs f8=[%0]" : : "r" (resp) : "f8");    }  else if (rtype == FFI_TYPE_DOUBLE)    {      asm volatile ("ldfd f8=[%0]" : : "r" (resp) : "f8");    }  else if (rtype == FFI_IS_SMALL_STRUCT2)    {      asm volatile ("ld8 r8=[%0]; ld8 r9=[%1]"		    : : "r" (resp), "r" (resp+8) : "r8","r9");    }  else if (rtype == FFI_IS_SMALL_STRUCT3)    {      asm volatile ("ld8 r8=[%0]; ld8 r9=[%1]; ld8 r10=[%2]"		    : : "r" (resp), "r" (resp+8), "r" (resp+16)		    : "r8","r9","r10");    }  else if (rtype == FFI_IS_SMALL_STRUCT4)    {      asm volatile ("ld8 r8=[%0]; ld8 r9=[%1]; ld8 r10=[%2]; ld8 r11=[%3]"		    : : "r" (resp), "r" (resp+8), "r" (resp+16), "r" (resp+24)		    : "r8","r9","r10","r11");    }  else if (rtype != FFI_TYPE_VOID && rtype != FFI_TYPE_STRUCT)    {      /* Can only happen for homogeneous FP aggregates?	*/      abort();    }}static void ffi_prep_incoming_args_UNIX(struct ia64_args *args, void **rvalue,			    void **avalue, ffi_cif *cif){  register unsigned int i;  register unsigned int avn;  register void **p_argv;  register unsigned long *argp = args -> out_regs;  unsigned fp_reg_num = 0;  register ffi_type **p_arg;  avn = cif->nargs;  p_argv = avalue;  for (i = cif->nargs, p_arg = cif->arg_types; i != 0; i--, p_arg++)    {      size_t z; /* In units of words or argument slots.	*/      switch ((*p_arg)->type)	{	case FFI_TYPE_SINT8:	case FFI_TYPE_UINT8:	case FFI_TYPE_SINT16:	case FFI_TYPE_UINT16:	case FFI_TYPE_SINT32:	case FFI_TYPE_UINT32:	case FFI_TYPE_SINT64:	case FFI_TYPE_UINT64:	case FFI_TYPE_POINTER:	  z = 1;	  *p_argv = (void *)argp;	  break;		  	case FFI_TYPE_FLOAT:	  z = 1;	  /* Convert argument back to float in place from the saved value */	  if (fp_reg_num < 8) {	      *(float *)argp = args -> fp_regs[fp_reg_num++];	  } else {	      *(float *)argp = *(double *)argp;	  }	  *p_argv = (void *)argp;	  break;	case FFI_TYPE_DOUBLE:	  z = 1;	  if (fp_reg_num < 8) {	      *p_argv = args -> fp_regs + fp_reg_num++;	  } else {	      *p_argv = (void *)argp;	  }	  break;	case FFI_TYPE_STRUCT:	  {	      size_t sz = (*p_arg)->size;	      unsigned short element_type;              z = ((*p_arg)->size + SIZEOF_ARG - 1)/SIZEOF_ARG;	      if (is_homogeneous_fp_aggregate(*p_arg, 8, &element_type)) {		int nelements = sz/float_type_size(element_type);		if (nelements + fp_reg_num >= 8) {		  /* hard case NYI.	*/		  abort();		}		if (element_type == FFI_TYPE_DOUBLE) {	          *p_argv = args -> fp_regs + fp_reg_num;		  fp_reg_num += nelements;		  break;		}		if (element_type == FFI_TYPE_FLOAT) {		  int j;		  for (j = 0; j < nelements; ++ j) {		     ((float *)argp)[j] = args -> fp_regs[fp_reg_num + j];		  }	          *p_argv = (void *)argp;		  fp_reg_num += nelements;		  break;		}		abort();  /* Other fp types NYI */	      }	  }	  break;	default:	  FFI_ASSERT(0);	}      argp += z;      p_argv++;    }    return;}/* Fill in a closure to refer to the specified fun and user_data.	*//* cif specifies the argument and result types for fun.			*//* the cif must already be prep'ed *//* The layout of a function descriptor.  A C function pointer really 	*//* points to one of these.						*/typedef struct ia64_fd_struct {    void *code_pointer;    void *gp;} ia64_fd;ffi_statusffi_prep_closure (ffi_closure* closure,		  ffi_cif* cif,		  void (*fun)(ffi_cif*,void*,void**,void*),		  void *user_data){  struct ffi_ia64_trampoline_struct *tramp =    (struct ffi_ia64_trampoline_struct *) (closure -> tramp);  ia64_fd *fd = (ia64_fd *)(void *)ffi_closure_UNIX;  FFI_ASSERT (cif->abi == FFI_UNIX);  tramp -> code_pointer = fd -> code_pointer;  tramp -> real_gp = fd -> gp;  tramp -> fake_gp = closure;  closure->cif  = cif;  closure->user_data = user_data;  closure->fun  = fun;  return FFI_OK;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -