aboutsummaryrefslogtreecommitdiff
path: root/libffi/src
diff options
context:
space:
mode:
Diffstat (limited to 'libffi/src')
-rw-r--r--libffi/src/s390/ffi.c589
-rw-r--r--libffi/src/s390/sysv.S161
2 files changed, 750 insertions, 0 deletions
diff --git a/libffi/src/s390/ffi.c b/libffi/src/s390/ffi.c
new file mode 100644
index 00000000000..8b514e36c26
--- /dev/null
+++ b/libffi/src/s390/ffi.c
@@ -0,0 +1,589 @@
+/* -----------------------------------------------------------------------
+ ffi.c - Copyright (c) 2000 Software AG
+
+ S390 Foreign Function Interface
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ ``Software''), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+ ----------------------------------------------------------------------- */
+/*====================================================================*/
+/* Includes */
+/* -------- */
+/*====================================================================*/
+
+#include <ffi.h>
+#include <ffi_common.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+/*====================== End of Includes =============================*/
+
+/*====================================================================*/
+/* Defines */
+/* ------- */
+/*====================================================================*/
+
+#define MAX_GPRARGS 5 /* Max. no. of GPR available */
+#define MAX_FPRARGS 2 /* Max. no. of FPR available */
+
+#define STR_GPR 1 /* Structure will fit in 1 or 2 GPR */
+#define STR_FPR 2 /* Structure will fit in a FPR */
+#define STR_STACK 3 /* Structure needs to go on stack */
+
+/*===================== End of Defines ===============================*/
+
+/*====================================================================*/
+/* Types */
+/* ----- */
+/*====================================================================*/
+
+typedef struct stackLayout
+{
+ int *backChain;
+ int *endOfStack;
+ int glue[2];
+ int scratch[2];
+ int gprArgs[MAX_GPRARGS];
+ int notUsed;
+ union
+ {
+ float f;
+ double d;
+ } fprArgs[MAX_FPRARGS];
+ int unUsed[8];
+ int outArgs[100];
+} stackLayout;
+
+/*======================== End of Types ==============================*/
+
+/*====================================================================*/
+/* Prototypes */
+/* ---------- */
+/*====================================================================*/
+
+void ffi_prep_args(stackLayout *, extended_cif *);
+static int ffi_check_struct(ffi_type *, unsigned int *);
+static void ffi_insert_int(int, stackLayout *, int *, int *);
+static void ffi_insert_int64(long long, stackLayout *, int *, int *);
+static void ffi_insert_double(double, stackLayout *, int *, int *);
+
+/*====================== End of Prototypes ===========================*/
+
+/*====================================================================*/
+/* Externals */
+/* --------- */
+/*====================================================================*/
+
+extern void ffi_call_SYSV(void (*)(stackLayout *, extended_cif *),
+ extended_cif *,
+ unsigned, unsigned,
+ unsigned *,
+ void (*fn)());
+
+/*====================== End of Externals ============================*/
+
+/*====================================================================*/
+/* */
+/* Name - ffi_check_struct. */
+/* */
+/* Function - Determine if a structure can be passed within a */
+/* general or floating point register. */
+/* */
+/*====================================================================*/
+
+int
+ffi_check_struct(ffi_type *arg, unsigned int *strFlags)
+{
+ ffi_type *element;
+ int i_Element;
+
+ for (i_Element = 0; arg->elements[i_Element]; i_Element++) {
+ element = arg->elements[i_Element];
+ switch (element->type) {
+ case FFI_TYPE_DOUBLE :
+ *strFlags |= STR_FPR;
+ break;
+
+ case FFI_TYPE_STRUCT :
+ *strFlags |= ffi_check_struct(element, strFlags);
+ break;
+
+ default :
+ *strFlags |= STR_GPR;
+ }
+ }
+ return (*strFlags);
+}
+
+/*======================== End of Routine ============================*/
+
+/*====================================================================*/
+/* */
+/* Name - ffi_insert_int. */
+/* */
+/* Function - Insert an integer parameter in a register if there are */
+/* spares else on the stack. */
+/* */
+/*====================================================================*/
+
+void
+ffi_insert_int(int gprValue, stackLayout *stack,
+ int *intArgC, int *outArgC)
+{
+ if (*intArgC < MAX_GPRARGS) {
+ stack->gprArgs[*intArgC] = gprValue;
+ *intArgC += 1;
+ }
+ else {
+ stack->outArgs[*outArgC++] = gprValue;
+ *outArgC += 1;
+ }
+}
+
+/*======================== End of Routine ============================*/
+
+/*====================================================================*/
+/* */
+/* Name - ffi_insert_int64. */
+/* */
+/* Function - Insert a long long parameter in registers if there are */
+/* spares else on the stack. */
+/* */
+/*====================================================================*/
+
+void
+ffi_insert_int64(long long llngValue, stackLayout *stack,
+ int *intArgC, int *outArgC)
+{
+
+ if (*intArgC < (MAX_GPRARGS-1)) {
+ memcpy(&stack->gprArgs[*intArgC],
+ &llngValue, sizeof(long long));
+ *intArgC += 2;
+ }
+ else {
+ memcpy(&stack->outArgs[*outArgC],
+ &llngValue, sizeof(long long));
+ *outArgC += 2;
+ }
+
+}
+
+/*======================== End of Routine ============================*/
+
+/*====================================================================*/
+/* */
+/* Name - ffi_insert_double. */
+/* */
+/* Function - Insert a double parameter in a FP register if there is */
+/* a spare else on the stack. */
+/* */
+/*====================================================================*/
+
+void
+ffi_insert_double(double dblValue, stackLayout *stack,
+ int *fprArgC, int *outArgC)
+{
+
+ if (*fprArgC < MAX_FPRARGS) {
+ stack->fprArgs[*fprArgC].d = dblValue;
+ *fprArgC += 1;
+ }
+ else {
+ memcpy(&stack->outArgs[*outArgC],
+ &dblValue,sizeof(double));
+ *outArgC += 2;
+ }
+
+}
+
+/*======================== 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. */
+/* */
+/* The stack layout we want looks like this: */
+/* *------------------------------------------------------------* */
+/* | 0 | Back chain (a 0 here signifies end of back chain) | */
+/* +--------+---------------------------------------------------+ */
+/* | 4 | EOS (end of stack, not used on Linux for S390) | */
+/* +--------+---------------------------------------------------+ */
+/* | 8 | Glue used in other linkage formats | */
+/* +--------+---------------------------------------------------+ */
+/* | 12 | Glue used in other linkage formats | */
+/* +--------+---------------------------------------------------+ */
+/* | 16 | Scratch area | */
+/* +--------+---------------------------------------------------+ */
+/* | 20 | Scratch area | */
+/* +--------+---------------------------------------------------+ */
+/* | 24 | GPR parameter register 1 | */
+/* +--------+---------------------------------------------------+ */
+/* | 28 | GPR parameter register 2 | */
+/* +--------+---------------------------------------------------+ */
+/* | 32 | GPR parameter register 3 | */
+/* +--------+---------------------------------------------------+ */
+/* | 36 | GPR parameter register 4 | */
+/* +--------+---------------------------------------------------+ */
+/* | 40 | GPR parameter register 5 | */
+/* +--------+---------------------------------------------------+ */
+/* | 44 | Unused | */
+/* +--------+---------------------------------------------------+ */
+/* | 48 | FPR parameter register 1 | */
+/* +--------+---------------------------------------------------+ */
+/* | 56 | FPR parameter register 2 | */
+/* +--------+---------------------------------------------------+ */
+/* | 64 | Unused | */
+/* +--------+---------------------------------------------------+ */
+/* | 96 | Outgoing args (length x) | */
+/* +--------+---------------------------------------------------+ */
+/* | 96+x | Copy area for structures (length y) | */
+/* +--------+---------------------------------------------------+ */
+/* | 96+x+y | Possible stack alignment | */
+/* *------------------------------------------------------------* */
+/* */
+/*====================================================================*/
+
+void
+ffi_prep_args(stackLayout *stack, extended_cif *ecif)
+{
+ const unsigned bytes = ecif->cif->bytes;
+ const unsigned flags = ecif->cif->flags;
+
+ /*----------------------------------------------------------*/
+ /* Pointer to the copy area on stack for structures */
+ /*----------------------------------------------------------*/
+ char *copySpace = (char *) stack + bytes + sizeof(stackLayout);
+
+ /*----------------------------------------------------------*/
+ /* Count of general and floating point register usage */
+ /*----------------------------------------------------------*/
+ int intArgC = 0,
+ fprArgC = 0,
+ outArgC = 0;
+
+ int i;
+ ffi_type **ptr;
+ void **p_argv;
+ size_t structCopySize;
+ unsigned gprValue, strFlags = 0;
+ unsigned long long llngValue;
+ double dblValue;
+
+ /* Now for the arguments. */
+ p_argv = ecif->avalue;
+
+ /*----------------------------------------------------------------------*/
+ /* If we returning a structure then we set the first parameter register */
+ /* to the address of where we are returning this structure */
+ /*----------------------------------------------------------------------*/
+ if (flags == FFI_TYPE_STRUCT)
+ stack->gprArgs[intArgC++] = (int) ecif->rvalue;
+
+ for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs;
+ i > 0;
+ i--, ptr++, p_argv++)
+ {
+ switch ((*ptr)->type) {
+
+ case FFI_TYPE_FLOAT:
+ if (fprArgC < MAX_FPRARGS)
+ stack->fprArgs[fprArgC++].f = *(float *) *p_argv;
+ else
+ stack->outArgs[outArgC++] = *(int *) *p_argv;
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ dblValue = *(double *) *p_argv;
+ ffi_insert_double(dblValue, stack, &fprArgC, &outArgC);
+ break;
+
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_SINT64:
+ llngValue = *(unsigned long long *) *p_argv;
+ ffi_insert_int64(llngValue, stack, &intArgC, &outArgC);
+ break;
+
+ case FFI_TYPE_UINT8:
+ gprValue = *(unsigned char *)*p_argv;
+ ffi_insert_int(gprValue, stack, &intArgC, &outArgC);
+ break;
+
+ case FFI_TYPE_SINT8:
+ gprValue = *(signed char *)*p_argv;
+ ffi_insert_int(gprValue, stack, &intArgC, &outArgC);
+ break;
+
+ case FFI_TYPE_UINT16:
+ gprValue = *(unsigned short *)*p_argv;
+ ffi_insert_int(gprValue, stack, &intArgC, &outArgC);
+ break;
+
+ case FFI_TYPE_SINT16:
+ gprValue = *(signed short *)*p_argv;
+ ffi_insert_int(gprValue, stack, &intArgC, &outArgC);
+ break;
+
+ case FFI_TYPE_STRUCT:
+ /*--------------------------------------------------*/
+ /* If structure > 8 bytes then it goes on the stack */
+ /*--------------------------------------------------*/
+ if (((*ptr)->size > 8) ||
+ ((*ptr)->size > 4 &&
+ (*ptr)->size < 8))
+ strFlags = STR_STACK;
+ else
+ strFlags = ffi_check_struct((ffi_type *) *ptr, &strFlags);
+
+ switch (strFlags) {
+ /*-------------------------------------------*/
+ /* Structure that will fit in one or two GPR */
+ /*-------------------------------------------*/
+ case STR_GPR :
+ if ((*ptr)->size <= 4) {
+ gprValue = *(unsigned int *) *p_argv;
+ gprValue = gprValue >> ((4 - (*ptr)->size) * 8);
+ ffi_insert_int(gprValue, stack, &intArgC, &outArgC);
+ }
+ else {
+ llngValue = *(unsigned long long *) *p_argv;
+ ffi_insert_int64(llngValue, stack, &intArgC, &outArgC);
+ }
+ break;
+
+ /*-------------------------------------------*/
+ /* Structure that will fit in one FPR */
+ /*-------------------------------------------*/
+ case STR_FPR :
+ dblValue = *(double *) *p_argv;
+ ffi_insert_double(dblValue, stack, &fprArgC, &outArgC);
+ break;
+
+ /*-------------------------------------------*/
+ /* Structure that must be copied to stack */
+ /*-------------------------------------------*/
+ default :
+ structCopySize = (((*ptr)->size + 15) & ~0xF);
+ copySpace -= structCopySize;
+ memcpy(copySpace, (char *)*p_argv, (*ptr)->size);
+ gprValue = (unsigned) copySpace;
+ if (intArgC < MAX_GPRARGS)
+ stack->gprArgs[intArgC++] = gprValue;
+ else
+ stack->outArgs[outArgC++] = gprValue;
+ }
+ break;
+
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+ structCopySize = (((*ptr)->size + 15) & ~0xF);
+ copySpace -= structCopySize;
+ memcpy(copySpace, (char *)*p_argv, (*ptr)->size);
+ gprValue = (unsigned) copySpace;
+ if (intArgC < MAX_GPRARGS)
+ stack->gprArgs[intArgC++] = gprValue;
+ else
+ stack->outArgs[outArgC++] = gprValue;
+ break;
+#endif
+
+ case FFI_TYPE_INT:
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_POINTER:
+ gprValue = *(unsigned *)*p_argv;
+ if (intArgC < MAX_GPRARGS)
+ stack->gprArgs[intArgC++] = gprValue;
+ else
+ stack->outArgs[outArgC++] = gprValue;
+ break;
+
+ }
+ }
+}
+
+/*======================== End of Routine ============================*/
+
+/*====================================================================*/
+/* */
+/* Name - ffi_prep_cif_machdep. */
+/* */
+/* Function - Perform machine dependent CIF processing. */
+/* */
+/*====================================================================*/
+
+ffi_status
+ffi_prep_cif_machdep(ffi_cif *cif)
+{
+ int i;
+ ffi_type **ptr;
+ unsigned bytes;
+ int fpArgC = 0,
+ intArgC = 0;
+ unsigned flags = 0;
+ unsigned structCopySize = 0;
+
+ /*-----------------------------------------------------------------*/
+ /* Extra space required in stack for overflow parameters. */
+ /*-----------------------------------------------------------------*/
+ bytes = 0;
+
+ /*--------------------------------------------------------*/
+ /* Return value handling. The rules are as follows: */
+ /* - 32-bit (or less) integer values are returned in gpr2 */
+ /* - Structures are returned as pointers in gpr2 */
+ /* - 64-bit integer values are returned in gpr2 and 3 */
+ /* - Single/double FP values are returned in fpr0 */
+ /*--------------------------------------------------------*/
+ flags = cif->rtype->type;
+
+ /*------------------------------------------------------------------------*/
+ /* The first MAX_GPRARGS words of integer arguments, and the */
+ /* first MAX_FPRARGS floating point arguments, go in registers; the rest */
+ /* goes on the stack. Structures and long doubles (if not equivalent */
+ /* to double) are passed as a pointer to a copy of the structure. */
+ /* Stuff on the stack needs to keep proper alignment. */
+ /*------------------------------------------------------------------------*/
+ for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
+ {
+ switch ((*ptr)->type)
+ {
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ fpArgC++;
+ if (fpArgC > MAX_FPRARGS && intArgC%2 != 0)
+ intArgC++;
+ break;
+
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_SINT64:
+ /*----------------------------------------------------*/
+ /* 'long long' arguments are passed as two words, but */
+ /* either both words must fit in registers or both go */
+ /* on the stack. If they go on the stack, they must */
+ /* be 8-byte-aligned. */
+ /*----------------------------------------------------*/
+ if ((intArgC == MAX_GPRARGS-1) ||
+ (intArgC >= MAX_GPRARGS) &&
+ (intArgC%2 != 0))
+ intArgC++;
+ intArgC += 2;
+ break;
+
+ case FFI_TYPE_STRUCT:
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+#endif
+ /*----------------------------------------------------*/
+ /* We must allocate space for a copy of these to */
+ /* enforce pass-by-value. Pad the space up to a */
+ /* multiple of 16 bytes (the maximum alignment */
+ /* required for anything under the SYSV ABI). */
+ /*----------------------------------------------------*/
+ structCopySize += ((*ptr)->size + 15) & ~0xF;
+ /*----------------------------------------------------*/
+ /* Fall through (allocate space for the pointer). */
+ /*----------------------------------------------------*/
+
+ default:
+ /*----------------------------------------------------*/
+ /* Everything else is passed as a 4-byte word in a */
+ /* GPR either the object itself or a pointer to it. */
+ /*----------------------------------------------------*/
+ intArgC++;
+ break;
+ }
+ }
+
+ /*-----------------------------------------------------------------*/
+ /* Stack space. */
+ /*-----------------------------------------------------------------*/
+ if (intArgC > MAX_GPRARGS)
+ bytes += (intArgC - MAX_GPRARGS) * sizeof(int);
+ if (fpArgC > MAX_FPRARGS)
+ bytes += (fpArgC - MAX_FPRARGS) * sizeof(double);
+
+ /*-----------------------------------------------------------------*/
+ /* The stack space allocated needs to be a multiple of 16 bytes. */
+ /*-----------------------------------------------------------------*/
+ bytes = (bytes + 15) & ~0xF;
+
+ /*-----------------------------------------------------------------*/
+ /* Add in the space for the copied structures. */
+ /*-----------------------------------------------------------------*/
+ bytes += structCopySize;
+
+ cif->flags = flags;
+ cif->bytes = bytes;
+
+ return FFI_OK;
+}
+
+/*======================== End of Routine ============================*/
+
+/*====================================================================*/
+/* */
+/* Name - ffi_call. */
+/* */
+/* Function - Call the FFI routine. */
+/* */
+/*====================================================================*/
+
+void
+ffi_call(ffi_cif *cif,
+ void (*fn)(),
+ void *rvalue,
+ void **avalue)
+{
+ extended_cif ecif;
+
+ 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 */
+ /*-----------------------------------------------------------------*/
+ if ((rvalue == NULL) &&
+ (cif->rtype->type == FFI_TYPE_STRUCT))
+ ecif.rvalue = alloca(cif->rtype->size);
+ else
+ ecif.rvalue = rvalue;
+
+ switch (cif->abi)
+ {
+ case FFI_SYSV:
+ ffi_call_SYSV(ffi_prep_args,
+ &ecif, cif->bytes,
+ cif->flags, ecif.rvalue, fn);
+ break;
+
+ default:
+ FFI_ASSERT(0);
+ break;
+ }
+}
+
+/*======================== End of Routine ============================*/
diff --git a/libffi/src/s390/sysv.S b/libffi/src/s390/sysv.S
new file mode 100644
index 00000000000..afaf1ea1ca3
--- /dev/null
+++ b/libffi/src/s390/sysv.S
@@ -0,0 +1,161 @@
+/* -----------------------------------------------------------------------
+ sysv.S - Copyright (c) 2000 Software AG
+
+ S390 Foreign Function Interface
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ ``Software''), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+ ----------------------------------------------------------------------- */
+
+#define LIBFFI_ASM
+#include <ffi.h>
+#ifdef HAVE_MACHINE_ASM_H
+#include <machine/asm.h>
+#endif
+
+.text
+
+ # r2: ffi_prep_args
+ # r3: &ecif
+ # r4: cif->bytes
+ # r5: fig->flags
+ # r6: ecif.rvalue
+ # sp+0: fn
+
+ # This assumes we are using gas.
+ .globl ffi_call_SYSV
+ .type ffi_call_SYSV,%function
+ffi_call_SYSV:
+ # Save registers
+ stm %r7,%r15,28(%r15)
+ l %r7,96(%r15) # Get A(fn)
+ lr %r0,%r15
+ ahi %r15,-128 # Make room for my args
+ st %r0,0(%r15) # Set backchain
+ lr %r11,%r15 # Establish my stack register
+ sr %r15,%r4 # Make room for fn args
+ ahi %r15,-96 # Make room for new frame
+ lr %r10,%r15 # Establish stack build area
+ ahi %r15,-96 # Stack for next call
+ lr %r1,%r7
+ stm %r2,%r7,96(%r11) # Save args on my stack
+
+#------------------------------------------------------------------
+# move first 3 parameters in registers
+#------------------------------------------------------------------
+ lr %r9,%r2 # r9: &ffi_prep_args
+ lr %r2,%r10 # Parm 1: &stack Parm 2: &ecif
+ basr %r14,%r9 # call ffi_prep_args
+
+#------------------------------------------------------------------
+# load first 5 parameter registers
+#------------------------------------------------------------------
+ lm %r2,%r6,24(%r10)
+
+#------------------------------------------------------------------
+# load fp parameter registers
+#------------------------------------------------------------------
+ ld %f0,48(%r10)
+ ld %f2,56(%r10)
+
+#------------------------------------------------------------------
+# call function
+#------------------------------------------------------------------
+ lr %r15,%r10 # Set new stack
+ l %r9,116(%r11) # Get &fn
+ basr %r14,%r9 # Call function
+
+#------------------------------------------------------------------
+# On return:
+# r2: Return value (r3: Return value + 4 for long long)
+#------------------------------------------------------------------
+
+#------------------------------------------------------------------
+# If the return value pointer is NULL, assume no return value.
+#------------------------------------------------------------------
+ icm %r6,15,112(%r11)
+ jz .Lepilogue
+
+ l %r5,108(%r11) # Get return type
+#------------------------------------------------------------------
+# return INT
+#------------------------------------------------------------------
+ chi %r5,FFI_TYPE_INT
+ jne .Lchk64
+
+ st %r2,0(%r6)
+ j .Lepilogue
+
+.Lchk64:
+#------------------------------------------------------------------
+# return LONG LONG (signed/unsigned)
+#------------------------------------------------------------------
+ chi %r5,FFI_TYPE_UINT64
+ je .LdoLongLong
+
+ chi %r5,FFI_TYPE_SINT64
+ jne .LchkFloat
+
+.LdoLongLong:
+ stm %r2,%r3,0(%r6)
+ j .Lepilogue
+
+.LchkFloat:
+#------------------------------------------------------------------
+# return FLOAT
+#------------------------------------------------------------------
+ chi %r5,FFI_TYPE_FLOAT
+ jne .LchkDouble
+
+ std %f0,0(%r6)
+ j .Lepilogue
+
+.LchkDouble:
+#------------------------------------------------------------------
+# return DOUBLE or LONGDOUBLE
+#------------------------------------------------------------------
+ chi %r5,FFI_TYPE_DOUBLE
+ jne .LchkStruct
+
+ std %f0,0(%r6)
+ std %f2,8(%r6)
+ j .Lepilogue
+
+.LchkStruct:
+#------------------------------------------------------------------
+# Structure - rvalue already set as sent as 1st parm to routine
+#------------------------------------------------------------------
+ chi %r5,FFI_TYPE_STRUCT
+ je .Lepilogue
+
+.Ldefault:
+#------------------------------------------------------------------
+# return a pointer
+#------------------------------------------------------------------
+ st %r2,0(%r6)
+ j .Lepilogue
+
+.Lepilogue:
+ l %r15,0(%r11)
+ l %r4,56(%r15)
+ lm %r7,%r15,28(%r15)
+ br %r4
+
+.ffi_call_SYSV_end:
+ .size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV