re PR libffi/60073 (64-bit libffi.call/cls_double_va.c FAILs after recent modification)

PR libffi/60073
	* src/sparc/v8.S: Assemble only if !SPARC64.
	* src/sparc/v9.S: Remove obsolete comment.
	* src/sparc/ffitarget.h (enum ffi_abi): Add FFI_COMPAT_V9.
	(V8_ABI_P): New macro.
	(V9_ABI_P): Likewise.
	(FFI_EXTRA_CIF_FIELDS): Define only if SPARC64.
	* src/sparc/ffi.c (ffi_prep_args_v8): Compile only if !SPARC64.
	(ffi_prep_args_v9): Compile only if SPARC64.
	(ffi_prep_cif_machdep_core): Use V9_ABI_P predicate.
	(ffi_prep_cif_machdep): Guard access to nfixedargs field.
	(ffi_prep_cif_machdep_var): Likewise.
	(ffi_v9_layout_struct): Compile only if SPARC64.
	(ffi_call): Deal with FFI_V8PLUS and FFI_COMPAT_V9 and fix warnings.
	(ffi_prep_closure_loc): Use V9_ABI_P and V8_ABI_P predicates.
	(ffi_closure_sparc_inner_v8): Compile only if !SPARC64.
	(ffi_closure_sparc_inner_v9): Compile only if SPARC64.  Guard access
	to nfixedargs field.

From-SVN: r207822
This commit is contained in:
Eric Botcazou 2014-02-17 12:00:04 +00:00 committed by Eric Botcazou
parent 583a9919ad
commit 248d745ac2
5 changed files with 276 additions and 206 deletions

View File

@ -1,3 +1,24 @@
2014-02-17 Eric Botcazou <ebotcazou@adacore.com>
PR libffi/60073
* src/sparc/v8.S: Assemble only if !SPARC64.
* src/sparc/v9.S: Remove obsolete comment.
* src/sparc/ffitarget.h (enum ffi_abi): Add FFI_COMPAT_V9.
(V8_ABI_P): New macro.
(V9_ABI_P): Likewise.
(FFI_EXTRA_CIF_FIELDS): Define only if SPARC64.
* src/sparc/ffi.c (ffi_prep_args_v8): Compile only if !SPARC64.
(ffi_prep_args_v9): Compile only if SPARC64.
(ffi_prep_cif_machdep_core): Use V9_ABI_P predicate.
(ffi_prep_cif_machdep): Guard access to nfixedargs field.
(ffi_prep_cif_machdep_var): Likewise.
(ffi_v9_layout_struct): Compile only if SPARC64.
(ffi_call): Deal with FFI_V8PLUS and FFI_COMPAT_V9 and fix warnings.
(ffi_prep_closure_loc): Use V9_ABI_P and V8_ABI_P predicates.
(ffi_closure_sparc_inner_v8): Compile only if !SPARC64.
(ffi_closure_sparc_inner_v9): Compile only if SPARC64. Guard access
to nfixedargs field.
2014-02-13 Eric Botcazou <ebotcazou@adacore.com>
PR libffi/60073

View File

@ -1,7 +1,7 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 2011 Anthony Green
Copyright (c) 1996, 2003-2004, 2007-2008 Red Hat, Inc.
SPARC Foreign Function Interface
Permission is hereby granted, free of charge, to any person obtaining
@ -34,93 +34,10 @@
/* ffi_prep_args is called by the assembly routine once stack space
has been allocated for the function's arguments */
void ffi_prep_args_v8(char *stack, extended_cif *ecif)
{
int i;
void **p_argv;
char *argp;
ffi_type **p_arg;
#ifdef SPARC64
/* Skip 16 words for the window save area */
argp = stack + 16*sizeof(int);
/* This should only really be done when we are returning a structure,
however, it's faster just to do it all the time...
if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) */
*(int *) argp = (long)ecif->rvalue;
/* And 1 word for the structure return value. */
argp += sizeof(int);
#ifdef USING_PURIFY
/* Purify will probably complain in our assembly routine, unless we
zero out this memory. */
((int*)argp)[0] = 0;
((int*)argp)[1] = 0;
((int*)argp)[2] = 0;
((int*)argp)[3] = 0;
((int*)argp)[4] = 0;
((int*)argp)[5] = 0;
#endif
p_argv = ecif->avalue;
for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++)
{
size_t z;
if ((*p_arg)->type == FFI_TYPE_STRUCT
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|| (*p_arg)->type == FFI_TYPE_LONGDOUBLE
#endif
)
{
*(unsigned int *) argp = (unsigned long)(* p_argv);
z = sizeof(int);
}
else
{
z = (*p_arg)->size;
if (z < sizeof(int))
{
z = sizeof(int);
switch ((*p_arg)->type)
{
case FFI_TYPE_SINT8:
*(signed int *) argp = *(SINT8 *)(* p_argv);
break;
case FFI_TYPE_UINT8:
*(unsigned int *) argp = *(UINT8 *)(* p_argv);
break;
case FFI_TYPE_SINT16:
*(signed int *) argp = *(SINT16 *)(* p_argv);
break;
case FFI_TYPE_UINT16:
*(unsigned int *) argp = *(UINT16 *)(* p_argv);
break;
default:
FFI_ASSERT(0);
}
}
else
{
memcpy(argp, *p_argv, z);
}
}
p_argv++;
argp += z;
}
return;
}
int ffi_prep_args_v9(char *stack, extended_cif *ecif)
int
ffi_prep_args_v9(char *stack, extended_cif *ecif)
{
int i, ret = 0;
int tmp;
@ -248,12 +165,105 @@ int ffi_prep_args_v9(char *stack, extended_cif *ecif)
return ret;
}
#else
void
ffi_prep_args_v8(char *stack, extended_cif *ecif)
{
int i;
void **p_argv;
char *argp;
ffi_type **p_arg;
/* Skip 16 words for the window save area */
argp = stack + 16*sizeof(int);
/* This should only really be done when we are returning a structure,
however, it's faster just to do it all the time...
if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) */
*(int *) argp = (long)ecif->rvalue;
/* And 1 word for the structure return value. */
argp += sizeof(int);
#ifdef USING_PURIFY
/* Purify will probably complain in our assembly routine, unless we
zero out this memory. */
((int*)argp)[0] = 0;
((int*)argp)[1] = 0;
((int*)argp)[2] = 0;
((int*)argp)[3] = 0;
((int*)argp)[4] = 0;
((int*)argp)[5] = 0;
#endif
p_argv = ecif->avalue;
for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++)
{
size_t z;
if ((*p_arg)->type == FFI_TYPE_STRUCT
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|| (*p_arg)->type == FFI_TYPE_LONGDOUBLE
#endif
)
{
*(unsigned int *) argp = (unsigned long)(* p_argv);
z = sizeof(int);
}
else
{
z = (*p_arg)->size;
if (z < sizeof(int))
{
z = sizeof(int);
switch ((*p_arg)->type)
{
case FFI_TYPE_SINT8:
*(signed int *) argp = *(SINT8 *)(* p_argv);
break;
case FFI_TYPE_UINT8:
*(unsigned int *) argp = *(UINT8 *)(* p_argv);
break;
case FFI_TYPE_SINT16:
*(signed int *) argp = *(SINT16 *)(* p_argv);
break;
case FFI_TYPE_UINT16:
*(unsigned int *) argp = *(UINT16 *)(* p_argv);
break;
default:
FFI_ASSERT(0);
}
}
else
{
memcpy(argp, *p_argv, z);
}
}
p_argv++;
argp += z;
}
return;
}
#endif
/* Perform machine dependent cif processing */
static ffi_status ffi_prep_cif_machdep_core(ffi_cif *cif)
static
ffi_status ffi_prep_cif_machdep_core(ffi_cif *cif)
{
int wordsize;
if (cif->abi != FFI_V9)
if (!V9_ABI_P (cif->abi))
{
wordsize = 4;
@ -303,7 +313,7 @@ static ffi_status ffi_prep_cif_machdep_core(ffi_cif *cif)
break;
case FFI_TYPE_STRUCT:
if (cif->abi == FFI_V9 && cif->rtype->size > 32)
if (V9_ABI_P (cif->abi) && cif->rtype->size > 32)
cif->flags = FFI_TYPE_VOID;
else
cif->flags = FFI_TYPE_STRUCT;
@ -313,7 +323,7 @@ static ffi_status ffi_prep_cif_machdep_core(ffi_cif *cif)
case FFI_TYPE_UINT8:
case FFI_TYPE_SINT16:
case FFI_TYPE_UINT16:
if (cif->abi == FFI_V9)
if (V9_ABI_P (cif->abi))
cif->flags = FFI_TYPE_INT;
else
cif->flags = cif->rtype->type;
@ -321,7 +331,7 @@ static ffi_status ffi_prep_cif_machdep_core(ffi_cif *cif)
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
if (cif->abi == FFI_V9)
if (V9_ABI_P (cif->abi))
cif->flags = FFI_TYPE_INT;
else
cif->flags = FFI_TYPE_SINT64;
@ -334,20 +344,31 @@ static ffi_status ffi_prep_cif_machdep_core(ffi_cif *cif)
return FFI_OK;
}
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
ffi_status
ffi_prep_cif_machdep(ffi_cif *cif)
{
cif->nfixedargs = cif->nargs;
#ifdef SPARC64
if (cif->abi != FFI_COMPAT_V9)
cif->nfixedargs = cif->nargs;
#endif
return ffi_prep_cif_machdep_core (cif);
}
ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned int nfixedargs,
unsigned int ntotalargs)
ffi_status
ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned int nfixedargs,
unsigned int ntotalargs)
{
cif->nfixedargs = nfixedargs;
#ifdef SPARC64
if (cif->abi != FFI_COMPAT_V9)
cif->nfixedargs = nfixedargs;
#endif
return ffi_prep_cif_machdep_core (cif);
}
int ffi_v9_layout_struct(ffi_type *arg, int off, char *ret, char *intg, char *flt)
#ifdef SPARC64
int
ffi_v9_layout_struct(ffi_type *arg, int off, char *ret, char *intg, char *flt)
{
ffi_type **ptr = &arg->elements[0];
@ -380,6 +401,7 @@ int ffi_v9_layout_struct(ffi_type *arg, int off, char *ret, char *intg, char *fl
return off;
}
#endif
#ifdef SPARC64
extern int ffi_call_v9(void *, extended_cif *, unsigned,
@ -389,33 +411,37 @@ extern int ffi_call_v8(void *, extended_cif *, unsigned,
unsigned, unsigned *, void (*fn)(void));
#endif
void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
void
ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
{
extended_cif ecif;
#ifdef SPARC64
void *rval = rvalue;
#endif
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 */
ecif.rvalue = rvalue;
/* If the return value is a struct and we don't have a return value address,
then we need to make one. */
if (cif->rtype->type == FFI_TYPE_STRUCT)
{
if (ecif.rvalue == NULL)
ecif.rvalue = alloca(cif->rtype->size);
#ifdef SPARC64
if (cif->rtype->size <= 32)
rval = alloca(64);
else
{
rval = NULL;
if (rvalue == NULL)
ecif.rvalue = alloca(cif->rtype->size);
}
rval = NULL;
#endif
}
switch (cif->abi)
{
case FFI_V8:
case FFI_V8PLUS:
#ifdef SPARC64
/* We don't yet support calling 32bit code from 64bit */
FFI_ASSERT(0);
@ -430,7 +456,7 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
/* behind "call", so we alloc some executable space for it. */
/* l7 is used, we need to make sure v8.S doesn't use %l7. */
unsigned int *call_struct = NULL;
ffi_closure_alloc(32, &call_struct);
ffi_closure_alloc(32, (void **)&call_struct);
if (call_struct)
{
unsigned long f = (unsigned long)fn;
@ -450,7 +476,7 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
/* SPARC v8 requires 5 instructions for flush to be visible */
asm volatile ("nop; nop; nop; nop; nop");
ffi_call_v8(ffi_prep_args_v8, &ecif, cif->bytes,
cif->flags, rvalue, call_struct);
cif->flags, rvalue, (void (*)(void)) call_struct);
ffi_closure_free(call_struct);
}
else
@ -466,12 +492,13 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
}
#endif
break;
case FFI_COMPAT_V9:
case FFI_V9:
#ifdef SPARC64
ffi_call_v9(ffi_prep_args_v9, &ecif, cif->bytes,
cif->flags, rval, fn);
ffi_call_v9(ffi_prep_args_v9, &ecif, cif->bytes, cif->flags, rval, fn);
if (rvalue && rval && cif->rtype->type == FFI_TYPE_STRUCT)
ffi_v9_layout_struct(cif->rtype, 0, (char *)rvalue, (char *)rval, ((char *)rval)+32);
ffi_v9_layout_struct(cif->rtype, 0, (char *)rvalue, (char *)rval,
((char *)rval)+32);
#else
/* And vice versa */
FFI_ASSERT(0);
@ -502,7 +529,7 @@ ffi_prep_closure_loc (ffi_closure* closure,
#ifdef SPARC64
/* Trampoline address is equal to the closure address. We take advantage
of that to reduce the trampoline size by 8 bytes. */
if (cif->abi != FFI_V9)
if (!V9_ABI_P (cif->abi))
return FFI_BAD_ABI;
fn = (unsigned long) ffi_closure_v9;
tramp[0] = 0x83414000; /* rd %pc, %g1 */
@ -512,7 +539,7 @@ ffi_prep_closure_loc (ffi_closure* closure,
*((unsigned long *) &tramp[4]) = fn;
#else
unsigned long ctx = (unsigned long) codeloc;
if (cif->abi != FFI_V8)
if (!V8_ABI_P (cif->abi))
return FFI_BAD_ABI;
fn = (unsigned long) ffi_closure_v8;
tramp[0] = 0x03000000 | fn >> 10; /* sethi %hi(fn), %g1 */
@ -537,9 +564,100 @@ ffi_prep_closure_loc (ffi_closure* closure,
return FFI_OK;
}
#ifdef SPARC64
int
ffi_closure_sparc_inner_v8(ffi_closure *closure,
void *rvalue, unsigned long *gpr, unsigned long *scratch)
ffi_closure_sparc_inner_v9(ffi_closure *closure, void *rvalue,
unsigned long *gpr, double *fpr)
{
ffi_cif *cif;
ffi_type **arg_types;
void **avalue;
int i, argn, fp_slot_max;
cif = closure->cif;
arg_types = cif->arg_types;
avalue = alloca(cif->nargs * sizeof(void *));
/* Copy the caller's structure return address so that the closure
returns the data directly to the caller. */
if (cif->flags == FFI_TYPE_VOID && cif->rtype->type == FFI_TYPE_STRUCT)
{
rvalue = (void *) gpr[0];
/* Skip the structure return address. */
argn = 1;
}
else
argn = 0;
fp_slot_max = 16 - argn;
/* Grab the addresses of the arguments from the stack frame. */
for (i = 0; i < cif->nargs; i++)
{
/* If the function is variadic, FP arguments are passed in FP
registers only if the corresponding parameter is named. */
const int named
= (cif->abi == FFI_COMPAT_V9 ? 1 : i < cif->nfixedargs);
if (arg_types[i]->type == FFI_TYPE_STRUCT)
{
if (arg_types[i]->size > 16)
{
/* Straight copy of invisible reference. */
avalue[i] = (void *)gpr[argn++];
}
else
{
/* Left-justify. */
ffi_v9_layout_struct(arg_types[i],
0,
(char *) &gpr[argn],
(char *) &gpr[argn],
named
? (char *) &fpr[argn]
: (char *) &gpr[argn]);
avalue[i] = &gpr[argn];
argn
+= ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
}
}
else
{
/* Right-justify. */
argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
/* Align on a 16-byte boundary. */
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
if (arg_types[i]->type == FFI_TYPE_LONGDOUBLE && (argn % 2) != 0)
argn++;
#endif
if (i < fp_slot_max
&& named
&& (arg_types[i]->type == FFI_TYPE_FLOAT
|| arg_types[i]->type == FFI_TYPE_DOUBLE
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|| arg_types[i]->type == FFI_TYPE_LONGDOUBLE
#endif
))
avalue[i] = ((char *) &fpr[argn]) - arg_types[i]->size;
else
avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size;
}
}
/* Invoke the closure. */
closure->fun (cif, rvalue, avalue, closure->user_data);
/* Tell ffi_closure_sparc how to perform return type promotions. */
return cif->rtype->type;
}
#else
int
ffi_closure_sparc_inner_v8(ffi_closure *closure, void *rvalue,
unsigned long *gpr, unsigned long *scratch)
{
ffi_cif *cif;
ffi_type **arg_types;
@ -595,94 +713,11 @@ ffi_closure_sparc_inner_v8(ffi_closure *closure,
}
}
/* Invoke the closure. */
(closure->fun) (cif, rvalue, avalue, closure->user_data);
/* Tell ffi_closure_sparc how to perform return type promotions. */
return cif->rtype->type;
}
int
ffi_closure_sparc_inner_v9(ffi_closure *closure,
void *rvalue, unsigned long *gpr, double *fpr)
{
ffi_cif *cif;
ffi_type **arg_types;
void **avalue;
int i, argn, fp_slot_max;
cif = closure->cif;
arg_types = cif->arg_types;
avalue = alloca(cif->nargs * sizeof(void *));
/* Copy the caller's structure return address so that the closure
returns the data directly to the caller. */
if (cif->flags == FFI_TYPE_VOID && cif->rtype->type == FFI_TYPE_STRUCT)
{
rvalue = (void *) gpr[0];
/* Skip the structure return address. */
argn = 1;
}
else
argn = 0;
fp_slot_max = 16 - argn;
/* Grab the addresses of the arguments from the stack frame. */
for (i = 0; i < cif->nargs; i++)
{
/* If the function is variadic, FP arguments are passed in FP
registers only if the corresponding parameter is named. */
const int named = (i < cif->nfixedargs);
if (arg_types[i]->type == FFI_TYPE_STRUCT)
{
if (arg_types[i]->size > 16)
{
/* Straight copy of invisible reference. */
avalue[i] = (void *)gpr[argn++];
}
else
{
/* Left-justify. */
ffi_v9_layout_struct(arg_types[i],
0,
(char *) &gpr[argn],
(char *) &gpr[argn],
named
? (char *) &fpr[argn]
: (char *) &gpr[argn]);
avalue[i] = &gpr[argn];
argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
}
}
else
{
/* Right-justify. */
argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
/* Align on a 16-byte boundary. */
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
if (arg_types[i]->type == FFI_TYPE_LONGDOUBLE && (argn % 2) != 0)
argn++;
#endif
if (i < fp_slot_max
&& named
&& (arg_types[i]->type == FFI_TYPE_FLOAT
|| arg_types[i]->type == FFI_TYPE_DOUBLE
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|| arg_types[i]->type == FFI_TYPE_LONGDOUBLE
#endif
))
avalue[i] = ((char *) &fpr[argn]) - arg_types[i]->size;
else
avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size;
}
}
/* Invoke the closure. */
closure->fun (cif, rvalue, avalue, closure->user_data);
/* Tell ffi_closure_sparc how to perform return type promotions. */
return cif->rtype->type;
}
#endif

View File

@ -48,6 +48,8 @@ typedef enum ffi_abi {
FFI_FIRST_ABI = 0,
FFI_V8,
FFI_V8PLUS,
/* See below for the COMPAT_V9 rationale. */
FFI_COMPAT_V9,
FFI_V9,
FFI_LAST_ABI,
#ifdef SPARC64
@ -58,8 +60,19 @@ typedef enum ffi_abi {
} ffi_abi;
#endif
#define V8_ABI_P(abi) ((abi) == FFI_V8 || (abi) == FFI_V8PLUS)
#define V9_ABI_P(abi) ((abi) == FFI_COMPAT_V9 || (abi) == FFI_V9)
#define FFI_TARGET_SPECIFIC_VARIADIC 1
/* The support of variadic functions was broken in the original implementation
of the FFI_V9 ABI. This has been fixed by adding one extra field to the
CIF structure (nfixedargs field), which means that the ABI of libffi itself
has changed. In order to support applications using the original ABI, we
have renamed FFI_V9 into FFI_COMPAT_V9 and defined a new FFI_V9 value. */
#ifdef SPARC64
#define FFI_EXTRA_CIF_FIELDS unsigned int nfixedargs
#endif
/* ---- Definitions for closures ----------------------------------------- */

View File

@ -1,6 +1,6 @@
/* -----------------------------------------------------------------------
v8.S - Copyright (c) 1996, 1997, 2003, 2004, 2008 Red Hat, Inc.
SPARC Foreign Function Interface
Permission is hereby granted, free of charge, to any person obtaining
@ -28,6 +28,8 @@
#include <fficonfig.h>
#include <ffi.h>
#ifndef SPARC64
#define STACKFRAME 96 /* Minimum stack framesize for SPARC */
#define ARGS (64+4) /* Offset of register area in frame */
@ -307,6 +309,7 @@ done2:
.byte 0x1f ! uleb128 0x1f
.align WS
.LLEFDE2:
#endif
#if defined __ELF__ && defined __linux__
.section .note.GNU-stack,"",@progbits

View File

@ -1,6 +1,6 @@
/* -----------------------------------------------------------------------
v9.S - Copyright (c) 2000, 2003, 2004, 2008 Red Hat, Inc.
SPARC 64-bit Foreign Function Interface
Permission is hereby granted, free of charge, to any person obtaining
@ -29,8 +29,6 @@
#include <ffi.h>
#ifdef SPARC64
/* Only compile this in for 64bit builds, because otherwise the object file
will have inproper architecture due to used instructions. */
#define STACKFRAME 176 /* Minimum stack framesize for SPARC 64-bit */
#define STACK_BIAS 2047