summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAnthony Green <green@moxielogic.com>2022-05-29 10:12:30 -0400
committerAnthony Green <green@moxielogic.com>2022-05-29 10:12:30 -0400
commit36b265ae438a364722c98136ba79cb450a48fca3 (patch)
treefcd23d6b33c57a25bb53c1152297d634482d72b8 /src
parentc248764d3391a460cdd31a1cae82281fd6dfbecd (diff)
downloadlibffi-36b265ae438a364722c98136ba79cb450a48fca3.tar.gz
m32r: pass copies of large structs
Diffstat (limited to 'src')
-rw-r--r--src/m32r/ffi.c45
1 files changed, 31 insertions, 14 deletions
diff --git a/src/m32r/ffi.c b/src/m32r/ffi.c
index ab8fc4e..6fab50b 100644
--- a/src/m32r/ffi.c
+++ b/src/m32r/ffi.c
@@ -1,8 +1,9 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 2004 Renesas Technology
Copyright (c) 2008 Red Hat, Inc.
-
- M32R Foreign Function Interface
+ Copyright (c) 2022 Anthony Green
+
+ M32R Foreign Function Interface
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@@ -63,7 +64,7 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
if (((*p_arg)->alignment - 1) & (unsigned) argp)
argp = (char *) FFI_ALIGN (argp, (*p_arg)->alignment);
- if (avn != 0)
+ if (avn != 0)
{
avn--;
z = (*p_arg)->size;
@@ -76,19 +77,19 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
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)
@@ -131,7 +132,7 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
argp += z;
}
}
-
+
return;
}
@@ -178,24 +179,40 @@ extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
{
extended_cif ecif;
+ ffi_type **arg_types = cif->arg_types;
+ int i, nargs = cif->nargs;
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) &&
+ if ((rvalue == NULL) &&
(cif->rtype->type == FFI_TYPE_STRUCT))
{
ecif.rvalue = alloca (cif->rtype->size);
}
else
- ecif.rvalue = rvalue;
-
- switch (cif->abi)
+ ecif.rvalue = rvalue;
+
+ /* If we have any large structure arguments, make a copy so we are passing
+ by value. */
+ for (i = 0; i < nargs; i++)
+ {
+ ffi_type *at = arg_types[i];
+ int size = at->size;
+ if (at->type == FFI_TYPE_STRUCT && size > 4)
+ {
+ char *argcopy = alloca (size);
+ memcpy (argcopy, avalue[i], size);
+ avalue[i] = argcopy;
+ }
+ }
+
+ switch (cif->abi)
{
case FFI_SYSV:
- ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes,
+ ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes,
cif->flags, ecif.rvalue, fn);
if (cif->rtype->type == FFI_TYPE_STRUCT)
{