示例#1
0
ffi_status
ffi_prep_cif_machdep(ffi_cif *cif)
{
  size_t struct_size = 0;
  int n_gpr = 0;
  int n_fpr = 0;
  int n_ov = 0;

  ffi_type **ptr;
  int i;

  /* Determine return value handling.  */ 

  switch (cif->rtype->type)
    {
      /* Void is easy.  */
      case FFI_TYPE_VOID:
	cif->flags = FFI390_RET_VOID;
	break;

      /* Structures are returned via a hidden pointer.  */
      case FFI_TYPE_STRUCT:
	cif->flags = FFI390_RET_STRUCT;
	n_gpr++;  /* We need one GPR to pass the pointer.  */
	break; 

      /* Floating point values are returned in fpr 0.  */
      case FFI_TYPE_FLOAT:
	cif->flags = FFI390_RET_FLOAT;
	break;

      case FFI_TYPE_DOUBLE:
	cif->flags = FFI390_RET_DOUBLE;
	break;

#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
      case FFI_TYPE_LONGDOUBLE:
	cif->flags = FFI390_RET_STRUCT;
	n_gpr++;
	break;
#endif
      /* Integer values are returned in gpr 2 (and gpr 3
	 for 64-bit values on 31-bit machines).  */
      case FFI_TYPE_UINT64:
      case FFI_TYPE_SINT64:
	cif->flags = FFI390_RET_INT64;
	break;

      case FFI_TYPE_POINTER:
      case FFI_TYPE_INT:
      case FFI_TYPE_UINT32:
      case FFI_TYPE_SINT32:
      case FFI_TYPE_UINT16:
      case FFI_TYPE_SINT16:
      case FFI_TYPE_UINT8:
      case FFI_TYPE_SINT8:
	/* These are to be extended to word size.  */
#ifdef __s390x__
	cif->flags = FFI390_RET_INT64;
#else
	cif->flags = FFI390_RET_INT32;
#endif
	break;
 
      default:
        FFI_ASSERT (0);
        break;
    }

  /* Now for the arguments.  */
 
  for (ptr = cif->arg_types, i = cif->nargs;
       i > 0;
       i--, ptr++)
    {
      int type = (*ptr)->type;

#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
      /* 16-byte long double is passed like a struct.  */
      if (type == FFI_TYPE_LONGDOUBLE)
	type = FFI_TYPE_STRUCT;
#endif

      /* Check how a structure type is passed.  */
      if (type == FFI_TYPE_STRUCT)
	{
	  type = ffi_check_struct_type (*ptr);

	  /* If we pass the struct via pointer, we must reserve space
	     to copy its data for proper call-by-value semantics.  */
	  if (type == FFI_TYPE_POINTER)
	    struct_size += ROUND_SIZE ((*ptr)->size);
	}

      /* Now handle all primitive int/float data types.  */
      switch (type) 
	{
	  /* The first MAX_FPRARGS floating point arguments
	     go in FPRs, the rest overflow to the stack.  */

	  case FFI_TYPE_DOUBLE:
	    if (n_fpr < MAX_FPRARGS)
	      n_fpr++;
	    else
	      n_ov += sizeof (double) / sizeof (long);
	    break;
	
	  case FFI_TYPE_FLOAT:
	    if (n_fpr < MAX_FPRARGS)
	      n_fpr++;
	    else
	      n_ov++;
	    break;

	  /* On 31-bit machines, 64-bit integers are passed in GPR pairs,
	     if one is still available, or else on the stack.  If only one
	     register is free, skip the register (it won't be used for any 
	     subsequent argument either).  */
	      
#ifndef __s390x__
	  case FFI_TYPE_UINT64:
	  case FFI_TYPE_SINT64:
	    if (n_gpr == MAX_GPRARGS-1)
	      n_gpr = MAX_GPRARGS;
	    if (n_gpr < MAX_GPRARGS)
	      n_gpr += 2;
	    else
	      n_ov += 2;
	    break;
#endif

	  /* Everything else is passed in GPRs (until MAX_GPRARGS
	     have been used) or overflows to the stack.  */

	  default: 
	    if (n_gpr < MAX_GPRARGS)
	      n_gpr++;
	    else
	      n_ov++;
	    break;
        }
    }

  /* Total stack space as required for overflow arguments
     and temporary structure copies.  */

  cif->bytes = ROUND_SIZE (n_ov * sizeof (long)) + struct_size;
 
  return FFI_OK;
}
示例#2
0
/* Classify the argument of type TYPE and mode MODE.
   CLASSES will be filled by the register class used to pass each word
   of the operand.  The number of words is returned.  In case the parameter
   should be passed in memory, 0 is returned. As a special case for zero
   sized containers, classes[0] will be NO_CLASS and 1 is returned.

   See the x86-64 PS ABI for details.
*/
static int
classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
		   size_t byte_offset)
{
  switch (type->type)
    {
    case FFI_TYPE_UINT8:
    case FFI_TYPE_SINT8:
    case FFI_TYPE_UINT16:
    case FFI_TYPE_SINT16:
    case FFI_TYPE_UINT32:
    case FFI_TYPE_SINT32:
    case FFI_TYPE_UINT64:
    case FFI_TYPE_SINT64:
    case FFI_TYPE_POINTER:
      {
	int size = byte_offset + type->size;

	if (size <= 4)
	  {
	    classes[0] = X86_64_INTEGERSI_CLASS;
	    return 1;
	  }
	else if (size <= 8)
	  {
	    classes[0] = X86_64_INTEGER_CLASS;
	    return 1;
	  }
	else if (size <= 12)
	  {
	    classes[0] = X86_64_INTEGER_CLASS;
	    classes[1] = X86_64_INTEGERSI_CLASS;
	    return 2;
	  }
	else if (size <= 16)
	  {
	    classes[0] = classes[1] = X86_64_INTEGERSI_CLASS;
	    return 2;
	  }
	else
	  FFI_ASSERT (0);
      }
    case FFI_TYPE_FLOAT:
      if (!(byte_offset % 8))
	classes[0] = X86_64_SSESF_CLASS;
      else
	classes[0] = X86_64_SSE_CLASS;
      return 1;
    case FFI_TYPE_DOUBLE:
      classes[0] = X86_64_SSEDF_CLASS;
      return 1;
    case FFI_TYPE_LONGDOUBLE:
      classes[0] = X86_64_X87_CLASS;
      classes[1] = X86_64_X87UP_CLASS;
      return 2;
    case FFI_TYPE_STRUCT:
      {
	const int UNITS_PER_WORD = 8;
	int words = (type->size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
	ffi_type **ptr; 
	int i;
	enum x86_64_reg_class subclasses[MAX_CLASSES];

	/* If the struct is larger than 32 bytes, pass it on the stack.  */
	if (type->size > 32)
	  return 0;

	for (i = 0; i < words; i++)
	  classes[i] = X86_64_NO_CLASS;

	/* Zero sized arrays or structures are NO_CLASS.  We return 0 to
	   signalize memory class, so handle it as special case.  */
	if (!words)
	  {
	    classes[0] = X86_64_NO_CLASS;
	    return 1;
	  }

	/* Merge the fields of structure.  */
	for (ptr = type->elements; *ptr != NULL; ptr++)
	  {
	    int num;

	    byte_offset = ALIGN (byte_offset, (*ptr)->alignment);

	    num = classify_argument (*ptr, subclasses, byte_offset % 8);
	    if (num == 0)
	      return 0;
	    for (i = 0; i < num; i++)
	      {
		int pos = byte_offset / 8;
		classes[i + pos] =
		  merge_classes (subclasses[i], classes[i + pos]);
	      }

	    byte_offset += (*ptr)->size;
	  }

	if (words > 2)
	  {
	    /* When size > 16 bytes, if the first one isn't
	       X86_64_SSE_CLASS or any other ones aren't
	       X86_64_SSEUP_CLASS, everything should be passed in
	       memory.  */
	    if (classes[0] != X86_64_SSE_CLASS)
	      return 0;

	    for (i = 1; i < words; i++)
	      if (classes[i] != X86_64_SSEUP_CLASS)
		return 0;
	  }

	/* Final merger cleanup.  */
	for (i = 0; i < words; i++)
	  {
	    /* If one class is MEMORY, everything should be passed in
	       memory.  */
	    if (classes[i] == X86_64_MEMORY_CLASS)
	      return 0;

	    /* The X86_64_SSEUP_CLASS should be always preceded by
	       X86_64_SSE_CLASS or X86_64_SSEUP_CLASS.  */
	    if (classes[i] == X86_64_SSEUP_CLASS
		&& classes[i - 1] != X86_64_SSE_CLASS
		&& classes[i - 1] != X86_64_SSEUP_CLASS)
	      {
		/* The first one should never be X86_64_SSEUP_CLASS.  */
		FFI_ASSERT (i != 0);
		classes[i] = X86_64_SSE_CLASS;
	      }

	    /*  If X86_64_X87UP_CLASS isn't preceded by X86_64_X87_CLASS,
		everything should be passed in memory.  */
	    if (classes[i] == X86_64_X87UP_CLASS
		&& (classes[i - 1] != X86_64_X87_CLASS))
	      {
		/* The first one should never be X86_64_X87UP_CLASS.  */
		FFI_ASSERT (i != 0);
		return 0;
	      }
	  }
	return words;
      }

    default:
      FFI_ASSERT(0);
    }
  return 0; /* Never reached.  */
}
示例#3
0
文件: ffi.c 项目: 3l13/APE_Server
void ffi_prep_args(char *stack, extended_cif *ecif)
{
  register unsigned int i;
  register void **p_argv;
  register char *argp;
  register ffi_type **p_arg;

  argp = stack;

  if (ecif->cif->flags == FFI_TYPE_STRUCT
#ifdef X86_WIN64
      && (ecif->cif->rtype->size != 1 && ecif->cif->rtype->size != 2
          && ecif->cif->rtype->size != 4 && ecif->cif->rtype->size != 8)
#endif
      )
    {
      *(void **) argp = ecif->rvalue;
      argp += sizeof(void*);
    }

  p_argv = ecif->avalue;

  for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
       i != 0;
       i--, p_arg++)
    {
      size_t z;

      /* Align if necessary */
      if ((sizeof(void*) - 1) & (size_t) argp)
        argp = (char *) ALIGN(argp, sizeof(void*));

      z = (*p_arg)->size;
#ifdef X86_WIN64
      if (z > sizeof(ffi_arg)
          || ((*p_arg)->type == FFI_TYPE_STRUCT
              && (z != 1 && z != 2 && z != 4 && z != 8))
#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
          || ((*p_arg)->type == FFI_TYPE_LONGDOUBLE)
#endif
          )
        {
          z = sizeof(ffi_arg);
          *(void **)argp = *p_argv;
        }
      else if ((*p_arg)->type == FFI_TYPE_FLOAT)
        {
          memcpy(argp, *p_argv, z);
        }
      else
#endif
      if (z < sizeof(ffi_arg))
        {
          z = sizeof(ffi_arg);
          switch ((*p_arg)->type)
            {
            case FFI_TYPE_SINT8:
              *(ffi_sarg *) argp = (ffi_sarg)*(SINT8 *)(* p_argv);
              break;

            case FFI_TYPE_UINT8:
              *(ffi_arg *) argp = (ffi_arg)*(UINT8 *)(* p_argv);
              break;

            case FFI_TYPE_SINT16:
              *(ffi_sarg *) argp = (ffi_sarg)*(SINT16 *)(* p_argv);
              break;

            case FFI_TYPE_UINT16:
              *(ffi_arg *) argp = (ffi_arg)*(UINT16 *)(* p_argv);
              break;

            case FFI_TYPE_SINT32:
              *(ffi_sarg *) argp = (ffi_sarg)*(SINT32 *)(* p_argv);
              break;

            case FFI_TYPE_UINT32:
              *(ffi_arg *) argp = (ffi_arg)*(UINT32 *)(* p_argv);
              break;

            case FFI_TYPE_STRUCT:
              *(ffi_arg *) argp = *(ffi_arg *)(* p_argv);
              break;

            default:
              FFI_ASSERT(0);
            }
        }
      else
        {
          memcpy(argp, *p_argv, z);
        }
      p_argv++;
#ifdef X86_WIN64
      argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
#else
      argp += z;
#endif
    }
  
  return;
}
static void
ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
	      void **avalue, void *closure)
{
  int i, j, n, flags;
  UINT64 *stack;
  size_t rsize;
  struct win64_call_frame *frame;

  FFI_ASSERT(cif->abi == FFI_GNUW64 || cif->abi == FFI_WIN64);

  flags = cif->flags;
  rsize = 0;

  /* If we have no return value for a structure, we need to create one.
     Otherwise we can ignore the return type entirely.  */
  if (rvalue == NULL)
    {
      if (flags == FFI_TYPE_STRUCT)
	rsize = cif->rtype->size;
      else
	flags = FFI_TYPE_VOID;
    }

  stack = alloca(cif->bytes + sizeof(struct win64_call_frame) + rsize);
  frame = (struct win64_call_frame *)((char *)stack + cif->bytes);
  if (rsize)
    rvalue = frame + 1;

  frame->fn = (uintptr_t)fn;
  frame->flags = flags;
  frame->rvalue = (uintptr_t)rvalue;

  j = 0;
  if (flags == FFI_TYPE_STRUCT)
    {
      stack[0] = (uintptr_t)rvalue;
      j = 1;
    }

  for (i = 0, n = cif->nargs; i < n; ++i, ++j)
    {
      switch (cif->arg_types[i]->size)
	{
	case 8:
	  stack[j] = *(UINT64 *)avalue[i];
	  break;
	case 4:
	  stack[j] = *(UINT32 *)avalue[i];
	  break;
	case 2:
	  stack[j] = *(UINT16 *)avalue[i];
	  break;
	case 1:
	  stack[j] = *(UINT8 *)avalue[i];
	  break;
	default:
	  stack[j] = (uintptr_t)avalue[i];
	  break;
	}
    }

  ffi_call_win64 (stack, frame, closure);
}
示例#5
0
文件: ffi.c 项目: alex/libffi
void
ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *fake_avalue)
{
  extended_cif ecif;
  void **avalue = (void **)fake_avalue;

  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->flags == FFI_TYPE_STRUCT
          || cif->flags == FFI_TYPE_MS_STRUCT))
    {
      ecif.rvalue = alloca(cif->rtype->size);
    }
  else
    ecif.rvalue = rvalue;
    
  
  switch (cif->abi) 
    {
#ifdef X86_WIN32
    case FFI_SYSV:
    case FFI_STDCALL:
    case FFI_MS_CDECL:
      ffi_call_win32(ffi_prep_args_raw, &ecif, cif->abi, cif->bytes, cif->flags,
		     ecif.rvalue, fn);
      break;
    case FFI_THISCALL:
    case FFI_FASTCALL:
      {
	unsigned int abi = cif->abi;
	unsigned int i, passed_regs = 0;

	if (cif->flags == FFI_TYPE_STRUCT)
	  ++passed_regs;

	for (i=0; i < cif->nargs && passed_regs < 2;i++)
	  {
	    size_t sz;

	    if (cif->arg_types[i]->type == FFI_TYPE_FLOAT
	        || cif->arg_types[i]->type == FFI_TYPE_STRUCT)
	      continue;
	    sz = (cif->arg_types[i]->size + 3) & ~3;
	    if (sz == 0 || sz > 4)
	      continue;
	    ++passed_regs;
	  }
	if (passed_regs < 2 && abi == FFI_FASTCALL)
	  cif->abi = abi = FFI_THISCALL;
	if (passed_regs < 1 && abi == FFI_THISCALL)
	  cif->abi = abi = FFI_STDCALL;
        ffi_call_win32(ffi_prep_args_raw, &ecif, abi, cif->bytes, cif->flags,
                       ecif.rvalue, fn);
      }
      break;
#else
    case FFI_SYSV:
      ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
                    ecif.rvalue, fn);
      break;
#endif
    default:
      FFI_ASSERT(0);
      break;
    }
}
示例#6
0
void FFI_HIDDEN
ffi_closure_SYSV_inner (ffi_closure *closure, struct call_context *context,
			void *stack)
{
  ffi_cif *cif = closure->cif;
  void **avalue = (void**) alloca (cif->nargs * sizeof (void*));
  void *rvalue = NULL;
  int i;
  struct arg_state state;

  arg_init (&state, ALIGN(cif->bytes, 16));

  for (i = 0; i < cif->nargs; i++)
    {
      ffi_type *ty = cif->arg_types[i];

      switch (ty->type)
	{
	case FFI_TYPE_VOID:
	  FFI_ASSERT (0);
	  break;

	case FFI_TYPE_UINT8:
	case FFI_TYPE_SINT8:
	case FFI_TYPE_UINT16:
	case FFI_TYPE_SINT16:
	case FFI_TYPE_UINT32:
	case FFI_TYPE_SINT32:
	case FFI_TYPE_INT:
	case FFI_TYPE_POINTER:
	case FFI_TYPE_UINT64:
	case FFI_TYPE_SINT64:
	case  FFI_TYPE_FLOAT:
	case  FFI_TYPE_DOUBLE:
#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
	case  FFI_TYPE_LONGDOUBLE:
	  avalue[i] = allocate_to_register_or_stack (context, stack,
						     &state, ty->type);
	  break;
#endif

	case FFI_TYPE_STRUCT:
	  if (is_hfa (ty))
	    {
	      unsigned n = element_count (ty);
	      if (available_v (&state) < n)
		{
		  state.nsrn = N_V_ARG_REG;
		  avalue[i] = allocate_to_stack (&state, stack, ty->alignment,
						 ty->size);
		}
	      else
		{
		  switch (get_homogeneous_type (ty))
		    {
		    case FFI_TYPE_FLOAT:
		      {
			/* Eeek! We need a pointer to the structure,
			   however the homogeneous float elements are
			   being passed in individual S registers,
			   therefore the structure is not represented as
			   a contiguous sequence of bytes in our saved
			   register context. We need to fake up a copy
			   of the structure laid out in memory
			   correctly. The fake can be tossed once the
			   closure function has returned hence alloca()
			   is sufficient. */
			int j;
			UINT32 *p = avalue[i] = alloca (ty->size);
			for (j = 0; j < element_count (ty); j++)
			  memcpy (&p[j],
				  allocate_to_s (context, &state),
				  sizeof (*p));
			break;
		      }

		    case FFI_TYPE_DOUBLE:
		      {
			/* Eeek! We need a pointer to the structure,
			   however the homogeneous float elements are
			   being passed in individual S registers,
			   therefore the structure is not represented as
			   a contiguous sequence of bytes in our saved
			   register context. We need to fake up a copy
			   of the structure laid out in memory
			   correctly. The fake can be tossed once the
			   closure function has returned hence alloca()
			   is sufficient. */
			int j;
			UINT64 *p = avalue[i] = alloca (ty->size);
			for (j = 0; j < element_count (ty); j++)
			  memcpy (&p[j],
				  allocate_to_d (context, &state),
				  sizeof (*p));
			break;
		      }

#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
		    case FFI_TYPE_LONGDOUBLE:
			  memcpy (&avalue[i],
				  allocate_to_v (context, &state),
				  sizeof (*avalue));
		      break;
#endif

		    default:
		      FFI_ASSERT (0);
		      break;
		    }
		}
	    }
	  else if (ty->size > 16)
	    {
	      /* Replace Composite type of size greater than 16 with a
		 pointer.  */
	      memcpy (&avalue[i],
		      allocate_to_register_or_stack (context, stack,
						     &state, FFI_TYPE_POINTER),
		      sizeof (avalue[i]));
	    }
	  else if (available_x (&state) >= (ty->size + 7) / 8)
	    {
	      avalue[i] = get_x_addr (context, state.ngrn);
	      state.ngrn += (ty->size + 7) / 8;
	    }
	  else
	    {
	      state.ngrn = N_X_ARG_REG;

	      avalue[i] = allocate_to_stack (&state, stack, ty->alignment,
					     ty->size);
	    }
	  break;

	default:
	  FFI_ASSERT (0);
	  break;
	}
    }

  /* Figure out where the return value will be passed, either in
     registers or in a memory block allocated by the caller and passed
     in x8.  */

  if (is_register_candidate (cif->rtype))
    {
      /* Register candidates are *always* returned in registers. */

      /* Allocate a scratchpad for the return value, we will let the
         callee scrible the result into the scratch pad then move the
         contents into the appropriate return value location for the
         call convention.  */
      rvalue = alloca (cif->rtype->size);
      (closure->fun) (cif, rvalue, avalue, closure->user_data);

      /* Copy the return value into the call context so that it is returned
         as expected to our caller.  */
      switch (cif->rtype->type)
        {
        case FFI_TYPE_VOID:
          break;

        case FFI_TYPE_UINT8:
        case FFI_TYPE_UINT16:
        case FFI_TYPE_UINT32:
        case FFI_TYPE_POINTER:
        case FFI_TYPE_UINT64:
        case FFI_TYPE_SINT8:
        case FFI_TYPE_SINT16:
        case FFI_TYPE_INT:
        case FFI_TYPE_SINT32:
        case FFI_TYPE_SINT64:
        case FFI_TYPE_FLOAT:
        case FFI_TYPE_DOUBLE:
#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
        case FFI_TYPE_LONGDOUBLE:
#endif
	  {
	    void *addr = get_basic_type_addr (cif->rtype->type, context, 0);
	    copy_basic_type (addr, rvalue, cif->rtype->type);
            break;
	  }
        case FFI_TYPE_STRUCT:
          if (is_hfa (cif->rtype))
	    {
	      int j;
	      unsigned short type = get_homogeneous_type (cif->rtype);
	      unsigned elems = element_count (cif->rtype);
	      for (j = 0; j < elems; j++)
		{
		  void *reg = get_basic_type_addr (type, context, j);
		  copy_basic_type (reg, rvalue, type);
		  rvalue += get_basic_type_size (type);
		}
	    }
          else if ((cif->rtype->size + 7) / 8 < N_X_ARG_REG)
            {
              size_t size = ALIGN (cif->rtype->size, sizeof (UINT64)) ;
              memcpy (get_x_addr (context, 0), rvalue, size);
            }
          else
            {
              FFI_ASSERT (0);
            }
          break;
        default:
          FFI_ASSERT (0);
          break;
        }
    }
  else
    {
      memcpy (&rvalue, get_x_addr (context, 8), sizeof (UINT64));
      (closure->fun) (cif, rvalue, avalue, closure->user_data);
    }
}
示例#7
0
/* Classify the argument of type TYPE and mode MODE.
   CLASSES will be filled by the register class used to pass each word
   of the operand.  The number of words is returned.  In case the parameter
   should be passed in memory, 0 is returned. As a special case for zero
   sized containers, classes[0] will be NO_CLASS and 1 is returned.

   See the x86-64 PS ABI for details.
*/
static int
classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
		   int *byte_offset)
{
  /* First, align to the right place.  */
  *byte_offset = ALIGN(*byte_offset, type->alignment);

  switch (type->type)
    {
    case FFI_TYPE_UINT8:
    case FFI_TYPE_SINT8:
    case FFI_TYPE_UINT16:
    case FFI_TYPE_SINT16:
    case FFI_TYPE_UINT32:
    case FFI_TYPE_SINT32:
    case FFI_TYPE_UINT64:
    case FFI_TYPE_SINT64:
    case FFI_TYPE_POINTER:
      if (((*byte_offset) % 8 + type->size) <= 4)
	classes[0] = X86_64_INTEGERSI_CLASS;
      else
	classes[0] = X86_64_INTEGER_CLASS;
      return 1;
    case FFI_TYPE_FLOAT:
      if (((*byte_offset) % 8) == 0)
	classes[0] = X86_64_SSESF_CLASS;
      else
	classes[0] = X86_64_SSE_CLASS;
      return 1;
    case FFI_TYPE_DOUBLE:
      classes[0] = X86_64_SSEDF_CLASS;
      return 1;
    case FFI_TYPE_LONGDOUBLE:
      classes[0] = X86_64_X87_CLASS;
      classes[1] = X86_64_X87UP_CLASS;
      return 2;
    case FFI_TYPE_STRUCT:
      {
	const int UNITS_PER_WORD = 8;
	int words = (type->size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
	ffi_type **ptr; 
	int i;
	enum x86_64_reg_class subclasses[MAX_CLASSES];

	/* If the struct is larger than 16 bytes, pass it on the stack.  */
	if (type->size > 16)
	  return 0;

	for (i = 0; i < words; i++)
	  classes[i] = X86_64_NO_CLASS;

	/* Merge the fields of structure.  */
	for (ptr=type->elements; (*ptr)!=NULL; ptr++)
	  {
	    int num;

	    num = classify_argument (*ptr, subclasses, byte_offset);
	    if (num == 0)
	      return 0;
	    for (i = 0; i < num; i++)
	      {
		int pos = *byte_offset / 8;
		classes[i + pos] =
		  merge_classes (subclasses[i], classes[i + pos]);
	      }

	    if ((*ptr)->type != FFI_TYPE_STRUCT)
	      *byte_offset += (*ptr)->size;
	  }

	/* Final merger cleanup.  */
	for (i = 0; i < words; i++)
	  {
	    /* If one class is MEMORY, everything should be passed in
	       memory.  */
	    if (classes[i] == X86_64_MEMORY_CLASS)
	      return 0;

	    /* The X86_64_SSEUP_CLASS should be always preceded by
	       X86_64_SSE_CLASS.  */
	    if (classes[i] == X86_64_SSEUP_CLASS
		&& (i == 0 || classes[i - 1] != X86_64_SSE_CLASS))
	      classes[i] = X86_64_SSE_CLASS;

	    /*  X86_64_X87UP_CLASS should be preceded by X86_64_X87_CLASS.  */
	    if (classes[i] == X86_64_X87UP_CLASS
		&& (i == 0 || classes[i - 1] != X86_64_X87_CLASS))
	      classes[i] = X86_64_SSE_CLASS;
	  }
	return words;
      }

    default:
      FFI_ASSERT(0);
    }
  return 0; /* Never reached.  */
}
示例#8
0
文件: ffi.c 项目: 0-wiz-0/libffi
void ffi_prep_args(char *stack, extended_cif *ecif)
{
  register unsigned int i;
  register int tmp;
  register unsigned int avn;
  register void **p_argv;
  register char *argp;
  register ffi_type **p_arg;
  int greg, ireg;
#if defined(__SH4__)
  int freg = 0;
#endif

  tmp = 0;
  argp = stack;

  if (return_type (ecif->cif->rtype) == FFI_TYPE_STRUCT)
    {
      *(void **) argp = ecif->rvalue;
      argp += 4;
      ireg = STRUCT_VALUE_ADDRESS_WITH_ARG ? 1 : 0;
    }
  else
    ireg = 0;

  /* Set arguments for registers.  */
  greg = ireg;
  avn = ecif->cif->nargs;
  p_argv = ecif->avalue;

  for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
    {
      size_t z;

      z = (*p_arg)->size;
      if (z < sizeof(int))
	{
	  if (greg++ >= NGREGARG)
	    continue;

	  z = sizeof(int);
	  switch ((*p_arg)->type)
	    {
	    case FFI_TYPE_SINT8:
	      *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
	      break;
  
	    case FFI_TYPE_UINT8:
	      *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
	      break;
  
	    case FFI_TYPE_SINT16:
	      *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
	      break;
  
	    case FFI_TYPE_UINT16:
	      *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
	      break;
  
	    case FFI_TYPE_STRUCT:
	      *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
	      break;

	    default:
	      FFI_ASSERT(0);
	    }
	  argp += z;
	}
      else if (z == sizeof(int))
	{
#if defined(__SH4__)
	  if ((*p_arg)->type == FFI_TYPE_FLOAT)
	    {
	      if (freg++ >= NFREGARG)
		continue;
	    }
	  else
#endif
	    {
	      if (greg++ >= NGREGARG)
		continue;
	    }
	  *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
	  argp += z;
	}
#if defined(__SH4__)
      else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
	{
	  if (freg + 1 >= NFREGARG)
	    continue;
	  freg = (freg + 1) & ~1;
	  freg += 2;
	  memcpy (argp, *p_argv, z);
	  argp += z;
	}
#endif
      else
	{
	  int n = (z + sizeof (int) - 1) / sizeof (int);
#if defined(__SH4__)
	  if (greg + n - 1 >= NGREGARG)
	    continue;
#else
	  if (greg >= NGREGARG)
	    continue;
#endif
	  greg += n;
	  memcpy (argp, *p_argv, z);
	  argp += n * sizeof (int);
	}
    }

  /* Set arguments on stack.  */
  greg = ireg;
#if defined(__SH4__)
  freg = 0;
#endif
  p_argv = ecif->avalue;

  for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
    {
      size_t z;

      z = (*p_arg)->size;
      if (z < sizeof(int))
	{
	  if (greg++ < NGREGARG)
	    continue;

	  z = sizeof(int);
	  switch ((*p_arg)->type)
	    {
	    case FFI_TYPE_SINT8:
	      *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
	      break;
  
	    case FFI_TYPE_UINT8:
	      *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
	      break;
  
	    case FFI_TYPE_SINT16:
	      *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
	      break;
  
	    case FFI_TYPE_UINT16:
	      *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
	      break;
  
	    case FFI_TYPE_STRUCT:
	      *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
	      break;

	    default:
	      FFI_ASSERT(0);
	    }
	  argp += z;
	}
      else if (z == sizeof(int))
	{
#if defined(__SH4__)
	  if ((*p_arg)->type == FFI_TYPE_FLOAT)
	    {
	      if (freg++ < NFREGARG)
		continue;
	    }
	  else
#endif
	    {
	      if (greg++ < NGREGARG)
		continue;
	    }
	  *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
	  argp += z;
	}
#if defined(__SH4__)
      else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
	{
	  if (freg + 1 < NFREGARG)
	    {
	      freg = (freg + 1) & ~1;
	      freg += 2;
	      continue;
	    }
	  memcpy (argp, *p_argv, z);
	  argp += z;
	}
#endif
      else
	{
	  int n = (z + sizeof (int) - 1) / sizeof (int);
	  if (greg + n - 1 < NGREGARG)
	    {
	      greg += n;
	      continue;
	    }
#if (! defined(__SH4__))
	  else if (greg < NGREGARG)
	    {
	      greg = NGREGARG;
	      continue;
	    }
#endif
	  memcpy (argp, *p_argv, z);
	  argp += n * sizeof (int);
	}
    }

  return;
}
示例#9
0
文件: ffi.c 项目: 0-wiz-0/libffi
int
ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue, 
			 unsigned long *pgr, unsigned long *pfr, 
			 unsigned long *pst)
{
  void **avalue;
  ffi_type **p_arg;
  int i, avn;
  int ireg, greg = 0;
#if defined(__SH4__)
  int freg = 0;
#endif
  ffi_cif *cif; 

  cif = closure->cif;
  avalue = alloca(cif->nargs * sizeof(void *));

  /* Copy the caller's structure return value address so that the closure
     returns the data directly to the caller.  */
  if (cif->rtype->type == FFI_TYPE_STRUCT && STRUCT_VALUE_ADDRESS_WITH_ARG)
    {
      rvalue = (void *) *pgr++;
      ireg = 1;
    }
  else
    ireg = 0;

  cif = closure->cif;
  greg = ireg;
  avn = cif->nargs;

  /* Grab the addresses of the arguments from the stack frame.  */
  for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
    {
      size_t z;

      z = (*p_arg)->size;
      if (z < sizeof(int))
	{
	  if (greg++ >= NGREGARG)
	    continue;

	  z = sizeof(int);
	  switch ((*p_arg)->type)
	    {
	    case FFI_TYPE_SINT8:
	    case FFI_TYPE_UINT8:
	      avalue[i] = (((char *)pgr) + OFS_INT8);
	      break;
  
	    case FFI_TYPE_SINT16:
	    case FFI_TYPE_UINT16:
	      avalue[i] = (((char *)pgr) + OFS_INT16);
	      break;
  
	    case FFI_TYPE_STRUCT:
	      avalue[i] = pgr;
	      break;

	    default:
	      FFI_ASSERT(0);
	    }
	  pgr++;
	}
      else if (z == sizeof(int))
	{
#if defined(__SH4__)
	  if ((*p_arg)->type == FFI_TYPE_FLOAT)
	    {
	      if (freg++ >= NFREGARG)
		continue;
	      avalue[i] = pfr;
	      pfr++;
	    }
	  else
#endif
	    {
	      if (greg++ >= NGREGARG)
		continue;
	      avalue[i] = pgr;
	      pgr++;
	    }
	}
#if defined(__SH4__)
      else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
	{
	  if (freg + 1 >= NFREGARG)
	    continue;
	  if (freg & 1)
	    pfr++;
	  freg = (freg + 1) & ~1;
	  freg += 2;
	  avalue[i] = pfr;
	  pfr += 2;
	}
#endif
      else
	{
	  int n = (z + sizeof (int) - 1) / sizeof (int);
#if defined(__SH4__)
	  if (greg + n - 1 >= NGREGARG)
	    continue;
#else
	  if (greg >= NGREGARG)
	    continue;
#endif
	  greg += n;
	  avalue[i] = pgr;
	  pgr += n;
	}
    }

  greg = ireg;
#if defined(__SH4__)
  freg = 0;
#endif

  for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
    {
      size_t z;

      z = (*p_arg)->size;
      if (z < sizeof(int))
	{
	  if (greg++ < NGREGARG)
	    continue;

	  z = sizeof(int);
	  switch ((*p_arg)->type)
	    {
	    case FFI_TYPE_SINT8:
	    case FFI_TYPE_UINT8:
	      avalue[i] = (((char *)pst) + OFS_INT8);
	      break;
  
	    case FFI_TYPE_SINT16:
	    case FFI_TYPE_UINT16:
	      avalue[i] = (((char *)pst) + OFS_INT16);
	      break;
  
	    case FFI_TYPE_STRUCT:
	      avalue[i] = pst;
	      break;

	    default:
	      FFI_ASSERT(0);
	    }
	  pst++;
	}
      else if (z == sizeof(int))
	{
#if defined(__SH4__)
	  if ((*p_arg)->type == FFI_TYPE_FLOAT)
	    {
	      if (freg++ < NFREGARG)
		continue;
	    }
	  else
#endif
	    {
	      if (greg++ < NGREGARG)
		continue;
	    }
	  avalue[i] = pst;
	  pst++;
	}
#if defined(__SH4__)
      else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
	{
	  if (freg + 1 < NFREGARG)
	    {
	      freg = (freg + 1) & ~1;
	      freg += 2;
	      continue;
	    }
	  avalue[i] = pst;
	  pst += 2;
	}
#endif
      else
	{
	  int n = (z + sizeof (int) - 1) / sizeof (int);
	  if (greg + n - 1 < NGREGARG)
	    {
	      greg += n;
	      continue;
	    }
#if (! defined(__SH4__))
	  else if (greg < NGREGARG)
	    {
	      greg += n;
	      pst += greg - NGREGARG;
	      continue;
	    }
#endif
	  avalue[i] = pst;
	  pst += n;
	}
    }

  (closure->fun) (cif, rvalue, avalue, closure->user_data);

  /* Tell ffi_closure_SYSV how to perform return type promotions.  */
  return return_type (cif->rtype);
}
示例#10
0
ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif, 
			ffi_abi abi, unsigned int nargs, 
			/*@dependent@*/ /*@out@*/ /*@partial@*/ ffi_type *rtype, 
			/*@dependent@*/ ffi_type **atypes)
{
  unsigned bytes = 0;
  unsigned int i;
  ffi_type **ptr;

  FFI_ASSERT(cif != NULL);
  FFI_ASSERT((abi > FFI_FIRST_ABI) && (abi <= FFI_DEFAULT_ABI));

  cif->abi = abi;
  cif->arg_types = atypes;
  cif->nargs = nargs;
  cif->rtype = rtype;

  cif->flags = 0;

  /* Initialize the return type if necessary */
  /*@-usedef@*/
  if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK))
    return FFI_BAD_TYPEDEF;
  /*@=usedef@*/

  /* Perform a sanity check on the return type */
  FFI_ASSERT_VALID_TYPE(cif->rtype);

  /* x86-64 and s390 stack space allocation is handled in prep_machdep.  */
#if !defined M68K && !defined __x86_64__ && !defined S390
  /* Make space for the return structure pointer */
  if (cif->rtype->type == FFI_TYPE_STRUCT
#ifdef _WIN32
      && (cif->rtype->size > 8)  /* MSVC returns small structs in registers */
#endif
#ifdef SPARC
      && (cif->abi != FFI_V9 || cif->rtype->size > 32)
#endif
      )
    bytes = STACK_ARG_SIZE(sizeof(void*));
#endif

  for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
    {

      /* Initialize any uninitialized aggregate type definitions */
      if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK))
	return FFI_BAD_TYPEDEF;

      /* Perform a sanity check on the argument type, do this 
	 check after the initialization.  */
      FFI_ASSERT_VALID_TYPE(*ptr);

#if !defined __x86_64__ && !defined S390
#ifdef SPARC
      if (((*ptr)->type == FFI_TYPE_STRUCT
	   && ((*ptr)->size > 16 || cif->abi != FFI_V9))
	  || ((*ptr)->type == FFI_TYPE_LONGDOUBLE
	      && cif->abi != FFI_V9))
	bytes += sizeof(void*);
      else
#endif
	{
#if !defined(_MSC_VER) && !defined(__MINGW32__)
		/* Don't know if this is a libffi bug or not.  At least on
		   Windows with MSVC, function call parameters are *not*
		   aligned in the same way as structure fields are, they are
		   only aligned in integer boundaries.

		   This doesn't do any harm for cdecl functions and closures,
		   since the caller cleans up the stack, but it is wrong for
		   stdcall functions where the callee cleans.
		*/

	  /* Add any padding if necessary */
	  if (((*ptr)->alignment - 1) & bytes)
	    bytes = ALIGN(bytes, (*ptr)->alignment);
	  
#endif
	  bytes += STACK_ARG_SIZE((*ptr)->size);
	}
#endif
    }

#ifdef _WIN64
  /* Function call needs at least 40 bytes stack size, on win64 AMD64 */
  if (bytes < 40)
      bytes = 40;
#endif

  cif->bytes = bytes;

  /* Perform machine dependent cif processing */
  return ffi_prep_cif_machdep(cif);
}
示例#11
0
void
ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw)
{
  unsigned i;
  ffi_type **tp = cif->arg_types;

  for (i = 0; i < cif->nargs; i++, tp++, args++)
    {
      switch ((*tp)->type)
	{
	case FFI_TYPE_UINT8:
#if WORDS_BIGENDIAN
	  *(UINT32*)(raw++) = *(UINT8*) (*args);
#else
	  (raw++)->uint = *(UINT8*) (*args);
#endif
	  break;

	case FFI_TYPE_SINT8:
#if WORDS_BIGENDIAN
	  *(SINT32*)(raw++) = *(SINT8*) (*args);
#else
	  (raw++)->sint = *(SINT8*) (*args);
#endif
	  break;

	case FFI_TYPE_UINT16:
#if WORDS_BIGENDIAN
	  *(UINT32*)(raw++) = *(UINT16*) (*args);
#else
	  (raw++)->uint = *(UINT16*) (*args);
#endif
	  break;

	case FFI_TYPE_SINT16:
#if WORDS_BIGENDIAN
	  *(SINT32*)(raw++) = *(SINT16*) (*args);
#else
	  (raw++)->sint = *(SINT16*) (*args);
#endif
	  break;

	case FFI_TYPE_UINT32:
#if WORDS_BIGENDIAN
	  *(UINT32*)(raw++) = *(UINT32*) (*args);
#else
	  (raw++)->uint = *(UINT32*) (*args);
#endif
	  break;

	case FFI_TYPE_SINT32:
#if WORDS_BIGENDIAN
	  *(SINT32*)(raw++) = *(SINT32*) (*args);
#else
	  (raw++)->sint = *(SINT32*) (*args);
#endif
	  break;

	case FFI_TYPE_FLOAT:
	  (raw++)->flt = *(FLOAT32*) (*args);
	  break;

#if FFI_SIZEOF_ARG == 8
	case FFI_TYPE_UINT64:
	case FFI_TYPE_SINT64:
	case FFI_TYPE_DOUBLE:
	  raw->uint = *(UINT64*) (*args);
	  raw += 2;
	  break;
#endif

	case FFI_TYPE_POINTER:
	  (raw++)->ptr = **(void***) args;
	  break;

	default:
#if FFI_SIZEOF_ARG == 8
	  FFI_ASSERT(0);	/* Should have covered all cases */
#else
	  memcpy ((void*) raw->data, (void*)*args, (*tp)->size);
	  raw += ALIGN ((*tp)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
#endif
	}
    }
}
示例#12
0
/* This is more-or-less an inverse of ffi_call -- we have arguments on
   the stack, and we need to fill them into a cif structure and invoke
   the user function. This really ought to be in asm to make sure
   the compiler doesn't do things we don't expect.  */
ffi_status ffi_closure_inner_LINUX(ffi_closure *closure, UINT32 *stack)
{
  ffi_cif *cif;
  void **avalue;
  void *rvalue;
  UINT32 ret[2]; /* function can return up to 64-bits in registers */
  ffi_type **p_arg;
  char *tmp;
  int i, avn;
  unsigned int slot = FIRST_ARG_SLOT;
  register UINT32 r28 asm("r28");

  cif = closure->cif;

  /* If returning via structure, callee will write to our pointer.  */
  if (cif->flags == FFI_TYPE_STRUCT)
    rvalue = (void *)r28;
  else
    rvalue = &ret[0];

  avalue = (void **)alloca(cif->nargs * FFI_SIZEOF_ARG);
  avn = cif->nargs;
  p_arg = cif->arg_types;

  for (i = 0; i < avn; i++)
    {
      int type = (*p_arg)->type;

      switch (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_POINTER:
	  avalue[i] = (char *)(stack - slot) + sizeof(UINT32) - (*p_arg)->size;
	  break;

	case FFI_TYPE_SINT64:
	case FFI_TYPE_UINT64:
	  slot += (slot & 1) ? 1 : 2;
	  avalue[i] = (void *)(stack - slot);
	  break;

	case FFI_TYPE_FLOAT:
	  /* The closure call is indirect.  In Linux, floating point
	     arguments in indirect calls with a prototype are passed
	     in the floating point registers instead of the general
	     registers.  So, we need to replace what was previously
	     stored in the current slot with the value in the
	     corresponding floating point register.  */
	  switch (slot - FIRST_ARG_SLOT)
	    {
	    case 0: fstw(fr4, (void *)(stack - slot)); break;
	    case 1: fstw(fr5, (void *)(stack - slot)); break;
	    case 2: fstw(fr6, (void *)(stack - slot)); break;
	    case 3: fstw(fr7, (void *)(stack - slot)); break;
	    }
	  avalue[i] = (void *)(stack - slot);
	  break;

	case FFI_TYPE_DOUBLE:
	  slot += (slot & 1) ? 1 : 2;
	  /* See previous comment for FFI_TYPE_FLOAT.  */
	  switch (slot - FIRST_ARG_SLOT)
	    {
	    case 1: fstd(fr5, (void *)(stack - slot)); break;
	    case 3: fstd(fr7, (void *)(stack - slot)); break;
	    }
	  avalue[i] = (void *)(stack - slot);
	  break;

	case FFI_TYPE_STRUCT:
	  /* Structs smaller or equal than 4 bytes are passed in one
	     register. Structs smaller or equal 8 bytes are passed in two
	     registers. Larger structures are passed by pointer.  */
	  if((*p_arg)->size <= 4)
	    {
	      avalue[i] = (void *)(stack - slot) + sizeof(UINT32) -
		(*p_arg)->size;
	    }
	  else if ((*p_arg)->size <= 8)
	    {
	      slot += (slot & 1) ? 1 : 2;
	      avalue[i] = (void *)(stack - slot) + sizeof(UINT64) -
		(*p_arg)->size;
	    }
	  else
	    avalue[i] = (void *) *(stack - slot);
	  break;

	default:
	  FFI_ASSERT(0);
	}

      slot++;
      p_arg++;
    }

  /* Invoke the closure.  */
  (closure->fun) (cif, rvalue, avalue, closure->user_data);

  debug(3, "after calling function, ret[0] = %08x, ret[1] = %08x\n", ret[0],
	ret[1]);

  /* Store the result using the lower 2 bytes of the flags.  */
  switch (cif->flags)
    {
    case FFI_TYPE_UINT8:
      *(stack - FIRST_ARG_SLOT) = (UINT8)(ret[0] >> 24);
      break;
    case FFI_TYPE_SINT8:
      *(stack - FIRST_ARG_SLOT) = (SINT8)(ret[0] >> 24);
      break;
    case FFI_TYPE_UINT16:
      *(stack - FIRST_ARG_SLOT) = (UINT16)(ret[0] >> 16);
      break;
    case FFI_TYPE_SINT16:
      *(stack - FIRST_ARG_SLOT) = (SINT16)(ret[0] >> 16);
      break;
    case FFI_TYPE_INT:
    case FFI_TYPE_SINT32:
    case FFI_TYPE_UINT32:
      *(stack - FIRST_ARG_SLOT) = ret[0];
      break;
    case FFI_TYPE_SINT64:
    case FFI_TYPE_UINT64:
      *(stack - FIRST_ARG_SLOT) = ret[0];
      *(stack - FIRST_ARG_SLOT - 1) = ret[1];
      break;

    case FFI_TYPE_DOUBLE:
      fldd(rvalue, fr4);
      break;

    case FFI_TYPE_FLOAT:
      fldw(rvalue, fr4);
      break;

    case FFI_TYPE_STRUCT:
      /* Don't need a return value, done by caller.  */
      break;

    case FFI_TYPE_SMALL_STRUCT2:
    case FFI_TYPE_SMALL_STRUCT3:
    case FFI_TYPE_SMALL_STRUCT4:
      tmp = (void*)(stack -  FIRST_ARG_SLOT);
      tmp += 4 - cif->rtype->size;
      memcpy((void*)tmp, &ret[0], cif->rtype->size);
      break;

    case FFI_TYPE_SMALL_STRUCT5:
    case FFI_TYPE_SMALL_STRUCT6:
    case FFI_TYPE_SMALL_STRUCT7:
    case FFI_TYPE_SMALL_STRUCT8:
      {
	unsigned int ret2[2];
	int off;

	/* Right justify ret[0] and ret[1] */
	switch (cif->flags)
	  {
	    case FFI_TYPE_SMALL_STRUCT5: off = 3; break;
	    case FFI_TYPE_SMALL_STRUCT6: off = 2; break;
	    case FFI_TYPE_SMALL_STRUCT7: off = 1; break;
	    default: off = 0; break;
	  }

	memset (ret2, 0, sizeof (ret2));
	memcpy ((char *)ret2 + off, ret, 8 - off);

	*(stack - FIRST_ARG_SLOT) = ret2[0];
	*(stack - FIRST_ARG_SLOT - 1) = ret2[1];
      }
      break;

    case FFI_TYPE_POINTER:
    case FFI_TYPE_VOID:
      break;

    default:
      debug(0, "assert with cif->flags: %d\n",cif->flags);
      FFI_ASSERT(0);
      break;
    }
  return FFI_OK;
}
示例#13
0
void ffi_prep_args_LINUX(UINT32 *stack, extended_cif *ecif, unsigned bytes)
{
  register unsigned int i;
  register ffi_type **p_arg;
  register void **p_argv;
  unsigned int slot = FIRST_ARG_SLOT;
  char *dest_cpy;
  size_t len;

  debug(1, "%s: stack = %p, ecif = %p, bytes = %u\n", __FUNCTION__, stack,
	ecif, bytes);

  p_arg = ecif->cif->arg_types;
  p_argv = ecif->avalue;

  for (i = 0; i < ecif->cif->nargs; i++)
    {
      int type = (*p_arg)->type;

      switch (type)
	{
	case FFI_TYPE_SINT8:
	  *(SINT32 *)(stack - slot) = *(SINT8 *)(*p_argv);
	  break;

	case FFI_TYPE_UINT8:
	  *(UINT32 *)(stack - slot) = *(UINT8 *)(*p_argv);
	  break;

	case FFI_TYPE_SINT16:
	  *(SINT32 *)(stack - slot) = *(SINT16 *)(*p_argv);
	  break;

	case FFI_TYPE_UINT16:
	  *(UINT32 *)(stack - slot) = *(UINT16 *)(*p_argv);
	  break;

	case FFI_TYPE_UINT32:
	case FFI_TYPE_SINT32:
	case FFI_TYPE_POINTER:
	  debug(3, "Storing UINT32 %u in slot %u\n", *(UINT32 *)(*p_argv),
		slot);
	  *(UINT32 *)(stack - slot) = *(UINT32 *)(*p_argv);
	  break;

	case FFI_TYPE_UINT64:
	case FFI_TYPE_SINT64:
	  /* Align slot for 64-bit type.  */
	  slot += (slot & 1) ? 1 : 2;
	  *(UINT64 *)(stack - slot) = *(UINT64 *)(*p_argv);
	  break;

	case FFI_TYPE_FLOAT:
	  /* First 4 args go in fr4L - fr7L.  */
	  debug(3, "Storing UINT32(float) in slot %u\n", slot);
	  *(UINT32 *)(stack - slot) = *(UINT32 *)(*p_argv);
	  switch (slot - FIRST_ARG_SLOT)
	    {
	    /* First 4 args go in fr4L - fr7L.  */
	    case 0: fldw(stack - slot, fr4); break;
	    case 1: fldw(stack - slot, fr5); break;
	    case 2: fldw(stack - slot, fr6); break;
	    case 3: fldw(stack - slot, fr7); break;
	    }
	  break;

	case FFI_TYPE_DOUBLE:
	  /* Align slot for 64-bit type.  */
	  slot += (slot & 1) ? 1 : 2;
	  debug(3, "Storing UINT64(double) at slot %u\n", slot);
	  *(UINT64 *)(stack - slot) = *(UINT64 *)(*p_argv);
	  switch (slot - FIRST_ARG_SLOT)
	    {
	      /* First 2 args go in fr5, fr7.  */
	      case 1: fldd(stack - slot, fr5); break;
	      case 3: fldd(stack - slot, fr7); break;
	    }
	  break;

	case FFI_TYPE_STRUCT:

	  /* Structs smaller or equal than 4 bytes are passed in one
	     register. Structs smaller or equal 8 bytes are passed in two
	     registers. Larger structures are passed by pointer.  */

	  len = (*p_arg)->size;
	  if (len <= 4)
	    {
	      dest_cpy = (char *)(stack - slot) + 4 - len;
	      memcpy(dest_cpy, (char *)*p_argv, len);
	    }
	  else if (len <= 8)
	    {
	      slot += (slot & 1) ? 1 : 2;
	      dest_cpy = (char *)(stack - slot) + 8 - len;
	      memcpy(dest_cpy, (char *)*p_argv, len);
	    }
	  else
	    *(UINT32 *)(stack - slot) = (UINT32)(*p_argv);
	  break;

	default:
	  FFI_ASSERT(0);
	}

      slot++;
      p_arg++;
      p_argv++;
    }

  /* Make sure we didn't mess up and scribble on the stack.  */
  {
    unsigned int n;

    debug(5, "Stack setup:\n");
    for (n = 0; n < (bytes + 3) / 4; n++)
      {
	if ((n%4) == 0) { debug(5, "\n%08x: ", (unsigned int)(stack - n)); }
	debug(5, "%08x ", *(stack - n));
      }
    debug(5, "\n");
  }

  FFI_ASSERT(slot * 4 <= bytes);

  return;
}
示例#14
0
void
ffi_closure_helper_SYSV (ffi_closure *closure,
			 unsigned long *p_gpr,
			 unsigned long long *p_fpr,
			 unsigned long *p_ov)
{
  unsigned long long ret_buffer;

  void *rvalue = &ret_buffer;
  void **avalue;
  void **p_arg;

  int n_gpr = 0;
  int n_fpr = 0;
  int n_ov = 0;

  ffi_type **ptr;
  int i;

  /* Allocate buffer for argument list pointers.  */

  p_arg = avalue = alloca (closure->cif->nargs * sizeof (void *));

  /* If we returning a structure, pass the structure address 
     directly to the target function.  Otherwise, have the target 
     function store the return value to the GPR save area.  */

  if (closure->cif->flags == FFI390_RET_STRUCT)
    rvalue = (void *) p_gpr[n_gpr++];

  /* Now for the arguments.  */

  for (ptr = closure->cif->arg_types, i = closure->cif->nargs;
       i > 0;
       i--, p_arg++, ptr++)
    {
      int deref_struct_pointer = 0;
      int type = (*ptr)->type;

#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
      /* 16-byte long double is passed like a struct.  */
      if (type == FFI_TYPE_LONGDOUBLE)
	type = FFI_TYPE_STRUCT;
#endif

      /* Check how a structure type is passed.  */
      if (type == FFI_TYPE_STRUCT)
	{
	  type = ffi_check_struct_type (*ptr);

	  /* If we pass the struct via pointer, remember to 
	     retrieve the pointer later.  */
	  if (type == FFI_TYPE_POINTER)
	    deref_struct_pointer = 1;
	}

      /* Pointers are passed like UINTs of the same size.  */
      if (type == FFI_TYPE_POINTER)
#ifdef __s390x__
	type = FFI_TYPE_UINT64;
#else
	type = FFI_TYPE_UINT32;
#endif

      /* Now handle all primitive int/float data types.  */
      switch (type) 
	{
	  case FFI_TYPE_DOUBLE:
	    if (n_fpr < MAX_FPRARGS)
	      *p_arg = &p_fpr[n_fpr++];
	    else
	      *p_arg = &p_ov[n_ov], 
	      n_ov += sizeof (double) / sizeof (long);
	    break;
	
	  case FFI_TYPE_FLOAT:
	    if (n_fpr < MAX_FPRARGS)
	      *p_arg = &p_fpr[n_fpr++];
	    else
	      *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 4;
	    break;
 
	  case FFI_TYPE_UINT64:
	  case FFI_TYPE_SINT64:
#ifdef __s390x__
	    if (n_gpr < MAX_GPRARGS)
	      *p_arg = &p_gpr[n_gpr++];
	    else
	      *p_arg = &p_ov[n_ov++];
#else
	    if (n_gpr == MAX_GPRARGS-1)
	      n_gpr = MAX_GPRARGS;
	    if (n_gpr < MAX_GPRARGS)
	      *p_arg = &p_gpr[n_gpr], n_gpr += 2;
	    else
	      *p_arg = &p_ov[n_ov], n_ov += 2;
#endif
	    break;
 
	  case FFI_TYPE_INT:
	  case FFI_TYPE_UINT32:
	  case FFI_TYPE_SINT32:
	    if (n_gpr < MAX_GPRARGS)
	      *p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 4;
	    else
	      *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 4;
	    break;
 
	  case FFI_TYPE_UINT16:
	  case FFI_TYPE_SINT16:
	    if (n_gpr < MAX_GPRARGS)
	      *p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 2;
	    else
	      *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 2;
	    break;

	  case FFI_TYPE_UINT8:
	  case FFI_TYPE_SINT8:
	    if (n_gpr < MAX_GPRARGS)
	      *p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 1;
	    else
	      *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 1;
	    break;
 
	  default:
	    FFI_ASSERT (0);
	    break;
        }

      /* If this is a struct passed via pointer, we need to
	 actually retrieve that pointer.  */
      if (deref_struct_pointer)
	*p_arg = *(void **)*p_arg;
    }


  /* Call the target function.  */
  (closure->fun) (closure->cif, rvalue, avalue, closure->user_data);

  /* Convert the return value.  */
  switch (closure->cif->rtype->type)
    {
      /* Void is easy, and so is struct.  */
      case FFI_TYPE_VOID:
      case FFI_TYPE_STRUCT:
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
      case FFI_TYPE_LONGDOUBLE:
#endif
	break;

      /* Floating point values are returned in fpr 0.  */
      case FFI_TYPE_FLOAT:
	p_fpr[0] = (long long) *(unsigned int *) rvalue << 32;
	break;

      case FFI_TYPE_DOUBLE:
	p_fpr[0] = *(unsigned long long *) rvalue;
	break;

      /* Integer values are returned in gpr 2 (and gpr 3
	 for 64-bit values on 31-bit machines).  */
      case FFI_TYPE_UINT64:
      case FFI_TYPE_SINT64:
#ifdef __s390x__
	p_gpr[0] = *(unsigned long *) rvalue;
#else
	p_gpr[0] = ((unsigned long *) rvalue)[0],
	p_gpr[1] = ((unsigned long *) rvalue)[1];
#endif
	break;

      case FFI_TYPE_POINTER:
      case FFI_TYPE_UINT32:
      case FFI_TYPE_UINT16:
      case FFI_TYPE_UINT8:
	p_gpr[0] = *(unsigned long *) rvalue;
	break;

      case FFI_TYPE_INT:
      case FFI_TYPE_SINT32:
      case FFI_TYPE_SINT16:
      case FFI_TYPE_SINT8:
	p_gpr[0] = *(signed long *) rvalue;
	break;

      default:
        FFI_ASSERT (0);
        break;
    }
}
示例#15
0
static unsigned
aarch64_prep_args (struct call_context *context, unsigned char *stack,
		   extended_cif *ecif)
{
  int i;
  struct arg_state state;

  arg_init (&state, ALIGN(ecif->cif->bytes, 16));

  for (i = 0; i < ecif->cif->nargs; i++)
    {
      ffi_type *ty = ecif->cif->arg_types[i];
      switch (ty->type)
	{
	case FFI_TYPE_VOID:
	  FFI_ASSERT (0);
	  break;

	/* If the argument is a basic type the argument is allocated to an
	   appropriate register, or if none are available, to the stack.  */
	case FFI_TYPE_FLOAT:
	case FFI_TYPE_DOUBLE:
#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
	case FFI_TYPE_LONGDOUBLE:
#endif
	case FFI_TYPE_UINT8:
	case FFI_TYPE_SINT8:
	case FFI_TYPE_UINT16:
	case FFI_TYPE_SINT16:
	case FFI_TYPE_UINT32:
	case FFI_TYPE_INT:
	case FFI_TYPE_SINT32:
	case FFI_TYPE_POINTER:
	case FFI_TYPE_UINT64:
	case FFI_TYPE_SINT64:
	  copy_to_register_or_stack (context, stack, &state,
				     ecif->avalue[i], ty->type);
	  break;

	case FFI_TYPE_STRUCT:
	  if (is_hfa (ty))
	    {
	      copy_hfa_to_reg_or_stack (ecif->avalue[i], ty, context,
					stack, &state);
	    }
	  else if (ty->size > 16)
	    {
	      /* If the argument is a composite type that is larger than 16
		 bytes, then the argument has been copied to memory, and
		 the argument is replaced by a pointer to the copy.  */

	      copy_to_register_or_stack (context, stack, &state,
					 &(ecif->avalue[i]), FFI_TYPE_POINTER);
	    }
	  else if (available_x (&state) >= (ty->size + 7) / 8)
	    {
	      /* If the argument is a composite type and the size in
		 double-words is not more than the number of available
		 X registers, then the argument is copied into consecutive
		 X registers.  */
	      int j;
	      for (j = 0; j < (ty->size + 7) / 8; j++)
		{
		  memcpy (allocate_to_x (context, &state),
			  &(((UINT64 *) ecif->avalue[i])[j]),
			  sizeof (UINT64));
		}
	    }
	  else
	    {
	      /* Otherwise, there are insufficient X registers. Further X
		 register allocations are prevented, the NSAA is adjusted
		 (by allocate_to_stack ()) and the argument is copied to
		 memory at the adjusted NSAA.  */
	      state.ngrn = N_X_ARG_REG;

	      memcpy (allocate_to_stack (&state, stack, ty->alignment,
					 ty->size), ecif->avalue + i, ty->size);
	    }
	  break;

	default:
	  FFI_ASSERT (0);
	  break;
	}
    }

  return ecif->cif->aarch64_flags;
}
示例#16
0
unsigned int ffi_prep_args(char *stack, extended_cif *ecif)
{
  register unsigned int i;
  register void **p_argv;
  register char *argp;
  register ffi_type **p_arg;
#ifndef X86_WIN64
  const int cabi = ecif->cif->abi;
  const int dir = (cabi == FFI_PASCAL || cabi == FFI_REGISTER) ? -1 : +1;
  unsigned int stack_args_count = 0;
  void *p_stack_data[3];
  char *argp2 = stack;
#else
  #define dir 1
#endif

  argp = stack;

  if ((ecif->cif->flags == FFI_TYPE_STRUCT
       || ecif->cif->flags == FFI_TYPE_MS_STRUCT)
#ifdef X86_WIN64
      && ((ecif->cif->rtype->size & (1 | 2 | 4 | 8)) == 0)
#endif
      )
    {
#ifndef X86_WIN64
      /* For fastcall/thiscall/register this is first register-passed
         argument.  */
      if (cabi == FFI_THISCALL || cabi == FFI_FASTCALL || cabi == FFI_REGISTER)
        {
          p_stack_data[stack_args_count] = argp;
          ++stack_args_count;
        }
#endif

      *(void **) argp = ecif->rvalue;
      argp += sizeof(void*);
    }

  p_arg  = ecif->cif->arg_types;
  p_argv = ecif->avalue;
  if (dir < 0)
    {
      const int nargs = ecif->cif->nargs - 1;
      if (nargs > 0)
      {
        p_arg  += nargs;
        p_argv += nargs;
      }
    }

  for (i = ecif->cif->nargs;
       i != 0;
       i--, p_arg += dir, p_argv += dir)
    {
      /* Align if necessary */
      if ((sizeof(void*) - 1) & (size_t) argp)
        argp = (char *) ALIGN(argp, sizeof(void*));

      size_t z = (*p_arg)->size;

#ifdef X86_WIN64
      if (z > FFI_SIZEOF_ARG
          || ((*p_arg)->type == FFI_TYPE_STRUCT
              && (z & (1 | 2 | 4 | 8)) == 0)
#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
          || ((*p_arg)->type == FFI_TYPE_LONGDOUBLE)
#endif
          )
        {
          z = FFI_SIZEOF_ARG;
          *(void **)argp = *p_argv;
        }
      else if ((*p_arg)->type == FFI_TYPE_FLOAT)
        {
          memcpy(argp, *p_argv, z);
        }
      else
#endif
      if (z < FFI_SIZEOF_ARG)
        {
          z = FFI_SIZEOF_ARG;
          switch ((*p_arg)->type)
            {
            case FFI_TYPE_SINT8:
              *(ffi_sarg *) argp = (ffi_sarg)*(SINT8 *)(* p_argv);
              break;

            case FFI_TYPE_UINT8:
              *(ffi_arg *) argp = (ffi_arg)*(UINT8 *)(* p_argv);
              break;

            case FFI_TYPE_SINT16:
              *(ffi_sarg *) argp = (ffi_sarg)*(SINT16 *)(* p_argv);
              break;

            case FFI_TYPE_UINT16:
              *(ffi_arg *) argp = (ffi_arg)*(UINT16 *)(* p_argv);
              break;

            case FFI_TYPE_SINT32:
              *(ffi_sarg *) argp = (ffi_sarg)*(SINT32 *)(* p_argv);
              break;

            case FFI_TYPE_UINT32:
              *(ffi_arg *) argp = (ffi_arg)*(UINT32 *)(* p_argv);
              break;

            case FFI_TYPE_STRUCT:
              *(ffi_arg *) argp = *(ffi_arg *)(* p_argv);
              break;

            default:
              FFI_ASSERT(0);
            }
        }
      else
        {
          memcpy(argp, *p_argv, z);
        }

#ifndef X86_WIN64
    /* For thiscall/fastcall/register convention register-passed arguments
       are the first two none-floating-point arguments with a size
       smaller or equal to sizeof (void*).  */
    if ((z == FFI_SIZEOF_ARG)
        && ((cabi == FFI_REGISTER)
          || (cabi == FFI_THISCALL && stack_args_count < 1)
          || (cabi == FFI_FASTCALL && stack_args_count < 2))
        && ((*p_arg)->type != FFI_TYPE_FLOAT && (*p_arg)->type != FFI_TYPE_STRUCT)
       )
      {
        if (dir < 0 && stack_args_count > 2)
          {
            /* Iterating arguments backwards, so first register-passed argument
               will be passed last. Shift temporary values to make place. */
            p_stack_data[0] = p_stack_data[1];
            p_stack_data[1] = p_stack_data[2];
            stack_args_count = 2;
          }

        p_stack_data[stack_args_count] = argp;
        ++stack_args_count;
      }
#endif

#ifdef X86_WIN64
      argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
#else
      argp += z;
#endif
    }

#ifndef X86_WIN64
  /* We need to move the register-passed arguments for thiscall/fastcall/register
     on top of stack, so that those can be moved to registers by call-handler.  */
  if (stack_args_count > 0)
    {
      if (dir < 0 && stack_args_count > 1)
        {
          /* Reverse order if iterating arguments backwards */
          ffi_arg tmp = *(ffi_arg*) p_stack_data[0];
          *(ffi_arg*) p_stack_data[0] = *(ffi_arg*) p_stack_data[stack_args_count - 1];
          *(ffi_arg*) p_stack_data[stack_args_count - 1] = tmp;
        }
      
      int i;
      for (i = 0; i < stack_args_count; i++)
        {
          if (p_stack_data[i] != argp2)
            {
              ffi_arg tmp = *(ffi_arg*) p_stack_data[i];
              memmove (argp2 + FFI_SIZEOF_ARG, argp2, (size_t) ((char*) p_stack_data[i] - (char*)argp2));
              *(ffi_arg *) argp2 = tmp;
            }

          argp2 += FFI_SIZEOF_ARG;
        }
    }

    return stack_args_count;
#endif
    return 0;
}
示例#17
0
/* Call a function with the provided arguments and capture the return
   value.  */
void
ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
{
  extended_cif ecif;

  ecif.cif = cif;
  ecif.avalue = avalue;
  ecif.rvalue = rvalue;

  switch (cif->abi)
    {
    case FFI_SYSV:
      {
        struct call_context context;
	size_t stack_bytes;

	/* Figure out the total amount of stack space we need, the
	   above call frame space needs to be 16 bytes aligned to
	   ensure correct alignment of the first object inserted in
	   that space hence the ALIGN applied to cif->bytes.*/
	stack_bytes = ALIGN(cif->bytes, 16);

	memset (&context, 0, sizeof (context));
        if (is_register_candidate (cif->rtype))
          {
            ffi_call_SYSV (aarch64_prep_args, &context, &ecif, stack_bytes, fn);
            switch (cif->rtype->type)
              {
              case FFI_TYPE_VOID:
              case FFI_TYPE_FLOAT:
              case FFI_TYPE_DOUBLE:
#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
              case FFI_TYPE_LONGDOUBLE:
#endif
              case FFI_TYPE_UINT8:
              case FFI_TYPE_SINT8:
              case FFI_TYPE_UINT16:
              case FFI_TYPE_SINT16:
              case FFI_TYPE_UINT32:
              case FFI_TYPE_SINT32:
              case FFI_TYPE_POINTER:
              case FFI_TYPE_UINT64:
              case FFI_TYPE_INT:
              case FFI_TYPE_SINT64:
		{
		  void *addr = get_basic_type_addr (cif->rtype->type,
						    &context, 0);
		  copy_basic_type (rvalue, addr, cif->rtype->type);
		  break;
		}

              case FFI_TYPE_STRUCT:
                if (is_hfa (cif->rtype))
		  {
		    int j;
		    unsigned short type = get_homogeneous_type (cif->rtype);
		    unsigned elems = element_count (cif->rtype);
		    for (j = 0; j < elems; j++)
		      {
			void *reg = get_basic_type_addr (type, &context, j);
			copy_basic_type (rvalue, reg, type);
			rvalue += get_basic_type_size (type);
		      }
		  }
                else if ((cif->rtype->size + 7) / 8 < N_X_ARG_REG)
                  {
                    size_t size = ALIGN (cif->rtype->size, sizeof (UINT64));
                    memcpy (rvalue, get_x_addr (&context, 0), size);
                  }
                else
                  {
                    FFI_ASSERT (0);
                  }
                break;

              default:
                FFI_ASSERT (0);
                break;
              }
          }
        else
          {
            memcpy (get_x_addr (&context, 8), &rvalue, sizeof (UINT64));
            ffi_call_SYSV (aarch64_prep_args, &context, &ecif,
			   stack_bytes, fn);
          }
        break;
      }

    default:
      FFI_ASSERT (0);
      break;
    }
}
示例#18
0
文件: ffi.c 项目: 620book/nu
ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs,
			ffi_type *rtype, ffi_type **atypes)
{
  unsigned bytes = 0;
  unsigned int i;
  ffi_type **ptr;

  FFI_ASSERT(cif != NULL);
  FFI_ASSERT((abi > FFI_FIRST_ABI) && (abi <= FFI_DEFAULT_ABI));

  cif->abi = abi;
  cif->arg_types = atypes;
  cif->nargs = nargs;
  cif->rtype = rtype;

  cif->flags = 0;

  /* Initialize the return type if necessary */
  if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK))
    return FFI_BAD_TYPEDEF;

  /* Perform a sanity check on the return type */
  FFI_ASSERT_VALID_TYPE(cif->rtype);

  /* x86-64 stack space allocation is handled in prep_machdep.  */
#if !defined __x86_64__ 
  /* Make space for the return structure pointer */
  if (cif->rtype->type == FFI_TYPE_STRUCT
#ifdef X86_DARWIN
      && (cif->rtype->size > 8)
#endif
     )
    bytes = STACK_ARG_SIZE(sizeof(void*));
#endif

  for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
    {

      /* Initialize any uninitialized aggregate type definitions */
      if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK))
	return FFI_BAD_TYPEDEF;

      /* Perform a sanity check on the argument type, do this
	 check after the initialization.  */
      FFI_ASSERT_VALID_TYPE(*ptr);

#if !defined __x86_64__ 
	{
	  /* Add any padding if necessary */
	  if (((*ptr)->alignment - 1) & bytes)
	    bytes = ALIGN(bytes, (*ptr)->alignment);

	  bytes += STACK_ARG_SIZE((*ptr)->size);
	}
#endif
    }

  cif->bytes = bytes;

  /* Perform machine dependent cif processing */
  return ffi_prep_cif_machdep(cif);
}
示例#19
0
文件: ffi.c 项目: microbang/libffi
/* ffi_prep_args is called by the assembly routine once stack space
   has been allocated for the function's arguments
   
   The vfp_space parameter is the load area for VFP regs, the return
   value is cif->vfp_used (word bitset of VFP regs used for passing
   arguments). These are only used for the VFP hard-float ABI.
*/
int ffi_prep_args(char *stack, extended_cif *ecif, float *vfp_space)
{
  register unsigned int i, vi = 0;
  register void **p_argv;
  register char *argp;
  register ffi_type **p_arg;

  argp = stack;

  if ( ecif->cif->flags == FFI_TYPE_STRUCT ) {
    *(void **) argp = ecif->rvalue;
    argp += 4;
  }

  p_argv = ecif->avalue;

  for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
       (i != 0);
       i--, p_arg++)
    {
      size_t z;

      /* Allocated in VFP registers. */
      if (ecif->cif->abi == FFI_VFP
	  && vi < ecif->cif->vfp_nargs && vfp_type_p (*p_arg))
	{
	  float* vfp_slot = vfp_space + ecif->cif->vfp_args[vi++];
	  if ((*p_arg)->type == FFI_TYPE_FLOAT)
	    *((float*)vfp_slot) = *((float*)*p_argv);
	  else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
	    *((double*)vfp_slot) = *((double*)*p_argv);
	  else
	    memcpy(vfp_slot, *p_argv, (*p_arg)->size);
	  p_argv++;
	  continue;
	}

      /* Align if necessary */
      if (((*p_arg)->alignment - 1) & (unsigned) argp) {
	argp = (char *) ALIGN(argp, (*p_arg)->alignment);
      }

      if ((*p_arg)->type == FFI_TYPE_STRUCT)
	argp = (char *) ALIGN(argp, 4);

	  z = (*p_arg)->size;
	  if (z < sizeof(int))
	    {
	      z = sizeof(int);
	      switch ((*p_arg)->type)
		{
		case FFI_TYPE_SINT8:
		  *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
		  break;
		  
		case FFI_TYPE_UINT8:
		  *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
		  break;
		  
		case FFI_TYPE_SINT16:
		  *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
		  break;
		  
		case FFI_TYPE_UINT16:
		  *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
		  break;
		  
		case FFI_TYPE_STRUCT:
		  memcpy(argp, *p_argv, (*p_arg)->size);
		  break;

		default:
		  FFI_ASSERT(0);
		}
	    }
	  else if (z == sizeof(int))
	    {
	      *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
	    }
	  else
	    {
	      memcpy(argp, *p_argv, z);
	    }
	  p_argv++;
	  argp += z;
    }

  /* Indicate the VFP registers used. */
  return ecif->cif->vfp_used;
}
示例#20
0
void ffi_prep_args(extended_cif *ecif, unsigned *const stack)
{
  const unsigned bytes = ecif->cif->bytes;
  const unsigned flags = ecif->cif->flags;

  /* 'stacktop' points at the previous backchain pointer.  */
  unsigned *const stacktop = stack + (bytes / sizeof(unsigned));

  /* 'fpr_base' points at the space for fpr1, and grows upwards as
     we use FPR registers.  */
  double *fpr_base = (double*) (stacktop - ASM_NEEDS_REGISTERS) - NUM_FPR_ARG_REGISTERS;
  int fparg_count = 0;


  /* 'next_arg' grows up as we put parameters in it.  */
  unsigned *next_arg = stack + 6; /* 6 reserved positions.  */

  int i = ecif->cif->nargs;
  double double_tmp;
  void **p_argv = ecif->avalue;
  unsigned gprvalue;
  ffi_type** ptr = ecif->cif->arg_types;
  char *dest_cpy;
  unsigned size_al = 0;

  /* Check that everything starts aligned properly.  */
  FFI_ASSERT(((unsigned)(char *)stack & 0xF) == 0);
  FFI_ASSERT(((unsigned)(char *)stacktop & 0xF) == 0);
  FFI_ASSERT((bytes & 0xF) == 0);

  /* Deal with return values that are actually pass-by-reference.
     Rule:
     Return values are referenced by r3, so r4 is the first parameter.  */

  if (flags & FLAG_RETVAL_REFERENCE)
    *next_arg++ = (unsigned)(char *)ecif->rvalue;

  /* Now for the arguments.  */
  for (;
       i > 0;
       i--, ptr++, p_argv++)
    {
      switch ((*ptr)->type)
	{
	/* If a floating-point parameter appears before all of the general-
	   purpose registers are filled, the corresponding GPRs that match
	   the size of the floating-point parameter are skipped.  */
	case FFI_TYPE_FLOAT:
	  double_tmp = *(float *)*p_argv;
	  if (fparg_count >= NUM_FPR_ARG_REGISTERS)
	    *(double *)next_arg = double_tmp;
	  else
	    *fpr_base++ = double_tmp;
	  next_arg++;
	  fparg_count++;
	  FFI_ASSERT(flags & FLAG_FP_ARGUMENTS);
	  break;

	case FFI_TYPE_DOUBLE:
	  double_tmp = *(double *)*p_argv;
	  if (fparg_count >= NUM_FPR_ARG_REGISTERS)
	    *(double *)next_arg = double_tmp;
	  else
	    *fpr_base++ = double_tmp;
	  next_arg += 2;
	  fparg_count++;
	  FFI_ASSERT(flags & FLAG_FP_ARGUMENTS);
	  break;

#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE

	case FFI_TYPE_LONGDOUBLE:
	  double_tmp = ((double *)*p_argv)[0];
	  if (fparg_count >= NUM_FPR_ARG_REGISTERS)
	    *(double *)next_arg = double_tmp;
	  else
	    *fpr_base++ = double_tmp;
	  next_arg += 2;
	  fparg_count++;
	  double_tmp = ((double *)*p_argv)[1];
	  if (fparg_count >= NUM_FPR_ARG_REGISTERS)
	    *(double *)next_arg = double_tmp;
	  else
	    *fpr_base++ = double_tmp;
	  next_arg += 2;
	  fparg_count++;
	  FFI_ASSERT(flags & FLAG_FP_ARGUMENTS);
	  break;
#endif
	case FFI_TYPE_UINT64:
	case FFI_TYPE_SINT64:
	  *(long long *)next_arg = *(long long *)*p_argv;
	  next_arg+=2;
	  break;
	case FFI_TYPE_UINT8:
	  gprvalue = *(unsigned char *)*p_argv;
	  goto putgpr;
	case FFI_TYPE_SINT8:
	  gprvalue = *(signed char *)*p_argv;
	  goto putgpr;
	case FFI_TYPE_UINT16:
	  gprvalue = *(unsigned short *)*p_argv;
	  goto putgpr;
	case FFI_TYPE_SINT16:
	  gprvalue = *(signed short *)*p_argv;
	  goto putgpr;

	case FFI_TYPE_STRUCT:
	  dest_cpy = (char *) next_arg;

	  /* Structures that match the basic modes (QI 1 byte, HI 2 bytes,
	     SI 4 bytes) are aligned as if they were those modes.
	     Structures with 3 byte in size are padded upwards.  */
	  size_al = (*ptr)->size;
	  /* If the first member of the struct is a double, then align
	     the struct to double-word.
	     Type 3 is defined in include/ffi.h. #define FFI_TYPE_DOUBLE 3.  */
	  if ((*ptr)->elements[0]->type == 3)
	    size_al = ALIGN((*ptr)->size, 8);
	  if (size_al < 3 && ecif->cif->abi == FFI_DARWIN)
	    dest_cpy += 4 - size_al;

	  memcpy((char *)dest_cpy, (char *)*p_argv, size_al);
	  next_arg += (size_al + 3) / 4;
	  break;

	case FFI_TYPE_INT:
	case FFI_TYPE_UINT32:
	case FFI_TYPE_SINT32:
	case FFI_TYPE_POINTER:
	  gprvalue = *(unsigned *)*p_argv;
	putgpr:
	  *next_arg++ = gprvalue;
	  break;
	default:
	  break;
	}
    }

  /* Check that we didn't overrun the stack...  */
  //FFI_ASSERT(gpr_base <= stacktop - ASM_NEEDS_REGISTERS);
  //FFI_ASSERT((unsigned *)fpr_base
  //	     <= stacktop - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS);
  //FFI_ASSERT(flags & FLAG_4_GPR_ARGUMENTS || intarg_count <= 4);
}
示例#21
0
int
ffi_closure_UNIX64_inner(ffi_closure *closure, va_list l, void *rp)
{
  ffi_cif *cif;
  void **avalue;
  ffi_type **arg_types;
  long i, avn, argn;

  cif = closure->cif;
  avalue = alloca(cif->nargs * sizeof(void *));

  argn = 0;

  i = 0;
  avn = cif->nargs;
  arg_types = cif->arg_types;
  
  /* Grab the addresses of the arguments from the stack frame.  */
  while (i < avn)
    {
      switch (arg_types[i]->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:
	  {
	    if (l->gp_offset > 48-8)
	      {
		avalue[i] = l->overflow_arg_area;
		l->overflow_arg_area = (char *)l->overflow_arg_area + 8;
	      }
	    else
	      {
		avalue[i] = (char *)l->reg_save_area + l->gp_offset;
		l->gp_offset += 8;
	      }
	  }
	  break;

	case FFI_TYPE_STRUCT:
	  /* FIXME  */
	  FFI_ASSERT(0);
	  break;

	case FFI_TYPE_DOUBLE:
	  {
	    if (l->fp_offset > 176-16)
	      {
		avalue[i] = l->overflow_arg_area;
		l->overflow_arg_area = (char *)l->overflow_arg_area + 8;
	      }
	    else
	      {
		avalue[i] = (char *)l->reg_save_area + l->fp_offset;
		l->fp_offset += 16;
	      }
	  }
#if DEBUG_FFI
	  fprintf (stderr, "double arg %d = %g\n", i, *(double *)avalue[i]);
#endif
	  break;
	  
	case FFI_TYPE_FLOAT:
	  {
	    if (l->fp_offset > 176-16)
	      {
		avalue[i] = l->overflow_arg_area;
		l->overflow_arg_area = (char *)l->overflow_arg_area + 8;
	      }
	    else
	      {
		avalue[i] = (char *)l->reg_save_area + l->fp_offset;
		l->fp_offset += 16;
	      }
	  }
#if DEBUG_FFI
	  fprintf (stderr, "float arg %d = %g\n", i, *(float *)avalue[i]);
#endif
	  break;
	  
	default:
	  FFI_ASSERT(0);
	}

      argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
      i++;
    }

  /* Invoke the closure.  */
  (closure->fun) (cif, rp, avalue, closure->user_data);

  /* FIXME: Structs not supported.  */
  FFI_ASSERT(cif->rtype->type != FFI_TYPE_STRUCT);

  /* Tell ffi_closure_UNIX64 how to perform return type promotions.  */

  return cif->rtype->type;
}
示例#22
0
void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
{
  extended_cif ecif;

  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                     */

#ifdef X86_WIN64
  if (rvalue == NULL
      && cif->flags == FFI_TYPE_STRUCT
      && cif->rtype->size != 1 && cif->rtype->size != 2
      && cif->rtype->size != 4 && cif->rtype->size != 8)
    {
      ecif.rvalue = alloca((cif->rtype->size + 0xF) & ~0xF);
    }
#else
  if (rvalue == NULL
      && cif->flags == FFI_TYPE_STRUCT)
    {
      ecif.rvalue = alloca(cif->rtype->size);
    }
#endif
  else
    ecif.rvalue = rvalue;
    
  
  switch (cif->abi) 
    {
#ifdef X86_WIN64
    case FFI_WIN64:
      {
        // Make copies of all struct arguments
        // NOTE: not sure if responsibility should be here or in caller
        unsigned int i;
        for (i=0; i < cif->nargs;i++) {
          size_t size = cif->arg_types[i]->size;
          if ((cif->arg_types[i]->type == FFI_TYPE_STRUCT
               && (size != 1 && size != 2 && size != 4 && size != 8))
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
              || cif->arg_types[i]->type == FFI_TYPE_LONGDOUBLE
#endif
              )
            {
              void *local = alloca(size);
              memcpy(local, avalue[i], size);
              avalue[i] = local;
            }
        }
        ffi_call_win64(ffi_prep_args, &ecif, cif->bytes,
                       cif->flags, ecif.rvalue, fn);
      }
      break;
#else
    case FFI_SYSV:
      ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
                    fn);
      break;
#ifdef X86_WIN32
    case FFI_STDCALL:
      ffi_call_STDCALL(ffi_prep_args, &ecif, cif->bytes, cif->flags,
                       ecif.rvalue, fn);
      break;
#endif /* X86_WIN32 */
#endif /* X86_WIN64 */
    default:
      FFI_ASSERT(0);
      break;
    }
}
示例#23
0
文件: ffi.c 项目: alex/libffi
void ffi_prep_args(char *stack, extended_cif *ecif)
{
  register unsigned int i;
  register void **p_argv;
  register char *argp;
  register ffi_type **p_arg;
#ifdef X86_WIN32
  size_t p_stack_args[2];
  void *p_stack_data[2];
  char *argp2 = stack;
  int stack_args_count = 0;
  int cabi = ecif->cif->abi;
#endif

  argp = stack;

  if ((ecif->cif->flags == FFI_TYPE_STRUCT
       || ecif->cif->flags == FFI_TYPE_MS_STRUCT)
#ifdef X86_WIN64
      && (ecif->cif->rtype->size != 1 && ecif->cif->rtype->size != 2
          && ecif->cif->rtype->size != 4 && ecif->cif->rtype->size != 8)
#endif
      )
    {
      *(void **) argp = ecif->rvalue;
#ifdef X86_WIN32
      /* For fastcall/thiscall this is first register-passed
         argument.  */
      if (cabi == FFI_THISCALL || cabi == FFI_FASTCALL)
	{
	  p_stack_args[stack_args_count] = sizeof (void*);
	  p_stack_data[stack_args_count] = argp;
	  ++stack_args_count;
	}
#endif
      argp += sizeof(void*);
    }

  p_argv = ecif->avalue;

  for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
       i != 0;
       i--, p_arg++)
    {
      size_t z;

      /* Align if necessary */
      if ((sizeof(void*) - 1) & (size_t) argp)
        argp = (char *) ALIGN(argp, sizeof(void*));

      z = (*p_arg)->size;
#ifdef X86_WIN64
      if (z > sizeof(ffi_arg)
          || ((*p_arg)->type == FFI_TYPE_STRUCT
              && (z != 1 && z != 2 && z != 4 && z != 8))
#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
          || ((*p_arg)->type == FFI_TYPE_LONGDOUBLE)
#endif
          )
        {
          z = sizeof(ffi_arg);
          *(void **)argp = *p_argv;
        }
      else if ((*p_arg)->type == FFI_TYPE_FLOAT)
        {
          memcpy(argp, *p_argv, z);
        }
      else
#endif
      if (z < sizeof(ffi_arg))
        {
          z = sizeof(ffi_arg);
          switch ((*p_arg)->type)
            {
            case FFI_TYPE_SINT8:
              *(ffi_sarg *) argp = (ffi_sarg)*(SINT8 *)(* p_argv);
              break;

            case FFI_TYPE_UINT8:
              *(ffi_arg *) argp = (ffi_arg)*(UINT8 *)(* p_argv);
              break;

            case FFI_TYPE_SINT16:
              *(ffi_sarg *) argp = (ffi_sarg)*(SINT16 *)(* p_argv);
              break;

            case FFI_TYPE_UINT16:
              *(ffi_arg *) argp = (ffi_arg)*(UINT16 *)(* p_argv);
              break;

            case FFI_TYPE_SINT32:
              *(ffi_sarg *) argp = (ffi_sarg)*(SINT32 *)(* p_argv);
              break;

            case FFI_TYPE_UINT32:
              *(ffi_arg *) argp = (ffi_arg)*(UINT32 *)(* p_argv);
              break;

            case FFI_TYPE_STRUCT:
              *(ffi_arg *) argp = *(ffi_arg *)(* p_argv);
              break;

            default:
              FFI_ASSERT(0);
            }
        }
      else
        {
          memcpy(argp, *p_argv, z);
        }

#ifdef X86_WIN32
    /* For thiscall/fastcall convention register-passed arguments
       are the first two none-floating-point arguments with a size
       smaller or equal to sizeof (void*).  */
    if ((cabi == FFI_THISCALL && stack_args_count < 1)
        || (cabi == FFI_FASTCALL && stack_args_count < 2))
      {
	if (z <= 4
	    && ((*p_arg)->type != FFI_TYPE_FLOAT
	        && (*p_arg)->type != FFI_TYPE_STRUCT))
	  {
	    p_stack_args[stack_args_count] = z;
	    p_stack_data[stack_args_count] = argp;
	    ++stack_args_count;
	  }
      }
#endif
      p_argv++;
#ifdef X86_WIN64
      argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
#else
      argp += z;
#endif
    }

#ifdef X86_WIN32
  /* We need to move the register-passed arguments for thiscall/fastcall
     on top of stack, so that those can be moved to registers ecx/edx by
     call-handler.  */
  if (stack_args_count > 0)
    {
      size_t zz = (p_stack_args[0] + 3) & ~3;
      char *h;

      /* Move first argument to top-stack position.  */
      if (p_stack_data[0] != argp2)
	{
	  h = alloca (zz + 1);
	  memcpy (h, p_stack_data[0], zz);
	  memmove (argp2 + zz, argp2,
	           (size_t) ((char *) p_stack_data[0] - (char*)argp2));
	  memcpy (argp2, h, zz);
	}

      argp2 += zz;
      --stack_args_count;
      if (zz > 4)
	stack_args_count = 0;

      /* If we have a second argument, then move it on top
         after the first one.  */
      if (stack_args_count > 0 && p_stack_data[1] != argp2)
	{
	  zz = p_stack_args[1];
	  zz = (zz + 3) & ~3;
	  h = alloca (zz + 1);
	  h = alloca (zz + 1);
	  memcpy (h, p_stack_data[1], zz);
	  memmove (argp2 + zz, argp2, (size_t) ((char*) p_stack_data[1] - (char*)argp2));
	  memcpy (argp2, h, zz);
	}
    }
#endif
  return;
}
示例#24
0
文件: ffi.c 项目: czankel/xtensa-ffi
void *ffi_prep_args(char *stack, extended_cif *ecif)
{
  register unsigned int i;
  register void **p_argv;
  register char *argp;
  register ffi_type **p_arg;
  register int count = 0;

  p_argv = ecif->avalue;
  argp = stack;

  for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
       (i != 0);
       i--, p_arg++)
    {
      size_t z;
      
      z = (*p_arg)->size;

      if ((*p_arg)->type == FFI_TYPE_STRUCT)
	{
	  z = sizeof(void*);
	  *(void **) argp = *p_argv;
	} 
      else if (z < sizeof(int))
	{
	  z = sizeof(int);
	  switch ((*p_arg)->type)
	    {
	    case FFI_TYPE_SINT8:
	      *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
	      break;
	      
	    case FFI_TYPE_UINT8:
	      *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
	      break;
	      
	    case FFI_TYPE_SINT16:
	      *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
	      break;
		  
	    case FFI_TYPE_UINT16:
	      *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
	      break;
		  
	    default:
	      FFI_ASSERT(0);
	    }
	}
      else if (z == sizeof(int))
	{
	  *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
	}
      else
	{
	  memcpy(argp, *p_argv, z);
	}
      p_argv++;
      argp += z;
      count += z;
    }

  return (stack + ((count > 24) ? 24 : ALIGN_DOWN(count, 8)));
}
示例#25
0
/*@-exportheader@*/
void ffi_prep_args(char *stack, extended_cif *ecif)
/*@=exportheader@*/
{
  register unsigned int i;
  register void **p_argv;
  register char *argp;
  register ffi_type **p_arg;

  argp = stack;

  if (ecif->cif->flags == FFI_TYPE_STRUCT)
    {
      *(void **) argp = ecif->rvalue;
      argp += 4;
    }

  p_argv = ecif->avalue;

  for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
       i != 0;
       i--, p_arg++)
    {
      size_t z;

      /* Align if necessary */
      if ((sizeof(int) - 1) & (unsigned) argp)
	argp = (char *) ALIGN(argp, sizeof(int));

      z = (*p_arg)->size;
      if (z < sizeof(int))
	{
	  z = sizeof(int);
	  switch ((*p_arg)->type)
	    {
	    case FFI_TYPE_SINT8:
	      *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
	      break;

	    case FFI_TYPE_UINT8:
	      *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
	      break;

	    case FFI_TYPE_SINT16:
	      *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
	      break;

	    case FFI_TYPE_UINT16:
	      *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
	      break;

	    case FFI_TYPE_SINT32:
	      *(signed int *) argp = (signed int)*(SINT32 *)(* p_argv);
	      break;

	    case FFI_TYPE_UINT32:
	      *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
	      break;

	    case FFI_TYPE_STRUCT:
	      *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
	      break;

	    default:
	      FFI_ASSERT(0);
	    }
	}
      else
	{
	  memcpy(argp, *p_argv, z);
	}
      p_argv++;
      argp += z;
    }
  
  return;
}
示例#26
0
void *
ffi_prep_args (void *stack, extended_cif *ecif)
{
  unsigned int i;
  void **p_argv;
  char *argp;
  ffi_type **p_arg;
  void *struct_value_ptr;

  argp = stack;

  if (ecif->cif->rtype->type == FFI_TYPE_STRUCT
      && !ecif->cif->flags)
    struct_value_ptr = ecif->rvalue;
  else
    struct_value_ptr = NULL;

  p_argv = ecif->avalue;

  for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
       i != 0;
       i--, p_arg++)
    {
      size_t z;

      z = (*p_arg)->size;
      if (z < sizeof (int))
	{
	  switch ((*p_arg)->type)
	    {
	    case FFI_TYPE_SINT8:
	      *(signed int *) argp = (signed int) *(SINT8 *) *p_argv;
	      break;

	    case FFI_TYPE_UINT8:
	      *(unsigned int *) argp = (unsigned int) *(UINT8 *) *p_argv;
	      break;

	    case FFI_TYPE_SINT16:
	      *(signed int *) argp = (signed int) *(SINT16 *) *p_argv;
	      break;

	    case FFI_TYPE_UINT16:
	      *(unsigned int *) argp = (unsigned int) *(UINT16 *) *p_argv;
	      break;

	    case FFI_TYPE_STRUCT:
	      memcpy (argp + sizeof (int) - z, *p_argv, z);
	      break;

	    default:
	      FFI_ASSERT (0);
	    }
	  z = sizeof (int);
	}
      else
	{
	  memcpy (argp, *p_argv, z);

	  /* Align if necessary.  */
	  if ((sizeof(int) - 1) & z)
	    z = ALIGN(z, sizeof(int));
	}

      p_argv++;
      argp += z;
    }

  return struct_value_ptr;
}
示例#27
0
void
ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
{
  enum x86_64_reg_class classes[MAX_CLASSES];
  char *stack, *argp;
  ffi_type **arg_types;
  int gprcount, ssecount, ngpr, nsse, i, avn;
  _Bool ret_in_memory;
  struct register_args *reg_args;

  /* Can't call 32-bit mode from 64-bit mode.  */
  FFI_ASSERT (cif->abi == FFI_UNIX64);

  /* If the return value is a struct and we don't have a return value
     address then we need to make one.  Note the setting of flags to
     VOID above in ffi_prep_cif_machdep.  */
  ret_in_memory = (cif->rtype->type == FFI_TYPE_STRUCT
		   && (cif->flags & 0xff) == FFI_TYPE_VOID);
  if (rvalue == NULL && ret_in_memory)
    rvalue = alloca (cif->rtype->size);

  /* Allocate the space for the arguments, plus 4 words of temp space.  */
  stack = alloca (sizeof (struct register_args) + cif->bytes + 4*8);
  reg_args = (struct register_args *) stack;
  argp = stack + sizeof (struct register_args);

  gprcount = ssecount = 0;

  /* If the return value is passed in memory, add the pointer as the
     first integer argument.  */
  if (ret_in_memory)
    reg_args->gpr[gprcount++] = (long) rvalue;

  avn = cif->nargs;
  arg_types = cif->arg_types;

  for (i = 0; i < avn; ++i)
    {
      size_t size = arg_types[i]->size;
      int n;

      n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse);
      if (n == 0
	  || gprcount + ngpr > MAX_GPR_REGS
	  || ssecount + nsse > MAX_SSE_REGS)
	{
	  long align = arg_types[i]->alignment;

	  /* Stack arguments are *always* at least 8 byte aligned.  */
	  if (align < 8)
	    align = 8;

	  /* Pass this argument in memory.  */
	  argp = (void *) ALIGN (argp, align);
	  memcpy (argp, avalue[i], size);
	  argp += size;
	}
      else
	{
	  /* The argument is passed entirely in registers.  */
	  char *a = (char *) avalue[i];
	  int j;

	  for (j = 0; j < n; j++, a += 8, size -= 8)
	    {
	      switch (classes[j])
		{
		case X86_64_INTEGER_CLASS:
		case X86_64_INTEGERSI_CLASS:
		  reg_args->gpr[gprcount] = 0;
		  memcpy (&reg_args->gpr[gprcount], a, size < 8 ? size : 8);
		  gprcount++;
		  break;
		case X86_64_SSE_CLASS:
		case X86_64_SSEDF_CLASS:
		  reg_args->sse[ssecount].m[0] = *(UINT64 *) a;
		  reg_args->sse[ssecount].m[1] = 0;
		  reg_args->sse[ssecount].m[2] = 0;	
		  reg_args->sse[ssecount].m[3] = 0;	
		  reg_args->sse[ssecount].m[4] = 0;	
		  reg_args->sse[ssecount].m[5] = 0;	
		  reg_args->sse[ssecount].m[6] = 0;	
		  reg_args->sse[ssecount].m[7] = 0;	
		  ssecount++;
		  break;
		case X86_64_SSESF_CLASS:
		  reg_args->sse[ssecount].m[0] = *(UINT32 *) a;
		  reg_args->sse[ssecount].m[1] = 0;
		  reg_args->sse[ssecount].m[2] = 0;	
		  reg_args->sse[ssecount].m[3] = 0;	
		  reg_args->sse[ssecount].m[4] = 0;	
		  reg_args->sse[ssecount].m[5] = 0;	
		  reg_args->sse[ssecount].m[6] = 0;	
		  reg_args->sse[ssecount].m[7] = 0;	
		  ssecount++;
		  break;
		default:
		  abort();
		}
	    }
	}
    }

  ffi_call_unix64 (stack, cif->bytes + sizeof (struct register_args),
		   cif->flags, rvalue, fn, ssecount);
}
示例#28
0
static void *
allocate_to_v (struct call_context *context, struct arg_state *state)
{
  FFI_ASSERT (state->nsrn < N_V_ARG_REG);
  return get_v_addr (context, (state->nsrn)++);
}
示例#29
0
文件: ffi.c 项目: 5432935/crossbridge
void ffi_prep_args(char *stack, extended_cif *ecif)
{
  unsigned int i;
  int tmp;
  unsigned int avn;
  void **p_argv;
  char *argp;
  ffi_type **p_arg;

  tmp = 0;
  argp = stack;

  if (ecif->cif->rtype->type == FFI_TYPE_STRUCT && ecif->cif->rtype->size > 8)
    {
      *(void **) argp = ecif->rvalue;
      argp += 4;
    }

  avn = ecif->cif->nargs;
  p_argv = ecif->avalue;

  for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
       (i != 0) && (avn != 0);
       i--, p_arg++)
    {
      size_t z;

      /* Align if necessary.  */
      if (((*p_arg)->alignment - 1) & (unsigned) argp)
	argp = (char *) ALIGN (argp, (*p_arg)->alignment);

      if (avn != 0) 
	{
	  avn--;
	  z = (*p_arg)->size;
	  if (z < sizeof (int))
	    {
	      z = sizeof (int);

	      switch ((*p_arg)->type)
		{
		case FFI_TYPE_SINT8:
		  *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
		  break;
		  
		case FFI_TYPE_UINT8:
		  *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
		  break;
		  
		case FFI_TYPE_SINT16:
		  *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
		  break;
		  
		case FFI_TYPE_UINT16:
		  *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
		  break;
		  
		case FFI_TYPE_STRUCT:
	  	  z = (*p_arg)->size;
	  	  if ((*p_arg)->alignment != 1)
		    memcpy (argp, *p_argv, z);
		  else
		    memcpy (argp + 4 - z, *p_argv, z);
	  	  z = sizeof (int);
		  break;

		default:
		  FFI_ASSERT(0);
		}
	    }
	  else if (z == sizeof (int))
	    {
	       *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
	    }
	  else
	    {
	      if ((*p_arg)->type == FFI_TYPE_STRUCT)
	        {
		  if (z > 8)
		    {
		      *(unsigned int *) argp = (unsigned int)(void *)(* p_argv);
		      z = sizeof(void *);
		    }
		  else
		    {
	              memcpy(argp, *p_argv, z);
		      z = 8;
		    }
	        }
	      else
	        {
		  /* Double or long long 64bit.  */
	          memcpy (argp, *p_argv, z);
	        }
	    }
	  p_argv++;
	  argp += z;
	}
    }
  
  return;
}
示例#30
0
static void
ffi_prep_args (unsigned char *stack, extended_cif *ecif)
{
  /* The stack space will be filled with those areas:

	FPR argument register save area     (highest addresses)
	GPR argument register save area
	temporary struct copies
	overflow argument area              (lowest addresses)

     We set up the following pointers:

        p_fpr: bottom of the FPR area (growing upwards)
	p_gpr: bottom of the GPR area (growing upwards)
	p_ov: bottom of the overflow area (growing upwards)
	p_struct: top of the struct copy area (growing downwards)

     All areas are kept aligned to twice the word size.  */

  int gpr_off = ecif->cif->bytes;
  int fpr_off = gpr_off + ROUND_SIZE (MAX_GPRARGS * sizeof (long));

  unsigned long long *p_fpr = (unsigned long long *)(stack + fpr_off);
  unsigned long *p_gpr = (unsigned long *)(stack + gpr_off);
  unsigned char *p_struct = (unsigned char *)p_gpr;
  unsigned long *p_ov = (unsigned long *)stack;

  int n_fpr = 0;
  int n_gpr = 0;
  int n_ov = 0;

  ffi_type **ptr;
  void **p_argv = ecif->avalue;
  int i;
 
  /* If we returning a structure then we set the first parameter register
     to the address of where we are returning this structure.  */

  if (ecif->cif->flags == FFI390_RET_STRUCT)
    p_gpr[n_gpr++] = (unsigned long) ecif->rvalue;

  /* Now for the arguments.  */
 
  for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs;
       i > 0;
       i--, ptr++, p_argv++)
    {
      void *arg = *p_argv;
      int type = (*ptr)->type;

#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
      /* 16-byte long double is passed like a struct.  */
      if (type == FFI_TYPE_LONGDOUBLE)
	type = FFI_TYPE_STRUCT;
#endif

      /* Check how a structure type is passed.  */
      if (type == FFI_TYPE_STRUCT)
	{
	  type = ffi_check_struct_type (*ptr);

	  /* If we pass the struct via pointer, copy the data.  */
	  if (type == FFI_TYPE_POINTER)
	    {
	      p_struct -= ROUND_SIZE ((*ptr)->size);
	      memcpy (p_struct, (char *)arg, (*ptr)->size);
	      arg = &p_struct;
	    }
	}

      /* Now handle all primitive int/pointer/float data types.  */
      switch (type) 
	{
	  case FFI_TYPE_DOUBLE:
	    if (n_fpr < MAX_FPRARGS)
	      p_fpr[n_fpr++] = *(unsigned long long *) arg;
	    else
#ifdef __s390x__
	      p_ov[n_ov++] = *(unsigned long *) arg;
#else
	      p_ov[n_ov++] = ((unsigned long *) arg)[0],
	      p_ov[n_ov++] = ((unsigned long *) arg)[1];
#endif
	    break;
	
	  case FFI_TYPE_FLOAT:
	    if (n_fpr < MAX_FPRARGS)
	      p_fpr[n_fpr++] = (long long) *(unsigned int *) arg << 32;
	    else
	      p_ov[n_ov++] = *(unsigned int *) arg;
	    break;

	  case FFI_TYPE_POINTER:
	    if (n_gpr < MAX_GPRARGS)
	      p_gpr[n_gpr++] = (unsigned long)*(unsigned char **) arg;
	    else
	      p_ov[n_ov++] = (unsigned long)*(unsigned char **) arg;
	    break;
 
	  case FFI_TYPE_UINT64:
	  case FFI_TYPE_SINT64:
#ifdef __s390x__
	    if (n_gpr < MAX_GPRARGS)
	      p_gpr[n_gpr++] = *(unsigned long *) arg;
	    else
	      p_ov[n_ov++] = *(unsigned long *) arg;
#else
	    if (n_gpr == MAX_GPRARGS-1)
	      n_gpr = MAX_GPRARGS;
	    if (n_gpr < MAX_GPRARGS)
	      p_gpr[n_gpr++] = ((unsigned long *) arg)[0],
	      p_gpr[n_gpr++] = ((unsigned long *) arg)[1];
	    else
	      p_ov[n_ov++] = ((unsigned long *) arg)[0],
	      p_ov[n_ov++] = ((unsigned long *) arg)[1];
#endif
	    break;
 
	  case FFI_TYPE_UINT32:
	    if (n_gpr < MAX_GPRARGS)
	      p_gpr[n_gpr++] = *(unsigned int *) arg;
	    else
	      p_ov[n_ov++] = *(unsigned int *) arg;
	    break;
 
	  case FFI_TYPE_INT:
	  case FFI_TYPE_SINT32:
	    if (n_gpr < MAX_GPRARGS)
	      p_gpr[n_gpr++] = *(signed int *) arg;
	    else
	      p_ov[n_ov++] = *(signed int *) arg;
	    break;
 
	  case FFI_TYPE_UINT16:
	    if (n_gpr < MAX_GPRARGS)
	      p_gpr[n_gpr++] = *(unsigned short *) arg;
	    else
	      p_ov[n_ov++] = *(unsigned short *) arg;
	    break;
 
	  case FFI_TYPE_SINT16:
	    if (n_gpr < MAX_GPRARGS)
	      p_gpr[n_gpr++] = *(signed short *) arg;
	    else
	      p_ov[n_ov++] = *(signed short *) arg;
	    break;

	  case FFI_TYPE_UINT8:
	    if (n_gpr < MAX_GPRARGS)
	      p_gpr[n_gpr++] = *(unsigned char *) arg;
	    else
	      p_ov[n_ov++] = *(unsigned char *) arg;
	    break;
 
	  case FFI_TYPE_SINT8:
	    if (n_gpr < MAX_GPRARGS)
	      p_gpr[n_gpr++] = *(signed char *) arg;
	    else
	      p_ov[n_ov++] = *(signed char *) arg;
	    break;
 
	  default:
	    FFI_ASSERT (0);
	    break;
        }
    }
}