Merge pull request #194 from amodra/master
Correct powerpc sysv stack argument accounting
This commit is contained in:
@@ -93,7 +93,7 @@ ffi_prep_cif_sysv_core (ffi_cif *cif)
|
|||||||
{
|
{
|
||||||
ffi_type **ptr;
|
ffi_type **ptr;
|
||||||
unsigned bytes;
|
unsigned bytes;
|
||||||
unsigned i, fparg_count = 0, intarg_count = 0;
|
unsigned i, fpr_count = 0, gpr_count = 0, stack_count = 0;
|
||||||
unsigned flags = cif->flags;
|
unsigned flags = cif->flags;
|
||||||
unsigned struct_copy_size = 0;
|
unsigned struct_copy_size = 0;
|
||||||
unsigned type = cif->rtype->type;
|
unsigned type = cif->rtype->type;
|
||||||
@@ -155,7 +155,7 @@ ffi_prep_cif_sysv_core (ffi_cif *cif)
|
|||||||
flags |= FLAG_RETURNS_SMST;
|
flags |= FLAG_RETURNS_SMST;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
intarg_count++;
|
gpr_count++;
|
||||||
flags |= FLAG_RETVAL_REFERENCE;
|
flags |= FLAG_RETVAL_REFERENCE;
|
||||||
/* Fall through. */
|
/* Fall through. */
|
||||||
case FFI_TYPE_VOID:
|
case FFI_TYPE_VOID:
|
||||||
@@ -182,24 +182,41 @@ ffi_prep_cif_sysv_core (ffi_cif *cif)
|
|||||||
{
|
{
|
||||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||||
case FFI_TYPE_LONGDOUBLE:
|
case FFI_TYPE_LONGDOUBLE:
|
||||||
fparg_count++;
|
if (fpr_count >= NUM_FPR_ARG_REGISTERS - 1)
|
||||||
/* Fall thru */
|
{
|
||||||
|
fpr_count = NUM_FPR_ARG_REGISTERS;
|
||||||
|
/* 8-byte align long doubles. */
|
||||||
|
stack_count += stack_count & 1;
|
||||||
|
stack_count += 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fpr_count += 2;
|
||||||
|
#ifdef __NO_FPRS__
|
||||||
|
return FFI_BAD_ABI;
|
||||||
#endif
|
#endif
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
case FFI_TYPE_DOUBLE:
|
case FFI_TYPE_DOUBLE:
|
||||||
fparg_count++;
|
if (fpr_count >= NUM_FPR_ARG_REGISTERS)
|
||||||
/* If this FP arg is going on the stack, it must be
|
{
|
||||||
8-byte-aligned. */
|
/* 8-byte align doubles. */
|
||||||
if (fparg_count > NUM_FPR_ARG_REGISTERS
|
stack_count += stack_count & 1;
|
||||||
&& intarg_count >= NUM_GPR_ARG_REGISTERS
|
stack_count += 2;
|
||||||
&& intarg_count % 2 != 0)
|
}
|
||||||
intarg_count++;
|
else
|
||||||
|
fpr_count += 1;
|
||||||
#ifdef __NO_FPRS__
|
#ifdef __NO_FPRS__
|
||||||
return FFI_BAD_ABI;
|
return FFI_BAD_ABI;
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FFI_TYPE_FLOAT:
|
case FFI_TYPE_FLOAT:
|
||||||
fparg_count++;
|
if (fpr_count >= NUM_FPR_ARG_REGISTERS)
|
||||||
|
/* Yes, we don't follow the ABI, but neither does gcc. */
|
||||||
|
stack_count += 1;
|
||||||
|
else
|
||||||
|
fpr_count += 1;
|
||||||
#ifdef __NO_FPRS__
|
#ifdef __NO_FPRS__
|
||||||
return FFI_BAD_ABI;
|
return FFI_BAD_ABI;
|
||||||
#endif
|
#endif
|
||||||
@@ -208,11 +225,13 @@ ffi_prep_cif_sysv_core (ffi_cif *cif)
|
|||||||
case FFI_TYPE_UINT128:
|
case FFI_TYPE_UINT128:
|
||||||
/* A long double in FFI_LINUX_SOFT_FLOAT can use only a set
|
/* A long double in FFI_LINUX_SOFT_FLOAT can use only a set
|
||||||
of four consecutive gprs. If we do not have enough, we
|
of four consecutive gprs. If we do not have enough, we
|
||||||
have to adjust the intarg_count value. */
|
have to adjust the gpr_count value. */
|
||||||
if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3
|
if (gpr_count >= NUM_GPR_ARG_REGISTERS - 3)
|
||||||
&& intarg_count < NUM_GPR_ARG_REGISTERS)
|
gpr_count = NUM_GPR_ARG_REGISTERS;
|
||||||
intarg_count = NUM_GPR_ARG_REGISTERS;
|
if (gpr_count >= NUM_GPR_ARG_REGISTERS)
|
||||||
intarg_count += 4;
|
stack_count += 4;
|
||||||
|
else
|
||||||
|
gpr_count += 4;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FFI_TYPE_UINT64:
|
case FFI_TYPE_UINT64:
|
||||||
@@ -225,10 +244,14 @@ ffi_prep_cif_sysv_core (ffi_cif *cif)
|
|||||||
Also, only certain register pairs can be used for
|
Also, only certain register pairs can be used for
|
||||||
passing long long int -- specifically (r3,r4), (r5,r6),
|
passing long long int -- specifically (r3,r4), (r5,r6),
|
||||||
(r7,r8), (r9,r10). */
|
(r7,r8), (r9,r10). */
|
||||||
if (intarg_count == NUM_GPR_ARG_REGISTERS-1
|
gpr_count += gpr_count & 1;
|
||||||
|| intarg_count % 2 != 0)
|
if (gpr_count >= NUM_GPR_ARG_REGISTERS)
|
||||||
intarg_count++;
|
{
|
||||||
intarg_count += 2;
|
stack_count += stack_count & 1;
|
||||||
|
stack_count += 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
gpr_count += 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FFI_TYPE_STRUCT:
|
case FFI_TYPE_STRUCT:
|
||||||
@@ -249,7 +272,10 @@ ffi_prep_cif_sysv_core (ffi_cif *cif)
|
|||||||
case FFI_TYPE_SINT8:
|
case FFI_TYPE_SINT8:
|
||||||
/* Everything else is passed as a 4-byte word in a GPR, either
|
/* Everything else is passed as a 4-byte word in a GPR, either
|
||||||
the object itself or a pointer to it. */
|
the object itself or a pointer to it. */
|
||||||
intarg_count++;
|
if (gpr_count >= NUM_GPR_ARG_REGISTERS)
|
||||||
|
stack_count += 1;
|
||||||
|
else
|
||||||
|
gpr_count += 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -257,22 +283,19 @@ ffi_prep_cif_sysv_core (ffi_cif *cif)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fparg_count != 0)
|
if (fpr_count != 0)
|
||||||
flags |= FLAG_FP_ARGUMENTS;
|
flags |= FLAG_FP_ARGUMENTS;
|
||||||
if (intarg_count > 4)
|
if (gpr_count > 4)
|
||||||
flags |= FLAG_4_GPR_ARGUMENTS;
|
flags |= FLAG_4_GPR_ARGUMENTS;
|
||||||
if (struct_copy_size != 0)
|
if (struct_copy_size != 0)
|
||||||
flags |= FLAG_ARG_NEEDS_COPY;
|
flags |= FLAG_ARG_NEEDS_COPY;
|
||||||
|
|
||||||
/* Space for the FPR registers, if needed. */
|
/* Space for the FPR registers, if needed. */
|
||||||
if (fparg_count != 0)
|
if (fpr_count != 0)
|
||||||
bytes += NUM_FPR_ARG_REGISTERS * sizeof (double);
|
bytes += NUM_FPR_ARG_REGISTERS * sizeof (double);
|
||||||
|
|
||||||
/* Stack space. */
|
/* Stack space. */
|
||||||
if (intarg_count > NUM_GPR_ARG_REGISTERS)
|
bytes += stack_count * sizeof (int);
|
||||||
bytes += (intarg_count - NUM_GPR_ARG_REGISTERS) * sizeof (int);
|
|
||||||
if (fparg_count > NUM_FPR_ARG_REGISTERS)
|
|
||||||
bytes += (fparg_count - NUM_FPR_ARG_REGISTERS) * sizeof (double);
|
|
||||||
|
|
||||||
/* The stack space allocated needs to be a multiple of 16 bytes. */
|
/* The stack space allocated needs to be a multiple of 16 bytes. */
|
||||||
bytes = (bytes + 15) & ~0xF;
|
bytes = (bytes + 15) & ~0xF;
|
||||||
@@ -367,13 +390,13 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
|
|||||||
/* 'gpr_base' points at the space for gpr3, and grows upwards as
|
/* 'gpr_base' points at the space for gpr3, and grows upwards as
|
||||||
we use GPR registers. */
|
we use GPR registers. */
|
||||||
valp gpr_base;
|
valp gpr_base;
|
||||||
int intarg_count;
|
valp gpr_end;
|
||||||
|
|
||||||
#ifndef __NO_FPRS__
|
#ifndef __NO_FPRS__
|
||||||
/* 'fpr_base' points at the space for fpr1, and grows upwards as
|
/* 'fpr_base' points at the space for fpr1, and grows upwards as
|
||||||
we use FPR registers. */
|
we use FPR registers. */
|
||||||
valp fpr_base;
|
valp fpr_base;
|
||||||
int fparg_count;
|
valp fpr_end;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* 'copy_space' grows down as we put structures in it. It should
|
/* 'copy_space' grows down as we put structures in it. It should
|
||||||
@@ -405,11 +428,11 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
|
|||||||
unsigned gprvalue;
|
unsigned gprvalue;
|
||||||
|
|
||||||
stacktop.c = (char *) stack + bytes;
|
stacktop.c = (char *) stack + bytes;
|
||||||
gpr_base.u = stacktop.u - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS;
|
gpr_end.u = stacktop.u - ASM_NEEDS_REGISTERS;
|
||||||
intarg_count = 0;
|
gpr_base.u = gpr_end.u - NUM_GPR_ARG_REGISTERS;
|
||||||
#ifndef __NO_FPRS__
|
#ifndef __NO_FPRS__
|
||||||
fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS;
|
fpr_end.d = gpr_base.d;
|
||||||
fparg_count = 0;
|
fpr_base.d = fpr_end.d - NUM_FPR_ARG_REGISTERS;
|
||||||
copy_space.c = ((flags & FLAG_FP_ARGUMENTS) ? fpr_base.c : gpr_base.c);
|
copy_space.c = ((flags & FLAG_FP_ARGUMENTS) ? fpr_base.c : gpr_base.c);
|
||||||
#else
|
#else
|
||||||
copy_space.c = gpr_base.c;
|
copy_space.c = gpr_base.c;
|
||||||
@@ -425,10 +448,7 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
|
|||||||
|
|
||||||
/* Deal with return values that are actually pass-by-reference. */
|
/* Deal with return values that are actually pass-by-reference. */
|
||||||
if (flags & FLAG_RETVAL_REFERENCE)
|
if (flags & FLAG_RETVAL_REFERENCE)
|
||||||
{
|
*gpr_base.u++ = (unsigned) (char *) ecif->rvalue;
|
||||||
*gpr_base.u++ = (unsigned long) (char *) ecif->rvalue;
|
|
||||||
intarg_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now for the arguments. */
|
/* Now for the arguments. */
|
||||||
p_argv.v = ecif->avalue;
|
p_argv.v = ecif->avalue;
|
||||||
@@ -448,14 +468,11 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
|
|||||||
case FFI_TYPE_LONGDOUBLE:
|
case FFI_TYPE_LONGDOUBLE:
|
||||||
double_tmp = (*p_argv.d)[0];
|
double_tmp = (*p_argv.d)[0];
|
||||||
|
|
||||||
if (fparg_count >= NUM_FPR_ARG_REGISTERS - 1)
|
if (fpr_base.d >= fpr_end.d - 1)
|
||||||
{
|
{
|
||||||
if (intarg_count >= NUM_GPR_ARG_REGISTERS
|
fpr_base.d = fpr_end.d;
|
||||||
&& intarg_count % 2 != 0)
|
if (((next_arg.u - stack) & 1) != 0)
|
||||||
{
|
next_arg.u += 1;
|
||||||
intarg_count++;
|
|
||||||
next_arg.u++;
|
|
||||||
}
|
|
||||||
*next_arg.d = double_tmp;
|
*next_arg.d = double_tmp;
|
||||||
next_arg.u += 2;
|
next_arg.u += 2;
|
||||||
double_tmp = (*p_argv.d)[1];
|
double_tmp = (*p_argv.d)[1];
|
||||||
@@ -468,42 +485,33 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
|
|||||||
double_tmp = (*p_argv.d)[1];
|
double_tmp = (*p_argv.d)[1];
|
||||||
*fpr_base.d++ = double_tmp;
|
*fpr_base.d++ = double_tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
fparg_count += 2;
|
|
||||||
FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
|
FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
|
||||||
break;
|
break;
|
||||||
# endif
|
# endif
|
||||||
case FFI_TYPE_DOUBLE:
|
case FFI_TYPE_DOUBLE:
|
||||||
double_tmp = **p_argv.d;
|
double_tmp = **p_argv.d;
|
||||||
|
|
||||||
if (fparg_count >= NUM_FPR_ARG_REGISTERS)
|
if (fpr_base.d >= fpr_end.d)
|
||||||
{
|
{
|
||||||
if (intarg_count >= NUM_GPR_ARG_REGISTERS
|
if (((next_arg.u - stack) & 1) != 0)
|
||||||
&& intarg_count % 2 != 0)
|
next_arg.u += 1;
|
||||||
{
|
|
||||||
intarg_count++;
|
|
||||||
next_arg.u++;
|
|
||||||
}
|
|
||||||
*next_arg.d = double_tmp;
|
*next_arg.d = double_tmp;
|
||||||
next_arg.u += 2;
|
next_arg.u += 2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
*fpr_base.d++ = double_tmp;
|
*fpr_base.d++ = double_tmp;
|
||||||
fparg_count++;
|
|
||||||
FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
|
FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FFI_TYPE_FLOAT:
|
case FFI_TYPE_FLOAT:
|
||||||
double_tmp = **p_argv.f;
|
double_tmp = **p_argv.f;
|
||||||
if (fparg_count >= NUM_FPR_ARG_REGISTERS)
|
if (fpr_base.d >= fpr_end.d)
|
||||||
{
|
{
|
||||||
*next_arg.f = (float) double_tmp;
|
*next_arg.f = (float) double_tmp;
|
||||||
next_arg.u += 1;
|
next_arg.u += 1;
|
||||||
intarg_count++;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
*fpr_base.d++ = double_tmp;
|
*fpr_base.d++ = double_tmp;
|
||||||
fparg_count++;
|
|
||||||
FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
|
FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
|
||||||
break;
|
break;
|
||||||
#endif /* have FPRs */
|
#endif /* have FPRs */
|
||||||
@@ -513,42 +521,34 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
|
|||||||
is passed in four consecutive GPRs if available. A maximum of 2
|
is passed in four consecutive GPRs if available. A maximum of 2
|
||||||
long doubles can be passed in gprs. If we do not have 4 GPRs
|
long doubles can be passed in gprs. If we do not have 4 GPRs
|
||||||
left, the long double is passed on the stack, 4-byte aligned. */
|
left, the long double is passed on the stack, 4-byte aligned. */
|
||||||
{
|
if (gpr_base.u >= gpr_end.u - 3)
|
||||||
unsigned int int_tmp;
|
{
|
||||||
unsigned int ii;
|
unsigned int ii;
|
||||||
if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3)
|
gpr_base.u = gpr_end.u;
|
||||||
{
|
for (ii = 0; ii < 4; ii++)
|
||||||
if (intarg_count < NUM_GPR_ARG_REGISTERS)
|
{
|
||||||
intarg_count = NUM_GPR_ARG_REGISTERS;
|
unsigned int int_tmp = (*p_argv.ui)[ii];
|
||||||
for (ii = 0; ii < 4; ii++)
|
*next_arg.u++ = int_tmp;
|
||||||
{
|
}
|
||||||
int_tmp = (*p_argv.ui)[ii];
|
}
|
||||||
*next_arg.u++ = int_tmp;
|
else
|
||||||
}
|
{
|
||||||
}
|
unsigned int ii;
|
||||||
else
|
for (ii = 0; ii < 4; ii++)
|
||||||
{
|
{
|
||||||
for (ii = 0; ii < 4; ii++)
|
unsigned int int_tmp = (*p_argv.ui)[ii];
|
||||||
{
|
*gpr_base.u++ = int_tmp;
|
||||||
int_tmp = (*p_argv.ui)[ii];
|
}
|
||||||
*gpr_base.u++ = int_tmp;
|
}
|
||||||
}
|
break;
|
||||||
}
|
|
||||||
intarg_count += 4;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT64:
|
case FFI_TYPE_UINT64:
|
||||||
case FFI_TYPE_SINT64:
|
case FFI_TYPE_SINT64:
|
||||||
if (intarg_count == NUM_GPR_ARG_REGISTERS-1)
|
if (gpr_base.u >= gpr_end.u - 1)
|
||||||
intarg_count++;
|
|
||||||
if (intarg_count >= NUM_GPR_ARG_REGISTERS)
|
|
||||||
{
|
{
|
||||||
if (intarg_count % 2 != 0)
|
gpr_base.u = gpr_end.u;
|
||||||
{
|
if (((next_arg.u - stack) & 1) != 0)
|
||||||
intarg_count++;
|
next_arg.u++;
|
||||||
next_arg.u++;
|
|
||||||
}
|
|
||||||
*next_arg.ll = **p_argv.ll;
|
*next_arg.ll = **p_argv.ll;
|
||||||
next_arg.u += 2;
|
next_arg.u += 2;
|
||||||
}
|
}
|
||||||
@@ -559,14 +559,10 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
|
|||||||
(r5,r6), (r7,r8), (r9,r10). If next arg is long long
|
(r5,r6), (r7,r8), (r9,r10). If next arg is long long
|
||||||
but not correct starting register of pair then skip
|
but not correct starting register of pair then skip
|
||||||
until the proper starting register. */
|
until the proper starting register. */
|
||||||
if (intarg_count % 2 != 0)
|
if (((gpr_end.u - gpr_base.u) & 1) != 0)
|
||||||
{
|
gpr_base.u++;
|
||||||
intarg_count ++;
|
|
||||||
gpr_base.u++;
|
|
||||||
}
|
|
||||||
*gpr_base.ll++ = **p_argv.ll;
|
*gpr_base.ll++ = **p_argv.ll;
|
||||||
}
|
}
|
||||||
intarg_count += 2;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FFI_TYPE_STRUCT:
|
case FFI_TYPE_STRUCT:
|
||||||
@@ -601,29 +597,22 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
|
|||||||
gprvalue = **p_argv.ui;
|
gprvalue = **p_argv.ui;
|
||||||
|
|
||||||
putgpr:
|
putgpr:
|
||||||
if (intarg_count >= NUM_GPR_ARG_REGISTERS)
|
if (gpr_base.u >= gpr_end.u)
|
||||||
*next_arg.u++ = gprvalue;
|
*next_arg.u++ = gprvalue;
|
||||||
else
|
else
|
||||||
*gpr_base.u++ = gprvalue;
|
*gpr_base.u++ = gprvalue;
|
||||||
intarg_count++;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check that we didn't overrun the stack... */
|
/* Check that we didn't overrun the stack... */
|
||||||
FFI_ASSERT (copy_space.c >= next_arg.c);
|
FFI_ASSERT (copy_space.c >= next_arg.c);
|
||||||
FFI_ASSERT (gpr_base.u <= stacktop.u - ASM_NEEDS_REGISTERS);
|
FFI_ASSERT (gpr_base.u <= gpr_end.u);
|
||||||
/* The assert below is testing that the number of integer arguments agrees
|
|
||||||
with the number found in ffi_prep_cif_machdep(). However, intarg_count
|
|
||||||
is incremented whenever we place an FP arg on the stack, so account for
|
|
||||||
that before our assert test. */
|
|
||||||
#ifndef __NO_FPRS__
|
#ifndef __NO_FPRS__
|
||||||
if (fparg_count > NUM_FPR_ARG_REGISTERS)
|
FFI_ASSERT (fpr_base.u <= fpr_end.u);
|
||||||
intarg_count -= fparg_count - NUM_FPR_ARG_REGISTERS;
|
|
||||||
FFI_ASSERT (fpr_base.u
|
|
||||||
<= stacktop.u - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS);
|
|
||||||
#endif
|
#endif
|
||||||
FFI_ASSERT (flags & FLAG_4_GPR_ARGUMENTS || intarg_count <= 4);
|
FFI_ASSERT (((flags & FLAG_4_GPR_ARGUMENTS) != 0)
|
||||||
|
== (gpr_end.u - gpr_base.u < 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MIN_CACHE_LINE_SIZE 8
|
#define MIN_CACHE_LINE_SIZE 8
|
||||||
|
|||||||
Reference in New Issue
Block a user