Пример #1
0
void
ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
{
  /*
   * The final SYSV ABI says that structures smaller or equal 8 bytes
   * are returned in r3/r4. The FFI_GCC_SYSV ABI instead returns them
   * in memory.
   *
   * Just to keep things simple for the assembly code, we will always
   * bounce-buffer struct return values less than or equal to 8 bytes.
   * This allows the ASM to handle SYSV small structures by directly
   * writing r3 and r4 to memory without worrying about struct size.
   */
  unsigned int smst_buffer[2];
  extended_cif ecif;
  unsigned int rsize = 0;

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

  /* Ensure that we have a valid struct return value */
  ecif.rvalue = rvalue;
  if (cif->rtype->type == FFI_TYPE_STRUCT) {
    rsize = cif->rtype->size;
    if (rsize <= 8)
      ecif.rvalue = smst_buffer;
    else if (!rvalue)
      ecif.rvalue = alloca(rsize);
  }

  switch (cif->abi)
    {
#ifndef POWERPC64
# ifndef __NO_FPRS__
    case FFI_SYSV:
    case FFI_GCC_SYSV:
    case FFI_LINUX:
# endif
    case FFI_LINUX_SOFT_FLOAT:
      ffi_call_SYSV (&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn);
      break;
#else
    case FFI_LINUX64:
      ffi_call_LINUX64 (&ecif, -(REALLYLONG) cif->bytes, cif->flags, ecif.rvalue, fn);
      break;
#endif
    default:
      FFI_ASSERT (0);
      break;
    }

  /* Check for a bounce-buffered return value */
  if (rvalue && ecif.rvalue == smst_buffer)
    memcpy(rvalue, smst_buffer, rsize);
}
Пример #2
0
void
ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
{
  /* The final SYSV ABI says that structures smaller or equal 8 bytes
     are returned in r3/r4.  A draft ABI used by linux instead returns
     them in memory.

     We bounce-buffer SYSV small struct return values so that sysv.S
     can write r3 and r4 to memory without worrying about struct size.
   
     For ELFv2 ABI, use a bounce buffer for homogeneous structs too,
     for similar reasons.  */
  unsigned long smst_buffer[8];
  extended_cif ecif;

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

  ecif.rvalue = rvalue;
  if ((cif->flags & FLAG_RETURNS_SMST) != 0)
      ecif.rvalue = smst_buffer;
  /* Ensure that we have a valid struct return value.
     FIXME: Isn't this just papering over a user problem?  */
  else if (!rvalue && cif->rtype->type == FFI_TYPE_STRUCT)
    ecif.rvalue = alloca (cif->rtype->size);

#ifdef POWERPC64
      ffi_call_LINUX64 (&ecif, -(long) cif->bytes, cif->flags, ecif.rvalue, fn);
#else
  ffi_call_SYSV (&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn);
#endif

  /* Check for a bounce-buffered return value */
  if (rvalue && ecif.rvalue == smst_buffer)
    {
      unsigned int rsize = cif->rtype->size;
#ifndef __LITTLE_ENDIAN__
      /* The SYSV ABI returns a structure of up to 4 bytes in size
	 left-padded in r3.  */
# ifndef POWERPC64
      if (rsize <= 4)
	memcpy (rvalue, (char *) smst_buffer + 4 - rsize, rsize);
      else
# endif
	/* The SYSV ABI returns a structure of up to 8 bytes in size
	   left-padded in r3/r4, and the ELFv2 ABI similarly returns a
	   structure of up to 8 bytes in size left-padded in r3.  */
	if (rsize <= 8)
	  memcpy (rvalue, (char *) smst_buffer + 8 - rsize, rsize);
	else
#endif
	  memcpy (rvalue, smst_buffer, rsize);
    }
}
Пример #3
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		        */

  if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT))
    {
      ecif.rvalue = alloca(cif->rtype->size);
    }
  else
    ecif.rvalue = rvalue;


  switch (cif->abi)
    {
#ifndef POWERPC64
    case FFI_SYSV:
    case FFI_GCC_SYSV:
    case FFI_LINUX:
    case FFI_LINUX_SOFT_FLOAT:
      ffi_call_SYSV (&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn);
      break;
#else
    case FFI_LINUX64:
      ffi_call_LINUX64 (&ecif, -(long) cif->bytes, cif->flags, ecif.rvalue, fn);
      break;
#endif
    default:
      FFI_ASSERT (0);
      break;
    }
}