s390: Inline and tidy ffi_prep_args
As per discussion with Ulrich Weigand, document the restrictions on the code within ffi_call_int as we simultaneously prepare stack frames for ffi_call_SYSV and the target function.
This commit is contained in:
294
src/s390/ffi.c
294
src/s390/ffi.c
@@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
#include <ffi.h>
|
#include <ffi.h>
|
||||||
#include <ffi_common.h>
|
#include <ffi_common.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
/*====================== End of Includes =============================*/
|
/*====================== End of Includes =============================*/
|
||||||
@@ -128,165 +129,6 @@ ffi_check_struct_type (ffi_type *arg)
|
|||||||
|
|
||||||
/*======================== End of Routine ============================*/
|
/*======================== End of Routine ============================*/
|
||||||
|
|
||||||
/*====================================================================*/
|
|
||||||
/* */
|
|
||||||
/* Name - ffi_prep_args. */
|
|
||||||
/* */
|
|
||||||
/* Function - Prepare parameters for call to function. */
|
|
||||||
/* */
|
|
||||||
/* ffi_prep_args is called by the assembly routine once stack space */
|
|
||||||
/* has been allocated for the function's arguments. */
|
|
||||||
/* */
|
|
||||||
/*====================================================================*/
|
|
||||||
|
|
||||||
static void
|
|
||||||
ffi_prep_args (ffi_cif *cif, void *rvalue, void **p_argv,
|
|
||||||
unsigned long *p_ov, struct call_frame *p_frame)
|
|
||||||
{
|
|
||||||
unsigned char *p_struct = (unsigned char *)p_frame;
|
|
||||||
unsigned long *p_gpr = p_frame->gpr_args;
|
|
||||||
unsigned long long *p_fpr = p_frame->fpr_args;
|
|
||||||
int n_fpr = 0;
|
|
||||||
int n_gpr = 0;
|
|
||||||
int n_ov = 0;
|
|
||||||
ffi_type **ptr;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* If we returning a structure then we set the first parameter register
|
|
||||||
to the address of where we are returning this structure. */
|
|
||||||
if (cif->flags & FFI390_RET_IN_MEM)
|
|
||||||
p_gpr[n_gpr++] = (unsigned long) rvalue;
|
|
||||||
|
|
||||||
/* Now for the arguments. */
|
|
||||||
for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++, p_argv++)
|
|
||||||
{
|
|
||||||
ffi_type *ty = *ptr;
|
|
||||||
void *arg = *p_argv;
|
|
||||||
int type = ty->type;
|
|
||||||
|
|
||||||
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
|
||||||
/* 16-byte long double is passed like a struct. */
|
|
||||||
if (type == FFI_TYPE_LONGDOUBLE)
|
|
||||||
type = FFI_TYPE_STRUCT;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Check how a structure type is passed. */
|
|
||||||
if (type == FFI_TYPE_STRUCT || type == FFI_TYPE_COMPLEX)
|
|
||||||
{
|
|
||||||
if (type == FFI_TYPE_COMPLEX)
|
|
||||||
type = FFI_TYPE_POINTER;
|
|
||||||
else
|
|
||||||
type = ffi_check_struct_type (ty);
|
|
||||||
|
|
||||||
/* If we pass the struct via pointer, copy the data. */
|
|
||||||
if (type == FFI_TYPE_POINTER)
|
|
||||||
{
|
|
||||||
p_struct -= ROUND_SIZE (ty->size);
|
|
||||||
memcpy (p_struct, (char *)arg, ty->size);
|
|
||||||
arg = &p_struct;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now handle all primitive int/pointer/float data types. */
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case FFI_TYPE_DOUBLE:
|
|
||||||
if (n_fpr < MAX_FPRARGS)
|
|
||||||
p_fpr[n_fpr++] = *(unsigned long long *) arg;
|
|
||||||
else
|
|
||||||
#ifdef __s390x__
|
|
||||||
p_ov[n_ov++] = *(unsigned long *) arg;
|
|
||||||
#else
|
|
||||||
p_ov[n_ov++] = ((unsigned long *) arg)[0],
|
|
||||||
p_ov[n_ov++] = ((unsigned long *) arg)[1];
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_FLOAT:
|
|
||||||
if (n_fpr < MAX_FPRARGS)
|
|
||||||
p_fpr[n_fpr++] = (unsigned long long)*(unsigned int *) arg << 32;
|
|
||||||
else
|
|
||||||
p_ov[n_ov++] = *(unsigned int *) arg;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_POINTER:
|
|
||||||
if (n_gpr < MAX_GPRARGS)
|
|
||||||
p_gpr[n_gpr++] = (unsigned long)*(unsigned char **) arg;
|
|
||||||
else
|
|
||||||
p_ov[n_ov++] = (unsigned long)*(unsigned char **) arg;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT64:
|
|
||||||
case FFI_TYPE_SINT64:
|
|
||||||
#ifdef __s390x__
|
|
||||||
if (n_gpr < MAX_GPRARGS)
|
|
||||||
p_gpr[n_gpr++] = *(unsigned long *) arg;
|
|
||||||
else
|
|
||||||
p_ov[n_ov++] = *(unsigned long *) arg;
|
|
||||||
#else
|
|
||||||
if (n_gpr == MAX_GPRARGS-1)
|
|
||||||
n_gpr = MAX_GPRARGS;
|
|
||||||
if (n_gpr < MAX_GPRARGS)
|
|
||||||
p_gpr[n_gpr++] = ((unsigned long *) arg)[0],
|
|
||||||
p_gpr[n_gpr++] = ((unsigned long *) arg)[1];
|
|
||||||
else
|
|
||||||
p_ov[n_ov++] = ((unsigned long *) arg)[0],
|
|
||||||
p_ov[n_ov++] = ((unsigned long *) arg)[1];
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT32:
|
|
||||||
if (n_gpr < MAX_GPRARGS)
|
|
||||||
p_gpr[n_gpr++] = *(unsigned int *) arg;
|
|
||||||
else
|
|
||||||
p_ov[n_ov++] = *(unsigned int *) arg;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_INT:
|
|
||||||
case FFI_TYPE_SINT32:
|
|
||||||
if (n_gpr < MAX_GPRARGS)
|
|
||||||
p_gpr[n_gpr++] = *(signed int *) arg;
|
|
||||||
else
|
|
||||||
p_ov[n_ov++] = *(signed int *) arg;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT16:
|
|
||||||
if (n_gpr < MAX_GPRARGS)
|
|
||||||
p_gpr[n_gpr++] = *(unsigned short *) arg;
|
|
||||||
else
|
|
||||||
p_ov[n_ov++] = *(unsigned short *) arg;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_SINT16:
|
|
||||||
if (n_gpr < MAX_GPRARGS)
|
|
||||||
p_gpr[n_gpr++] = *(signed short *) arg;
|
|
||||||
else
|
|
||||||
p_ov[n_ov++] = *(signed short *) arg;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_UINT8:
|
|
||||||
if (n_gpr < MAX_GPRARGS)
|
|
||||||
p_gpr[n_gpr++] = *(unsigned char *) arg;
|
|
||||||
else
|
|
||||||
p_ov[n_ov++] = *(unsigned char *) arg;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FFI_TYPE_SINT8:
|
|
||||||
if (n_gpr < MAX_GPRARGS)
|
|
||||||
p_gpr[n_gpr++] = *(signed char *) arg;
|
|
||||||
else
|
|
||||||
p_ov[n_ov++] = *(signed char *) arg;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
FFI_ASSERT (0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*======================== End of Routine ============================*/
|
|
||||||
|
|
||||||
/*====================================================================*/
|
/*====================================================================*/
|
||||||
/* */
|
/* */
|
||||||
/* Name - ffi_prep_cif_machdep. */
|
/* Name - ffi_prep_cif_machdep. */
|
||||||
@@ -469,8 +311,12 @@ ffi_call_int(ffi_cif *cif,
|
|||||||
{
|
{
|
||||||
int ret_type = cif->flags;
|
int ret_type = cif->flags;
|
||||||
size_t rsize = 0, bytes = cif->bytes;
|
size_t rsize = 0, bytes = cif->bytes;
|
||||||
unsigned char *stack;
|
unsigned char *stack, *p_struct;
|
||||||
struct call_frame *frame;
|
struct call_frame *frame;
|
||||||
|
unsigned long *p_ov, *p_gpr;
|
||||||
|
unsigned long long *p_fpr;
|
||||||
|
int n_fpr, n_gpr, n_ov, i, n;
|
||||||
|
ffi_type **arg_types;
|
||||||
|
|
||||||
FFI_ASSERT (cif->abi == FFI_SYSV);
|
FFI_ASSERT (cif->abi == FFI_SYSV);
|
||||||
|
|
||||||
@@ -499,22 +345,134 @@ ffi_call_int(ffi_cif *cif,
|
|||||||
p_ov: bottom of the overflow area (growing upwards)
|
p_ov: bottom of the overflow area (growing upwards)
|
||||||
p_struct: top of the struct copy area (growing downwards)
|
p_struct: top of the struct copy area (growing downwards)
|
||||||
|
|
||||||
All areas are kept aligned to twice the word size. */
|
All areas are kept aligned to twice the word size.
|
||||||
|
|
||||||
|
Note that we're going to create the stack frame for both
|
||||||
|
ffi_call_SYSV _and_ the target function right here. This
|
||||||
|
works because we don't make any function calls with more
|
||||||
|
than 5 arguments (indeed only memcpy and ffi_call_SYSV),
|
||||||
|
and thus we don't have any stacked outgoing parameters. */
|
||||||
|
|
||||||
stack = alloca (bytes + sizeof(struct call_frame) + rsize);
|
stack = alloca (bytes + sizeof(struct call_frame) + rsize);
|
||||||
frame = (struct call_frame *)(stack + bytes);
|
frame = (struct call_frame *)(stack + bytes);
|
||||||
if (rsize)
|
if (rsize)
|
||||||
rvalue = frame + 1;
|
rvalue = frame + 1;
|
||||||
|
|
||||||
/* Assuming that the current function has the standard call frame,
|
/* Link the new frame back to the one from this function. */
|
||||||
we can maintain the linked list like so. */
|
frame->back_chain = __builtin_frame_address (0);
|
||||||
frame->back_chain = __builtin_dwarf_cfa() - sizeof(struct call_frame);
|
|
||||||
|
|
||||||
/* Pass the outgoing stack frame in the r15 save slot. */
|
|
||||||
frame->gpr_save[8] = (unsigned long)(stack - sizeof(struct call_frame));
|
|
||||||
|
|
||||||
/* Fill in all of the argument stuff. */
|
/* Fill in all of the argument stuff. */
|
||||||
ffi_prep_args (cif, rvalue, avalue, (unsigned long *)stack, frame);
|
p_ov = (unsigned long *)stack;
|
||||||
|
p_struct = (unsigned char *)frame;
|
||||||
|
p_gpr = frame->gpr_args;
|
||||||
|
p_fpr = frame->fpr_args;
|
||||||
|
n_fpr = n_gpr = n_ov = 0;
|
||||||
|
|
||||||
|
/* If we returning a structure then we set the first parameter register
|
||||||
|
to the address of where we are returning this structure. */
|
||||||
|
if (cif->flags & FFI390_RET_IN_MEM)
|
||||||
|
p_gpr[n_gpr++] = (uintptr_t) rvalue;
|
||||||
|
|
||||||
|
/* Now for the arguments. */
|
||||||
|
arg_types = cif->arg_types;
|
||||||
|
for (i = 0, n = cif->nargs; i < n; ++i)
|
||||||
|
{
|
||||||
|
ffi_type *ty = arg_types[i];
|
||||||
|
void *arg = avalue[i];
|
||||||
|
int type = ty->type;
|
||||||
|
ffi_arg val;
|
||||||
|
|
||||||
|
restart:
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case FFI_TYPE_SINT8:
|
||||||
|
val = *(SINT8 *)arg;
|
||||||
|
goto do_int;
|
||||||
|
case FFI_TYPE_UINT8:
|
||||||
|
val = *(UINT8 *)arg;
|
||||||
|
goto do_int;
|
||||||
|
case FFI_TYPE_SINT16:
|
||||||
|
val = *(SINT16 *)arg;
|
||||||
|
goto do_int;
|
||||||
|
case FFI_TYPE_UINT16:
|
||||||
|
val = *(UINT16 *)arg;
|
||||||
|
goto do_int;
|
||||||
|
case FFI_TYPE_INT:
|
||||||
|
case FFI_TYPE_SINT32:
|
||||||
|
val = *(SINT32 *)arg;
|
||||||
|
goto do_int;
|
||||||
|
case FFI_TYPE_UINT32:
|
||||||
|
val = *(UINT32 *)arg;
|
||||||
|
goto do_int;
|
||||||
|
case FFI_TYPE_POINTER:
|
||||||
|
val = *(uintptr_t *)arg;
|
||||||
|
do_int:
|
||||||
|
*(n_gpr < MAX_GPRARGS ? p_gpr + n_gpr++ : p_ov + n_ov++) = val;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FFI_TYPE_UINT64:
|
||||||
|
case FFI_TYPE_SINT64:
|
||||||
|
#ifdef __s390x__
|
||||||
|
val = *(UINT64 *)arg;
|
||||||
|
goto do_int;
|
||||||
|
#else
|
||||||
|
if (n_gpr == MAX_GPRARGS-1)
|
||||||
|
n_gpr = MAX_GPRARGS;
|
||||||
|
if (n_gpr < MAX_GPRARGS)
|
||||||
|
p_gpr[n_gpr++] = ((UINT32 *) arg)[0],
|
||||||
|
p_gpr[n_gpr++] = ((UINT32 *) arg)[1];
|
||||||
|
else
|
||||||
|
p_ov[n_ov++] = ((UINT32 *) arg)[0],
|
||||||
|
p_ov[n_ov++] = ((UINT32 *) arg)[1];
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FFI_TYPE_DOUBLE:
|
||||||
|
if (n_fpr < MAX_FPRARGS)
|
||||||
|
p_fpr[n_fpr++] = *(UINT64 *) arg;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#ifdef __s390x__
|
||||||
|
p_ov[n_ov++] = *(UINT64 *) arg;
|
||||||
|
#else
|
||||||
|
p_ov[n_ov++] = ((UINT32 *) arg)[0],
|
||||||
|
p_ov[n_ov++] = ((UINT32 *) arg)[1];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FFI_TYPE_FLOAT:
|
||||||
|
val = *(UINT32 *)arg;
|
||||||
|
if (n_fpr < MAX_FPRARGS)
|
||||||
|
p_fpr[n_fpr++] = (UINT64)val << 32;
|
||||||
|
else
|
||||||
|
p_ov[n_ov++] = val;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FFI_TYPE_STRUCT:
|
||||||
|
/* Check how a structure type is passed. */
|
||||||
|
type = ffi_check_struct_type (ty);
|
||||||
|
/* Some structures are passed via a type they contain. */
|
||||||
|
if (type != FFI_TYPE_POINTER)
|
||||||
|
goto restart;
|
||||||
|
/* ... otherwise, passed by reference. fallthru. */
|
||||||
|
|
||||||
|
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|
||||||
|
case FFI_TYPE_LONGDOUBLE:
|
||||||
|
/* 16-byte long double is passed via reference. */
|
||||||
|
#endif
|
||||||
|
case FFI_TYPE_COMPLEX:
|
||||||
|
/* Complex types are passed via reference. */
|
||||||
|
p_struct -= ROUND_SIZE (ty->size);
|
||||||
|
memcpy (p_struct, arg, ty->size);
|
||||||
|
val = (uintptr_t)p_struct;
|
||||||
|
goto do_int;
|
||||||
|
|
||||||
|
default:
|
||||||
|
FFI_ASSERT (0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ffi_call_SYSV (frame, ret_type & FFI360_RET_MASK, rvalue, fn, closure);
|
ffi_call_SYSV (frame, ret_type & FFI360_RET_MASK, rvalue, fn, closure);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,26 +54,24 @@ ffi_call_SYSV:
|
|||||||
.cfi_rel_offset r13, 52
|
.cfi_rel_offset r13, 52
|
||||||
.cfi_rel_offset r14, 56
|
.cfi_rel_offset r14, 56
|
||||||
.cfi_def_cfa_register r13
|
.cfi_def_cfa_register r13
|
||||||
l %r15,60(%r2) # Set up outgoing stack
|
st %r2,0(%r15) # Set up back chain
|
||||||
#ifdef HAVE_AS_S390_ZARCH
|
|
||||||
larl %r14,.Ltable
|
|
||||||
#else
|
|
||||||
basr %r14,0 # Set up base register
|
|
||||||
.Lbase:
|
|
||||||
#endif
|
|
||||||
sla %r3,3 # ret_type *= 8
|
sla %r3,3 # ret_type *= 8
|
||||||
lr %r12,%r4 # Save ret_addr
|
lr %r12,%r4 # Save ret_addr
|
||||||
lr %r1,%r5 # Save fun
|
lr %r1,%r5 # Save fun
|
||||||
lr %r0,%r6 # Install static chain
|
lr %r0,%r6 # Install static chain
|
||||||
|
|
||||||
|
# Set return address, so that there is only one indirect jump.
|
||||||
#ifdef HAVE_AS_S390_ZARCH
|
#ifdef HAVE_AS_S390_ZARCH
|
||||||
la %r14,0(%r14,%r3) # Set return address
|
larl %r14,.Ltable
|
||||||
|
ar %r14,%r3
|
||||||
#else
|
#else
|
||||||
la %r14,.Ltable-.Lbase(%r14,%r3) # Set return address
|
basr %r14,0
|
||||||
|
0: la %r14,.Ltable-0b(%r14,%r3)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
lm %r2,%r6,8(%r13) # Load arguments
|
lm %r2,%r6,8(%r13) # Load arguments
|
||||||
ld %f0,64(%r13)
|
ld %f0,64(%r13)
|
||||||
ld %f2,72(%r13)
|
ld %f2,72(%r13)
|
||||||
st %r13,0(%r15) # Set up back chain
|
|
||||||
br %r1 # ... and call function
|
br %r1 # ... and call function
|
||||||
|
|
||||||
.balign 8
|
.balign 8
|
||||||
@@ -210,7 +208,7 @@ ffi_call_SYSV:
|
|||||||
.cfi_rel_offset r13, 104
|
.cfi_rel_offset r13, 104
|
||||||
.cfi_rel_offset r14, 112
|
.cfi_rel_offset r14, 112
|
||||||
.cfi_def_cfa_register r13
|
.cfi_def_cfa_register r13
|
||||||
lg %r15,120(%r2) # Set up outgoing stack
|
stg %r2,0(%r15) # Set up back chain
|
||||||
larl %r14,.Ltable # Set up return address
|
larl %r14,.Ltable # Set up return address
|
||||||
slag %r3,%r3,3 # ret_type *= 8
|
slag %r3,%r3,3 # ret_type *= 8
|
||||||
lgr %r12,%r4 # Save ret_addr
|
lgr %r12,%r4 # Save ret_addr
|
||||||
@@ -222,7 +220,6 @@ ffi_call_SYSV:
|
|||||||
ld %f2,136(%r13)
|
ld %f2,136(%r13)
|
||||||
ld %f4,144(%r13)
|
ld %f4,144(%r13)
|
||||||
ld %f6,152(%r13)
|
ld %f6,152(%r13)
|
||||||
stg %r13,0(%r15) # Set up back chain
|
|
||||||
br %r1 # ... and call function
|
br %r1 # ... and call function
|
||||||
|
|
||||||
.balign 8
|
.balign 8
|
||||||
|
|||||||
Reference in New Issue
Block a user