summaryrefslogtreecommitdiff
path: root/libffi/src/sh
diff options
context:
space:
mode:
Diffstat (limited to 'libffi/src/sh')
-rw-r--r--libffi/src/sh/ffi.c722
-rw-r--r--libffi/src/sh/ffitarget.h48
-rw-r--r--libffi/src/sh/sysv.S775
3 files changed, 1545 insertions, 0 deletions
diff --git a/libffi/src/sh/ffi.c b/libffi/src/sh/ffi.c
new file mode 100644
index 0000000..8aa96a1
--- /dev/null
+++ b/libffi/src/sh/ffi.c
@@ -0,0 +1,722 @@
+/* -----------------------------------------------------------------------
+ ffi.c - Copyright (c) 2002, 2003 Kaz Kojima
+
+ SuperH 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.
+ ----------------------------------------------------------------------- */
+
+#include <ffi.h>
+#include <ffi_common.h>
+
+#include <stdlib.h>
+
+#define NGREGARG 4
+#if defined(__SH4__)
+#define NFREGARG 8
+#endif
+
+#if defined(__HITACHI__)
+#define STRUCT_VALUE_ADDRESS_WITH_ARG 1
+#else
+#define STRUCT_VALUE_ADDRESS_WITH_ARG 0
+#endif
+
+/* If the structure has essentialy an unique element, return its type. */
+static int
+simple_type (ffi_type *arg)
+{
+ if (arg->type != FFI_TYPE_STRUCT)
+ return arg->type;
+ else if (arg->elements[1])
+ return FFI_TYPE_STRUCT;
+
+ return simple_type (arg->elements[0]);
+}
+
+static int
+return_type (ffi_type *arg)
+{
+ unsigned short type;
+
+ if (arg->type != FFI_TYPE_STRUCT)
+ return arg->type;
+
+ type = simple_type (arg->elements[0]);
+ if (! arg->elements[1])
+ {
+ switch (type)
+ {
+ case FFI_TYPE_SINT8:
+ case FFI_TYPE_UINT8:
+ case FFI_TYPE_SINT16:
+ case FFI_TYPE_UINT16:
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_UINT32:
+ return FFI_TYPE_INT;
+
+ default:
+ return type;
+ }
+ }
+
+ /* gcc uses r0/r1 pair for some kind of structures. */
+ if (arg->size <= 2 * sizeof (int))
+ {
+ int i = 0;
+ ffi_type *e;
+
+ while ((e = arg->elements[i++]))
+ {
+ type = simple_type (e);
+ switch (type)
+ {
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_INT:
+ case FFI_TYPE_FLOAT:
+ return FFI_TYPE_UINT64;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ return FFI_TYPE_STRUCT;
+}
+
+/* ffi_prep_args is called by the assembly routine once stack space
+ has been allocated for the function's arguments */
+
+/*@-exportheader@*/
+void ffi_prep_args(char *stack, extended_cif *ecif)
+/*@=exportheader@*/
+{
+ register unsigned int i;
+ register int tmp;
+ register unsigned int avn;
+ register void **p_argv;
+ register char *argp;
+ register ffi_type **p_arg;
+ int greg, ireg;
+#if defined(__SH4__)
+ int freg = 0;
+#endif
+
+ tmp = 0;
+ argp = stack;
+
+ if (return_type (ecif->cif->rtype) == FFI_TYPE_STRUCT)
+ {
+ *(void **) argp = ecif->rvalue;
+ argp += 4;
+ ireg = STRUCT_VALUE_ADDRESS_WITH_ARG ? 1 : 0;
+ }
+ else
+ ireg = 0;
+
+ /* Set arguments for registers. */
+ greg = ireg;
+ avn = ecif->cif->nargs;
+ p_argv = ecif->avalue;
+
+ for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
+ {
+ size_t z;
+
+ z = (*p_arg)->size;
+ if (z < sizeof(int))
+ {
+ if (greg++ >= NGREGARG)
+ continue;
+
+ z = sizeof(int);
+ switch ((*p_arg)->type)
+ {
+ case FFI_TYPE_SINT8:
+ *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT8:
+ *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_SINT16:
+ *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT16:
+ *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_STRUCT:
+ *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
+ break;
+
+ default:
+ FFI_ASSERT(0);
+ }
+ argp += z;
+ }
+ else if (z == sizeof(int))
+ {
+#if defined(__SH4__)
+ if ((*p_arg)->type == FFI_TYPE_FLOAT)
+ {
+ if (freg++ >= NFREGARG)
+ continue;
+ }
+ else
+#endif
+ {
+ if (greg++ >= NGREGARG)
+ continue;
+ }
+ *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
+ argp += z;
+ }
+#if defined(__SH4__)
+ else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
+ {
+ if (freg + 1 >= NFREGARG)
+ continue;
+ freg = (freg + 1) & ~1;
+ freg += 2;
+ memcpy (argp, *p_argv, z);
+ argp += z;
+ }
+#endif
+ else
+ {
+ int n = (z + sizeof (int) - 1) / sizeof (int);
+#if defined(__SH4__)
+ if (greg + n - 1 >= NGREGARG)
+ continue;
+ greg += n;
+#else
+ if (greg >= NGREGARG)
+ continue;
+ else if (greg + n - 1 >= NGREGARG)
+ greg = NGREGARG;
+ else
+ greg += n;
+#endif
+ memcpy (argp, *p_argv, z);
+ argp += n * sizeof (int);
+ }
+ }
+
+ /* Set arguments on stack. */
+ greg = ireg;
+#if defined(__SH4__)
+ freg = 0;
+#endif
+ p_argv = ecif->avalue;
+
+ for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
+ {
+ size_t z;
+
+ z = (*p_arg)->size;
+ if (z < sizeof(int))
+ {
+ if (greg++ < NGREGARG)
+ continue;
+
+ z = sizeof(int);
+ switch ((*p_arg)->type)
+ {
+ case FFI_TYPE_SINT8:
+ *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT8:
+ *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_SINT16:
+ *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT16:
+ *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_STRUCT:
+ *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
+ break;
+
+ default:
+ FFI_ASSERT(0);
+ }
+ argp += z;
+ }
+ else if (z == sizeof(int))
+ {
+#if defined(__SH4__)
+ if ((*p_arg)->type == FFI_TYPE_FLOAT)
+ {
+ if (freg++ < NFREGARG)
+ continue;
+ }
+ else
+#endif
+ {
+ if (greg++ < NGREGARG)
+ continue;
+ }
+ *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
+ argp += z;
+ }
+#if defined(__SH4__)
+ else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
+ {
+ if (freg + 1 < NFREGARG)
+ {
+ freg = (freg + 1) & ~1;
+ freg += 2;
+ continue;
+ }
+ memcpy (argp, *p_argv, z);
+ argp += z;
+ }
+#endif
+ else
+ {
+ int n = (z + sizeof (int) - 1) / sizeof (int);
+ if (greg + n - 1 < NGREGARG)
+ {
+ greg += n;
+ continue;
+ }
+#if (! defined(__SH4__))
+ else if (greg < NGREGARG)
+ {
+ greg = NGREGARG;
+ continue;
+ }
+#endif
+ memcpy (argp, *p_argv, z);
+ argp += n * sizeof (int);
+ }
+ }
+
+ return;
+}
+
+/* Perform machine dependent cif processing */
+ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
+{
+ int i, j;
+ int size, type;
+ int n, m;
+ int greg;
+#if defined(__SH4__)
+ int freg = 0;
+#endif
+
+ cif->flags = 0;
+
+ greg = ((return_type (cif->rtype) == FFI_TYPE_STRUCT) &&
+ STRUCT_VALUE_ADDRESS_WITH_ARG) ? 1 : 0;
+
+#if defined(__SH4__)
+ for (i = j = 0; i < cif->nargs && j < 12; i++)
+ {
+ type = (cif->arg_types)[i]->type;
+ switch (type)
+ {
+ case FFI_TYPE_FLOAT:
+ if (freg >= NFREGARG)
+ continue;
+ freg++;
+ cif->flags += ((cif->arg_types)[i]->type) << (2 * j);
+ j++;
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ if ((freg + 1) >= NFREGARG)
+ continue;
+ freg = (freg + 1) & ~1;
+ freg += 2;
+ cif->flags += ((cif->arg_types)[i]->type) << (2 * j);
+ j++;
+ break;
+
+ default:
+ size = (cif->arg_types)[i]->size;
+ n = (size + sizeof (int) - 1) / sizeof (int);
+ if (greg + n - 1 >= NGREGARG)
+ continue;
+ greg += n;
+ for (m = 0; m < n; m++)
+ cif->flags += FFI_TYPE_INT << (2 * j++);
+ break;
+ }
+ }
+#else
+ for (i = j = 0; i < cif->nargs && j < 4; i++)
+ {
+ size = (cif->arg_types)[i]->size;
+ n = (size + sizeof (int) - 1) / sizeof (int);
+ if (greg >= NGREGARG)
+ continue;
+ else if (greg + n - 1 >= NGREGARG)
+ greg = NGREGARG;
+ else
+ greg += n;
+ for (m = 0; m < n; m++)
+ cif->flags += FFI_TYPE_INT << (2 * j++);
+ }
+#endif
+
+ /* Set the return type flag */
+ switch (cif->rtype->type)
+ {
+ case FFI_TYPE_STRUCT:
+ cif->flags += (unsigned) (return_type (cif->rtype)) << 24;
+ break;
+
+ case FFI_TYPE_VOID:
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT64:
+ cif->flags += (unsigned) cif->rtype->type << 24;
+ break;
+
+ default:
+ cif->flags += FFI_TYPE_INT << 24;
+ break;
+ }
+
+ return FFI_OK;
+}
+
+/*@-declundef@*/
+/*@-exportheader@*/
+extern void ffi_call_SYSV(void (*)(char *, extended_cif *),
+ /*@out@*/ extended_cif *,
+ unsigned, unsigned,
+ /*@out@*/ unsigned *,
+ void (*fn)());
+/*@=declundef@*/
+/*@=exportheader@*/
+
+void ffi_call(/*@dependent@*/ ffi_cif *cif,
+ void (*fn)(),
+ /*@out@*/ void *rvalue,
+ /*@dependent@*/ 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))
+ {
+ /*@-sysunrecog@*/
+ ecif.rvalue = alloca(cif->rtype->size);
+ /*@=sysunrecog@*/
+ }
+ else
+ ecif.rvalue = rvalue;
+
+
+ switch (cif->abi)
+ {
+ case FFI_SYSV:
+ /*@-usedef@*/
+ ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes,
+ cif->flags, ecif.rvalue, fn);
+ /*@=usedef@*/
+ break;
+ default:
+ FFI_ASSERT(0);
+ break;
+ }
+}
+
+extern void ffi_closure_SYSV (void);
+#if defined(__SH4__)
+extern void __ic_invalidate (void *line);
+#endif
+
+ffi_status
+ffi_prep_closure (ffi_closure* closure,
+ ffi_cif* cif,
+ void (*fun)(ffi_cif*, void*, void**, void*),
+ void *user_data)
+{
+ unsigned int *tramp;
+
+ FFI_ASSERT (cif->abi == FFI_GCC_SYSV);
+
+ tramp = (unsigned int *) &closure->tramp[0];
+#ifdef __LITTLE_ENDIAN__
+ tramp[0] = 0xd301d202;
+ tramp[1] = 0x0009422b;
+#else
+ tramp[0] = 0xd202d301;
+ tramp[1] = 0x422b0009;
+#endif
+ *(void **) &tramp[2] = (void *)closure; /* ctx */
+ *(void **) &tramp[3] = (void *)ffi_closure_SYSV; /* funaddr */
+
+ closure->cif = cif;
+ closure->fun = fun;
+ closure->user_data = user_data;
+
+#if defined(__SH4__)
+ /* Flush the icache. */
+ __ic_invalidate(&closure->tramp[0]);
+#endif
+
+ return FFI_OK;
+}
+
+/* Basically the trampoline invokes ffi_closure_SYSV, and on
+ * entry, r3 holds the address of the closure.
+ * After storing the registers that could possibly contain
+ * parameters to be passed into the stack frame and setting
+ * up space for a return value, ffi_closure_SYSV invokes the
+ * following helper function to do most of the work.
+ */
+
+#ifdef __LITTLE_ENDIAN__
+#define OFS_INT8 0
+#define OFS_INT16 0
+#else
+#define OFS_INT8 3
+#define OFS_INT16 2
+#endif
+
+int
+ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
+ unsigned long *pgr, unsigned long *pfr,
+ unsigned long *pst)
+{
+ void **avalue;
+ ffi_type **p_arg;
+ int i, avn;
+ int ireg, greg = 0;
+#if defined(__SH4__)
+ int freg = 0;
+#endif
+ ffi_cif *cif;
+ double temp;
+
+ cif = closure->cif;
+ avalue = alloca(cif->nargs * sizeof(void *));
+
+ /* Copy the caller's structure return value address so that the closure
+ returns the data directly to the caller. */
+ if (cif->rtype->type == FFI_TYPE_STRUCT && STRUCT_VALUE_ADDRESS_WITH_ARG)
+ {
+ rvalue = *pgr++;
+ ireg = 1;
+ }
+ else
+ ireg = 0;
+
+ cif = closure->cif;
+ greg = ireg;
+ avn = cif->nargs;
+
+ /* Grab the addresses of the arguments from the stack frame. */
+ for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
+ {
+ size_t z;
+
+ z = (*p_arg)->size;
+ if (z < sizeof(int))
+ {
+ if (greg++ >= NGREGARG)
+ continue;
+
+ z = sizeof(int);
+ switch ((*p_arg)->type)
+ {
+ case FFI_TYPE_SINT8:
+ case FFI_TYPE_UINT8:
+ avalue[i] = (((char *)pgr) + OFS_INT8);
+ break;
+
+ case FFI_TYPE_SINT16:
+ case FFI_TYPE_UINT16:
+ avalue[i] = (((char *)pgr) + OFS_INT16);
+ break;
+
+ case FFI_TYPE_STRUCT:
+ avalue[i] = pgr;
+ break;
+
+ default:
+ FFI_ASSERT(0);
+ }
+ pgr++;
+ }
+ else if (z == sizeof(int))
+ {
+#if defined(__SH4__)
+ if ((*p_arg)->type == FFI_TYPE_FLOAT)
+ {
+ if (freg++ >= NFREGARG)
+ continue;
+ avalue[i] = pfr;
+ pfr++;
+ }
+ else
+#endif
+ {
+ if (greg++ >= NGREGARG)
+ continue;
+ avalue[i] = pgr;
+ pgr++;
+ }
+ }
+#if defined(__SH4__)
+ else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
+ {
+ if (freg + 1 >= NFREGARG)
+ continue;
+ freg = (freg + 1) & ~1;
+ freg += 2;
+ avalue[i] = pfr;
+ pfr += 2;
+ }
+#endif
+ else
+ {
+ int n = (z + sizeof (int) - 1) / sizeof (int);
+#if defined(__SH4__)
+ if (greg + n - 1 >= NGREGARG)
+ continue;
+ greg += n;
+#else
+ if (greg >= NGREGARG)
+ continue;
+ else if (greg + n - 1 >= NGREGARG)
+ greg = NGREGARG;
+ else
+ greg += n;
+#endif
+ avalue[i] = pgr;
+ pgr += n;
+ }
+ }
+
+ greg = ireg;
+#if defined(__SH4__)
+ freg = 0;
+#endif
+
+ for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
+ {
+ size_t z;
+
+ z = (*p_arg)->size;
+ if (z < sizeof(int))
+ {
+ if (greg++ < NGREGARG)
+ continue;
+
+ z = sizeof(int);
+ switch ((*p_arg)->type)
+ {
+ case FFI_TYPE_SINT8:
+ case FFI_TYPE_UINT8:
+ avalue[i] = (((char *)pst) + OFS_INT8);
+ break;
+
+ case FFI_TYPE_SINT16:
+ case FFI_TYPE_UINT16:
+ avalue[i] = (((char *)pst) + OFS_INT16);
+ break;
+
+ case FFI_TYPE_STRUCT:
+ avalue[i] = pst;
+ break;
+
+ default:
+ FFI_ASSERT(0);
+ }
+ pst++;
+ }
+ else if (z == sizeof(int))
+ {
+#if defined(__SH4__)
+ if ((*p_arg)->type == FFI_TYPE_FLOAT)
+ {
+ if (freg++ < NFREGARG)
+ continue;
+ }
+ else
+#endif
+ {
+ if (greg++ < NGREGARG)
+ continue;
+ }
+ avalue[i] = pst;
+ pst++;
+ }
+#if defined(__SH4__)
+ else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
+ {
+ if (freg + 1 < NFREGARG)
+ {
+ freg = (freg + 1) & ~1;
+ freg += 2;
+ continue;
+ }
+ avalue[i] = pst;
+ pst += 2;
+ }
+#endif
+ else
+ {
+ int n = (z + sizeof (int) - 1) / sizeof (int);
+ if (greg + n - 1 < NGREGARG)
+ {
+ greg += n;
+ continue;
+ }
+#if (! defined(__SH4__))
+ else if (greg < NGREGARG)
+ {
+ greg = NGREGARG;
+ continue;
+ }
+#endif
+ avalue[i] = pst;
+ pst += n;
+ }
+ }
+
+ (closure->fun) (cif, rvalue, avalue, closure->user_data);
+
+ /* Tell ffi_closure_SYSV how to perform return type promotions. */
+ return return_type (cif->rtype);
+}
diff --git a/libffi/src/sh/ffitarget.h b/libffi/src/sh/ffitarget.h
new file mode 100644
index 0000000..f8492a1
--- /dev/null
+++ b/libffi/src/sh/ffitarget.h
@@ -0,0 +1,48 @@
+/* -----------------------------------------------------------------*-C-*-
+ ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
+ Target configuration macros for SuperH.
+
+ 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.
+
+ ----------------------------------------------------------------------- */
+
+#ifndef LIBFFI_TARGET_H
+#define LIBFFI_TARGET_H
+
+/* ---- Generic type definitions ----------------------------------------- */
+
+#ifndef LIBFFI_ASM
+typedef unsigned long ffi_arg;
+typedef signed long ffi_sarg;
+
+typedef enum ffi_abi {
+ FFI_FIRST_ABI = 0,
+ FFI_SYSV,
+ FFI_DEFAULT_ABI = FFI_SYSV,
+ FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
+} ffi_abi;
+#endif
+
+#define FFI_CLOSURES 1
+#define FFI_TRAMPOLINE_SIZE 16
+#define FFI_NATIVE_RAW_API 0
+
+#endif
+
diff --git a/libffi/src/sh/sysv.S b/libffi/src/sh/sysv.S
new file mode 100644
index 0000000..a7121c5
--- /dev/null
+++ b/libffi/src/sh/sysv.S
@@ -0,0 +1,775 @@
+/* -----------------------------------------------------------------------
+ sysv.S - Copyright (c) 2002, 2003 Kaz Kojima
+
+ SuperH 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 <fficonfig.h>
+#include <ffi.h>
+#ifdef HAVE_MACHINE_ASM_H
+#include <machine/asm.h>
+#else
+/* XXX these lose for some platforms, I'm sure. */
+#define CNAME(x) x
+#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x):
+#endif
+
+#if defined(__HITACHI__)
+#define STRUCT_VALUE_ADDRESS_WITH_ARG 1
+#else
+#define STRUCT_VALUE_ADDRESS_WITH_ARG 0
+#endif
+
+.text
+
+ # r4: ffi_prep_args
+ # r5: &ecif
+ # r6: bytes
+ # r7: flags
+ # sp+0: rvalue
+ # sp+4: fn
+
+ # This assumes we are using gas.
+ENTRY(ffi_call_SYSV)
+ # Save registers
+.LFB1:
+ mov.l r8,@-r15
+.LCFI0:
+ mov.l r9,@-r15
+.LCFI1:
+ mov.l r10,@-r15
+.LCFI2:
+ mov.l r12,@-r15
+.LCFI3:
+ mov.l r14,@-r15
+.LCFI4:
+ sts.l pr,@-r15
+.LCFI5:
+ mov r15,r14
+.LCFI6:
+#if defined(__SH4__)
+ mov r6,r8
+ mov r7,r9
+
+ sub r6,r15
+ add #-16,r15
+ mov #~7,r0
+ and r0,r15
+
+ mov r4,r0
+ jsr @r0
+ mov r15,r4
+
+ mov r9,r1
+ shlr8 r9
+ shlr8 r9
+ shlr8 r9
+
+ mov #FFI_TYPE_STRUCT,r2
+ cmp/eq r2,r9
+ bf 1f
+#if STRUCT_VALUE_ADDRESS_WITH_ARG
+ mov.l @r15+,r4
+ bra 2f
+ mov #5,r2
+#else
+ mov.l @r15+,r10
+#endif
+1:
+ mov #4,r2
+2:
+ mov #4,r3
+
+L_pass:
+ cmp/pl r8
+ bf L_call_it
+
+ mov r1,r0
+ and #3,r0
+
+L_pass_d:
+ cmp/eq #FFI_TYPE_DOUBLE,r0
+ bf L_pass_f
+
+ mov r3,r0
+ and #1,r0
+ tst r0,r0
+ bt 1f
+ add #1,r3
+1:
+ mov r15,r0
+ and #7,r0
+ tst r0,r0
+ bt 2f
+ add #4,r15
+2:
+ mov #12,r0
+ cmp/hs r0,r3
+ bt/s 3f
+ shlr2 r1
+ bsr L_pop_d
+ nop
+3:
+ add #2,r3
+ bra L_pass
+ add #-8,r8
+
+L_pop_d:
+ mov r3,r0
+ add r0,r0
+ add r3,r0
+ add #-12,r0
+ braf r0
+ nop
+#ifdef __LITTLE_ENDIAN__
+ fmov.s @r15+,fr5
+ rts
+ fmov.s @r15+,fr4
+ fmov.s @r15+,fr7
+ rts
+ fmov.s @r15+,fr6
+ fmov.s @r15+,fr9
+ rts
+ fmov.s @r15+,fr8
+ fmov.s @r15+,fr11
+ rts
+ fmov.s @r15+,fr10
+#else
+ fmov.s @r15+,fr4
+ rts
+ fmov.s @r15+,fr5
+ fmov.s @r15+,fr6
+ rts
+ fmov.s @r15+,fr7
+ fmov.s @r15+,fr8
+ rts
+ fmov.s @r15+,fr9
+ fmov.s @r15+,fr10
+ rts
+ fmov.s @r15+,fr11
+#endif
+
+L_pass_f:
+ cmp/eq #FFI_TYPE_FLOAT,r0
+ bf L_pass_i
+
+ mov #12,r0
+ cmp/hs r0,r3
+ bt/s 2f
+ shlr2 r1
+ bsr L_pop_f
+ nop
+2:
+ add #1,r3
+ bra L_pass
+ add #-4,r8
+
+L_pop_f:
+ mov r3,r0
+ shll2 r0
+ add #-16,r0
+ braf r0
+ nop
+#ifdef __LITTLE_ENDIAN__
+ rts
+ fmov.s @r15+,fr5
+ rts
+ fmov.s @r15+,fr4
+ rts
+ fmov.s @r15+,fr7
+ rts
+ fmov.s @r15+,fr6
+ rts
+ fmov.s @r15+,fr9
+ rts
+ fmov.s @r15+,fr8
+ rts
+ fmov.s @r15+,fr11
+ rts
+ fmov.s @r15+,fr10
+#else
+ rts
+ fmov.s @r15+,fr4
+ rts
+ fmov.s @r15+,fr5
+ rts
+ fmov.s @r15+,fr6
+ rts
+ fmov.s @r15+,fr7
+ rts
+ fmov.s @r15+,fr8
+ rts
+ fmov.s @r15+,fr9
+ rts
+ fmov.s @r15+,fr10
+ rts
+ fmov.s @r15+,fr11
+#endif
+
+L_pass_i:
+ cmp/eq #FFI_TYPE_INT,r0
+ bf L_call_it
+
+ mov #8,r0
+ cmp/hs r0,r2
+ bt/s 2f
+ shlr2 r1
+ bsr L_pop_i
+ nop
+2:
+ add #1,r2
+ bra L_pass
+ add #-4,r8
+
+L_pop_i:
+ mov r2,r0
+ shll2 r0
+ add #-16,r0
+ braf r0
+ nop
+ rts
+ mov.l @r15+,r4
+ rts
+ mov.l @r15+,r5
+ rts
+ mov.l @r15+,r6
+ rts
+ mov.l @r15+,r7
+
+L_call_it:
+ # call function
+#if (! STRUCT_VALUE_ADDRESS_WITH_ARG)
+ mov r10, r2
+#endif
+ mov.l @(28,r14),r1
+ jsr @r1
+ nop
+
+L_ret_d:
+ mov #FFI_TYPE_DOUBLE,r2
+ cmp/eq r2,r9
+ bf L_ret_ll
+
+ mov.l @(24,r14),r1
+#ifdef __LITTLE_ENDIAN__
+ fmov.s fr1,@r1
+ add #4,r1
+ bra L_epilogue
+ fmov.s fr0,@r1
+#else
+ fmov.s fr0,@r1
+ add #4,r1
+ bra L_epilogue
+ fmov.s fr1,@r1
+#endif
+
+L_ret_ll:
+ mov #FFI_TYPE_SINT64,r2
+ cmp/eq r2,r9
+ bt/s 1f
+ mov #FFI_TYPE_UINT64,r2
+ cmp/eq r2,r9
+ bf L_ret_f
+
+1:
+ mov.l @(24,r14),r2
+ mov.l r0,@r2
+ bra L_epilogue
+ mov.l r1,@(4,r2)
+
+L_ret_f:
+ mov #FFI_TYPE_FLOAT,r2
+ cmp/eq r2,r9
+ bf L_ret_i
+
+ mov.l @(24,r14),r1
+ bra L_epilogue
+ fmov.s fr0,@r1
+
+L_ret_i:
+ mov #FFI_TYPE_INT,r2
+ cmp/eq r2,r9
+ bf L_epilogue
+
+ mov.l @(24,r14),r1
+ bra L_epilogue
+ mov.l r0,@r1
+
+L_epilogue:
+ # Remove the space we pushed for the args
+ mov r14,r15
+
+ lds.l @r15+,pr
+ mov.l @r15+,r14
+ mov.l @r15+,r12
+ mov.l @r15+,r10
+ mov.l @r15+,r9
+ rts
+ mov.l @r15+,r8
+#else
+ mov r6,r8
+ mov r7,r9
+
+ sub r6,r15
+ add #-16,r15
+ mov #~7,r0
+ and r0,r15
+
+ mov r4,r0
+ jsr @r0
+ mov r15,r4
+
+ mov r9,r3
+ shlr8 r9
+ shlr8 r9
+ shlr8 r9
+
+ mov #FFI_TYPE_STRUCT,r2
+ cmp/eq r2,r9
+ bf 1f
+#if STRUCT_VALUE_ADDRESS_WITH_ARG
+ mov.l @r15+,r4
+ bra 2f
+ mov #5,r2
+#else
+ mov.l @r15+,r10
+#endif
+1:
+ mov #4,r2
+2:
+
+L_pass:
+ cmp/pl r8
+ bf L_call_it
+
+ mov r3,r0
+ and #3,r0
+
+L_pass_d:
+ cmp/eq #FFI_TYPE_DOUBLE,r0
+ bf L_pass_i
+
+ mov r15,r0
+ and #7,r0
+ tst r0,r0
+ bt 1f
+ add #4,r15
+1:
+ mov #8,r0
+ cmp/hs r0,r2
+ bt/s 2f
+ shlr2 r3
+ bsr L_pop_d
+ nop
+2:
+ add #2,r2
+ bra L_pass
+ add #-8,r8
+
+L_pop_d:
+ mov r2,r0
+ add r0,r0
+ add r2,r0
+ add #-12,r0
+ add r0,r0
+ braf r0
+ nop
+ mov.l @r15+,r4
+ rts
+ mov.l @r15+,r5
+ mov.l @r15+,r5
+ rts
+ mov.l @r15+,r6
+ mov.l @r15+,r6
+ rts
+ mov.l @r15+,r7
+ rts
+ mov.l @r15+,r7
+
+L_pass_i:
+ mov #8,r0
+ cmp/hs r0,r2
+ bt/s 2f
+ shlr2 r3
+ bsr L_pop_i
+ nop
+2:
+ add #1,r2
+ bra L_pass
+ add #-4,r8
+
+L_pop_i:
+ mov r2,r0
+ shll2 r0
+ add #-16,r0
+ braf r0
+ nop
+ rts
+ mov.l @r15+,r4
+ rts
+ mov.l @r15+,r5
+ rts
+ mov.l @r15+,r6
+ rts
+ mov.l @r15+,r7
+
+L_call_it:
+ # call function
+#if (! STRUCT_VALUE_ADDRESS_WITH_ARG)
+ mov r10, r2
+#endif
+ mov.l @(28,r14),r1
+ jsr @r1
+ nop
+
+L_ret_d:
+ mov #FFI_TYPE_DOUBLE,r2
+ cmp/eq r2,r9
+ bf L_ret_ll
+
+ mov.l @(24,r14),r2
+ mov.l r0,@r2
+ bra L_epilogue
+ mov.l r1,@(4,r2)
+
+L_ret_ll:
+ mov #FFI_TYPE_SINT64,r2
+ cmp/eq r2,r9
+ bt/s 1f
+ mov #FFI_TYPE_UINT64,r2
+ cmp/eq r2,r9
+ bf L_ret_i
+
+1:
+ mov.l @(24,r14),r2
+ mov.l r0,@r2
+ bra L_epilogue
+ mov.l r1,@(4,r2)
+
+L_ret_i:
+ mov #FFI_TYPE_FLOAT,r2
+ cmp/eq r2,r9
+ bt 1f
+ mov #FFI_TYPE_INT,r2
+ cmp/eq r2,r9
+ bf L_epilogue
+1:
+ mov.l @(24,r14),r1
+ bra L_epilogue
+ mov.l r0,@r1
+
+L_epilogue:
+ # Remove the space we pushed for the args
+ mov r14,r15
+
+ lds.l @r15+,pr
+ mov.l @r15+,r14
+ mov.l @r15+,r12
+ mov.l @r15+,r10
+ mov.l @r15+,r9
+ rts
+ mov.l @r15+,r8
+#endif
+.LFE1:
+.ffi_call_SYSV_end:
+ .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
+
+.globl ffi_closure_helper_SYSV
+
+ENTRY(ffi_closure_SYSV)
+.LFB2:
+ mov.l r14,@-r15
+.LCFI7:
+ sts.l pr,@-r15
+
+ /* Stack layout:
+ ...
+ 32 bytes (floating register parameters, SH-4 only)
+ 16 bytes (register parameters)
+ 8 bytes (result)
+ 4 bytes (pad)
+ 4 bytes (5th arg)
+ <- new stack pointer
+ */
+.LCFI8:
+#if defined(__SH4__)
+ add #-64,r15
+#else
+ add #-32,r15
+#endif
+.LCFI9:
+ mov r15,r14
+.LCFIA:
+ mov r14,r1
+ add #32,r1
+ mov.l r7,@-r1
+ mov.l r6,@-r1
+ mov.l r5,@-r1
+ mov.l r4,@-r1
+ mov r1,r6
+
+#if defined(__SH4__)
+ mov r14,r1
+ add #64,r1
+#ifdef __LITTLE_ENDIAN__
+ fmov.s fr10,@-r1
+ fmov.s fr11,@-r1
+ fmov.s fr8,@-r1
+ fmov.s fr9,@-r1
+ fmov.s fr6,@-r1
+ fmov.s fr7,@-r1
+ fmov.s fr4,@-r1
+ fmov.s fr5,@-r1
+#else
+ fmov.s fr11,@-r1
+ fmov.s fr10,@-r1
+ fmov.s fr9,@-r1
+ fmov.s fr8,@-r1
+ fmov.s fr7,@-r1
+ fmov.s fr6,@-r1
+ fmov.s fr5,@-r1
+ fmov.s fr4,@-r1
+#endif
+ mov r1,r7
+#endif
+
+ mov r14,r1
+ add #8,r1
+ mov r1,r5
+
+ mov r14,r1
+#if defined(__SH4__)
+ add #72,r1
+#else
+ add #40,r1
+#endif
+ mov.l r1,@r14
+
+ mov.l L_helper,r0
+ jsr @r0
+ mov r3,r4
+
+ shll r0
+ mov r0,r1
+ mova L_table,r0
+ add r1,r0
+ mov.w @r0,r0
+ mov r14,r2
+ braf r0
+ add #8,r2
+0:
+ .align 2
+L_helper:
+ .long ffi_closure_helper_SYSV
+L_table:
+ .short L_case_v - 0b /* FFI_TYPE_VOID */
+ .short L_case_i - 0b /* FFI_TYPE_INT */
+#if defined(__SH4__)
+ .short L_case_f - 0b /* FFI_TYPE_FLOAT */
+ .short L_case_d - 0b /* FFI_TYPE_DOUBLE */
+ .short L_case_d - 0b /* FFI_TYPE_LONGDOUBLE */
+#else
+ .short L_case_i - 0b /* FFI_TYPE_FLOAT */
+ .short L_case_ll - 0b /* FFI_TYPE_DOUBLE */
+ .short L_case_ll - 0b /* FFI_TYPE_LONGDOUBLE */
+#endif
+ .short L_case_uq - 0b /* FFI_TYPE_UINT8 */
+ .short L_case_q - 0b /* FFI_TYPE_SINT8 */
+ .short L_case_uh - 0b /* FFI_TYPE_UINT16 */
+ .short L_case_h - 0b /* FFI_TYPE_SINT16 */
+ .short L_case_i - 0b /* FFI_TYPE_UINT32 */
+ .short L_case_i - 0b /* FFI_TYPE_SINT32 */
+ .short L_case_ll - 0b /* FFI_TYPE_UINT64 */
+ .short L_case_ll - 0b /* FFI_TYPE_SINT64 */
+ .short L_case_v - 0b /* FFI_TYPE_STRUCT */
+ .short L_case_i - 0b /* FFI_TYPE_POINTER */
+
+#if defined(__SH4__)
+L_case_d:
+#ifdef __LITTLE_ENDIAN__
+ fmov.s @r2+,fr1
+ bra L_case_v
+ fmov.s @r2,fr0
+#else
+ fmov.s @r2+,fr0
+ bra L_case_v
+ fmov.s @r2,fr1
+#endif
+
+L_case_f:
+ bra L_case_v
+ fmov.s @r2,fr0
+#endif
+
+L_case_ll:
+ mov.l @r2+,r0
+ bra L_case_v
+ mov.l @r2,r1
+
+L_case_i:
+ bra L_case_v
+ mov.l @r2,r0
+
+L_case_q:
+#ifdef __LITTLE_ENDIAN__
+#else
+ add #3,r2
+#endif
+ bra L_case_v
+ mov.b @r2,r0
+
+L_case_uq:
+#ifdef __LITTLE_ENDIAN__
+#else
+ add #3,r2
+#endif
+ mov.b @r2,r0
+ bra L_case_v
+ extu.b r0,r0
+
+L_case_h:
+#ifdef __LITTLE_ENDIAN__
+#else
+ add #2,r2
+#endif
+ bra L_case_v
+ mov.w @r2,r0
+
+L_case_uh:
+#ifdef __LITTLE_ENDIAN__
+#else
+ add #2,r2
+#endif
+ mov.w @r2,r0
+ extu.w r0,r0
+ /* fall through */
+
+L_case_v:
+#if defined(__SH4__)
+ add #64,r15
+#else
+ add #32,r15
+#endif
+ lds.l @r15+,pr
+ rts
+ mov.l @r15+,r14
+.LFE2:
+.ffi_closure_SYSV_end:
+ .size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV)
+
+ .section ".eh_frame","aw",@progbits
+__FRAME_BEGIN__:
+ .4byte .LECIE1-.LSCIE1 /* Length of Common Information Entry */
+.LSCIE1:
+ .4byte 0x0 /* CIE Identifier Tag */
+ .byte 0x1 /* CIE Version */
+ .byte 0x0 /* CIE Augmentation */
+ .byte 0x1 /* uleb128 0x1; CIE Code Alignment Factor */
+ .byte 0x7c /* sleb128 -4; CIE Data Alignment Factor */
+ .byte 0x11 /* CIE RA Column */
+ .byte 0xc /* DW_CFA_def_cfa */
+ .byte 0xf /* uleb128 0xf */
+ .byte 0x0 /* uleb128 0x0 */
+ .align 2
+.LECIE1:
+.LSFDE1:
+ .4byte .LEFDE1-.LASFDE1 /* FDE Length */
+.LASFDE1:
+ .4byte .LASFDE1-__FRAME_BEGIN__ /* FDE CIE offset */
+ .4byte .LFB1 /* FDE initial location */
+ .4byte .LFE1-.LFB1 /* FDE address range */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte .LCFI0-.LFB1
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .byte 0x4 /* uleb128 0x4 */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte .LCFI1-.LCFI0
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .byte 0x8 /* uleb128 0x4 */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte .LCFI2-.LCFI1
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .byte 0xc /* uleb128 0x4 */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte .LCFI3-.LCFI2
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .byte 0x10 /* uleb128 0x4 */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte .LCFI4-.LCFI3
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .byte 0x14 /* uleb128 0x4 */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte .LCFI5-.LCFI4
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .byte 0x18 /* uleb128 0x4 */
+ .byte 0x91 /* DW_CFA_offset, column 0x11 */
+ .byte 0x6 /* uleb128 0x6 */
+ .byte 0x8e /* DW_CFA_offset, column 0xe */
+ .byte 0x5 /* uleb128 0x5 */
+ .byte 0x8c /* DW_CFA_offset, column 0xc */
+ .byte 0x4 /* uleb128 0x4 */
+ .byte 0x8a /* DW_CFA_offset, column 0xa */
+ .byte 0x3 /* uleb128 0x3 */
+ .byte 0x89 /* DW_CFA_offset, column 0x9 */
+ .byte 0x2 /* uleb128 0x2 */
+ .byte 0x88 /* DW_CFA_offset, column 0x8 */
+ .byte 0x1 /* uleb128 0x1 */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte .LCFI6-.LCFI5
+ .byte 0xd /* DW_CFA_def_cfa_register */
+ .byte 0xe /* uleb128 0xe */
+ .align 2
+.LEFDE1:
+
+.LSFDE3:
+ .4byte .LEFDE3-.LASFDE3 /* FDE Length */
+.LASFDE3:
+ .4byte .LASFDE3-__FRAME_BEGIN__ /* FDE CIE offset */
+ .4byte .LFB2 /* FDE initial location */
+ .4byte .LFE2-.LFB2 /* FDE address range */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte .LCFI7-.LFB2
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .byte 0x4 /* uleb128 0x4 */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte .LCFI8-.LCFI7
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .byte 0x8 /* uleb128 0x8 */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte .LCFI9-.LCFI8
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+#if defined(__SH4__)
+ .byte 8+64 /* uleb128 8+64 */
+#else
+ .byte 8+32 /* uleb128 8+32 */
+#endif
+ .byte 0x91 /* DW_CFA_offset, column 0x11 */
+ .byte 0x2
+ .byte 0x8e /* DW_CFA_offset, column 0xe */
+ .byte 0x1
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte .LCFIA-.LCFI9
+ .byte 0xd /* DW_CFA_def_cfa_register */
+ .byte 0xe /* uleb128 0xe */
+ .align 2
+.LEFDE3: