@@ -691,7 +691,7 @@
case FFI_TYPE_STRUCT:
/*
* 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
+ * are returned in r3/r4. The FFI_GCC_SYSV ABI instead returns them
* in memory.
*
* NOTE: The assembly code can safely assume that it just needs to
@@ -700,7 +700,10 @@
* set.
*/
if (cif->abi == FFI_SYSV && size <= 8)
- flags |= FLAG_RETURNS_SMST;
+ {
+ flags |= FLAG_RETURNS_SMST;
+ break;
+ }
intarg_count++;
flags |= FLAG_RETVAL_REFERENCE;
/* Fall through. */
@@ -919,30 +922,25 @@
{
/*
* 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
+ * 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.
+ * We bounce-buffer SYSV small struct return values so that sysv.S
+ * can write 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);
- }
+ 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);
switch (cif->abi)
{
@@ -967,7 +965,21 @@
/* Check for a bounce-buffered return value */
if (rvalue && ecif.rvalue == smst_buffer)
- memcpy(rvalue, smst_buffer, rsize);
+ {
+ 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. */
+ if (rsize <= 4)
+ memcpy (rvalue, (char *) smst_buffer + 4 - rsize, rsize);
+ /* The SYSV ABI returns a structure of up to 8 bytes in size
+ left-padded in r3/r4. */
+ else if (rsize <= 8)
+ memcpy (rvalue, (char *) smst_buffer + 8 - rsize, rsize);
+ else
+#endif
+ memcpy (rvalue, smst_buffer, rsize);
+ }
}