mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-20 03:30:27 +02:00
Fix argument and return value alignment in `scm_i_foreign_call'.
* libguile/foreign.c (scm_i_foreign_call): Fix the computation of ARG_SIZE wrt. alignment. Arrange so that the address ARGS[i] is aligned, rather than checking whether OFF is aligned. Have the RVALUE be at least word-aligned, which fixes calls to `char'-returning functions on `armv5tel-*-linux-gnueabi'.
This commit is contained in:
parent
1880c97df1
commit
86425e2653
1 changed files with 21 additions and 16 deletions
|
@ -24,6 +24,8 @@
|
||||||
|
|
||||||
#include <alignof.h>
|
#include <alignof.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#include "libguile/_scm.h"
|
#include "libguile/_scm.h"
|
||||||
#include "libguile/bytevectors.h"
|
#include "libguile/bytevectors.h"
|
||||||
#include "libguile/instructions.h"
|
#include "libguile/instructions.h"
|
||||||
|
@ -985,32 +987,35 @@ scm_i_foreign_call (SCM foreign, const SCM *argv)
|
||||||
/* Argument pointers. */
|
/* Argument pointers. */
|
||||||
args = alloca (sizeof (void *) * cif->nargs);
|
args = alloca (sizeof (void *) * cif->nargs);
|
||||||
|
|
||||||
/* Compute the amount of memory needed to store all the argument values.
|
/* Compute the worst-case amount of memory needed to store all the argument
|
||||||
Note: as of libffi 3.0.9 `cif->bytes' is undocumented and is zero, so it
|
values. Note: as of libffi 3.0.9 `cif->bytes' is undocumented and is zero,
|
||||||
can't be used for that purpose. */
|
so it can't be used for that purpose. */
|
||||||
for (i = 0, arg_size = 0;
|
for (i = 0, arg_size = 0; i < cif->nargs; i++)
|
||||||
i < cif->nargs;
|
arg_size += cif->arg_types[i]->size + cif->arg_types[i]->alignment - 1;
|
||||||
i++, arg_size)
|
|
||||||
arg_size += ROUND_UP (cif->arg_types[i]->size,
|
|
||||||
cif->arg_types[i]->alignment);
|
|
||||||
|
|
||||||
/* Space for argument values, followed by return value. */
|
/* Space for argument values, followed by return value. */
|
||||||
data = alloca (arg_size
|
data = alloca (arg_size + cif->rtype->size
|
||||||
+ ROUND_UP (cif->rtype->size, cif->rtype->alignment));
|
+ max (sizeof (void *), cif->rtype->alignment));
|
||||||
|
|
||||||
/* Unpack ARGV to native values, setting ARGV pointers. */
|
/* Unpack ARGV to native values, setting ARGV pointers. */
|
||||||
for (i = 0, off = 0;
|
for (i = 0, off = 0;
|
||||||
i < cif->nargs;
|
i < cif->nargs;
|
||||||
off += cif->arg_types[i]->size, i++)
|
off = (scm_t_uint8 *) args[i] - data + cif->arg_types[i]->size,
|
||||||
|
i++)
|
||||||
{
|
{
|
||||||
off = ROUND_UP (off, cif->arg_types[i]->alignment);
|
/* Suitably align the storage area for argument I. */
|
||||||
args[i] = data + off;
|
args[i] = (void *) ROUND_UP ((scm_t_uintptr) data + off,
|
||||||
|
cif->arg_types[i]->alignment);
|
||||||
|
assert ((scm_t_uintptr) args[i] % cif->arg_types[i]->alignment == 0);
|
||||||
unpack (cif->arg_types[i], args[i], argv[i]);
|
unpack (cif->arg_types[i], args[i], argv[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Prepare space for the return value. */
|
/* Prepare space for the return value. On some platforms, such as
|
||||||
off = ROUND_UP (off, cif->rtype->alignment);
|
`armv5tel-*-linux-gnueabi', the return value has to be at least
|
||||||
rvalue = data + off;
|
word-aligned, even if its type doesn't have any alignment requirement as is
|
||||||
|
the case with `char'. */
|
||||||
|
rvalue = (void *) ROUND_UP ((scm_t_uintptr) data + off,
|
||||||
|
max (sizeof (void *), cif->rtype->alignment));
|
||||||
|
|
||||||
/* off we go! */
|
/* off we go! */
|
||||||
ffi_call (cif, func, rvalue, args);
|
ffi_call (cif, func, rvalue, args);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue