From efda7af2e3046b761ab2204c13ad6ae66535c408 Mon Sep 17 00:00:00 2001 From: ebotcazou Date: Mon, 17 Feb 2014 12:00:04 +0000 Subject: [PATCH 2/7] 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. --- src/sparc/ffi.c | 398 +++++++++++++++++++++++++++----------------------- src/sparc/ffitarget.h | 13 ++ src/sparc/v8.S | 5 +- src/sparc/v9.S | 4 +- 4 files changed, 235 insertions(+), 185 deletions(-) diff --git a/src/sparc/ffi.c b/src/sparc/ffi.c index 47cc9fd..12518e6 100644 --- a/src/sparc/ffi.c +++ b/src/sparc/ffi.c @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------- ffi.c - Copyright (c) 2011, 2013 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; - - /* 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; -} +#ifdef SPARC64 -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, @@ -393,33 +415,37 @@ extern int ffi_call_v8(void *, extended_cif *, unsigned, void ffi_flush_icache (void *, size_t); #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); @@ -459,6 +485,7 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) #endif 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 @@ -474,12 +501,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); @@ -510,7 +538,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 */ @@ -520,7 +548,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 */ @@ -549,74 +577,11 @@ ffi_prep_closure_loc (ffi_closure* closure, return FFI_OK; } -int -ffi_closure_sparc_inner_v8(ffi_closure *closure, - void *rvalue, unsigned long *gpr, unsigned long *scratch) -{ - ffi_cif *cif; - ffi_type **arg_types; - void **avalue; - int i, argn; - - 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_STRUCT -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - || cif->flags == FFI_TYPE_LONGDOUBLE -#endif - ) - rvalue = (void *) gpr[0]; - - /* Always skip the structure return address. */ - argn = 1; - - /* Grab the addresses of the arguments from the stack frame. */ - for (i = 0; i < cif->nargs; i++) - { - if (arg_types[i]->type == FFI_TYPE_STRUCT -#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE - || arg_types[i]->type == FFI_TYPE_LONGDOUBLE -#endif - ) - { - /* Straight copy of invisible reference. */ - avalue[i] = (void *)gpr[argn++]; - } - else if ((arg_types[i]->type == FFI_TYPE_DOUBLE - || arg_types[i]->type == FFI_TYPE_SINT64 - || arg_types[i]->type == FFI_TYPE_UINT64) - /* gpr is 8-byte aligned. */ - && (argn % 2) != 0) - { - /* Align on a 8-byte boundary. */ - scratch[0] = gpr[argn]; - scratch[1] = gpr[argn+1]; - avalue[i] = scratch; - scratch -= 2; - argn += 2; - } - else - { - /* Always right-justify. */ - argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; - 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; -} +#ifdef SPARC64 int -ffi_closure_sparc_inner_v9(ffi_closure *closure, - void *rvalue, unsigned long *gpr, double *fpr) +ffi_closure_sparc_inner_v9(ffi_closure *closure, void *rvalue, + unsigned long *gpr, double *fpr) { ffi_cif *cif; ffi_type **arg_types; @@ -645,7 +610,8 @@ ffi_closure_sparc_inner_v9(ffi_closure *closure, { /* 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); + const int named + = (cif->abi == FFI_COMPAT_V9 ? 1 : i < cif->nfixedargs); if (arg_types[i]->type == FFI_TYPE_STRUCT) { @@ -665,7 +631,8 @@ ffi_closure_sparc_inner_v9(ffi_closure *closure, ? (char *) &fpr[argn] : (char *) &gpr[argn]); avalue[i] = &gpr[argn]; - argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; + argn + += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; } } else @@ -698,3 +665,72 @@ ffi_closure_sparc_inner_v9(ffi_closure *closure, /* 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; + void **avalue; + int i, argn; + + 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_STRUCT +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + || cif->flags == FFI_TYPE_LONGDOUBLE +#endif + ) + rvalue = (void *) gpr[0]; + + /* Always skip the structure return address. */ + argn = 1; + + /* Grab the addresses of the arguments from the stack frame. */ + for (i = 0; i < cif->nargs; i++) + { + if (arg_types[i]->type == FFI_TYPE_STRUCT +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + || arg_types[i]->type == FFI_TYPE_LONGDOUBLE +#endif + ) + { + /* Straight copy of invisible reference. */ + avalue[i] = (void *)gpr[argn++]; + } + else if ((arg_types[i]->type == FFI_TYPE_DOUBLE + || arg_types[i]->type == FFI_TYPE_SINT64 + || arg_types[i]->type == FFI_TYPE_UINT64) + /* gpr is 8-byte aligned. */ + && (argn % 2) != 0) + { + /* Align on a 8-byte boundary. */ + scratch[0] = gpr[argn]; + scratch[1] = gpr[argn+1]; + avalue[i] = scratch; + scratch -= 2; + argn += 2; + } + else + { + /* Always right-justify. */ + argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; + 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 diff --git a/src/sparc/ffitarget.h b/src/sparc/ffitarget.h index a1f5e49..6489ac0 100644 --- a/src/sparc/ffitarget.h +++ b/src/sparc/ffitarget.h @@ -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 ----------------------------------------- */ diff --git a/src/sparc/v8.S b/src/sparc/v8.S index 6bf7ac0..d5af887 100644 --- a/src/sparc/v8.S +++ b/src/sparc/v8.S @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------- v8.S - Copyright (c) 2013 The Written Word, Inc. 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 @@ -29,6 +29,8 @@ #include #include +#ifndef SPARC64 + #define STACKFRAME 96 /* Minimum stack framesize for SPARC */ #define ARGS (64+4) /* Offset of register area in frame */ @@ -340,6 +342,7 @@ done2: .byte 0x1f ! uleb128 0x1f .align WS .LLEFDE2: +#endif #if defined __ELF__ && defined __linux__ .section .note.GNU-stack,"",@progbits diff --git a/src/sparc/v9.S b/src/sparc/v9.S index bf31a2b..2c97673 100644 --- a/src/sparc/v9.S +++ b/src/sparc/v9.S @@ -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 #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 -- 1.8.4.2