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); }
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); } }
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; } }