summaryrefslogtreecommitdiff
path: root/libffi/src/arm
diff options
context:
space:
mode:
Diffstat (limited to 'libffi/src/arm')
-rw-r--r--libffi/src/arm/ffi.c175
-rw-r--r--libffi/src/arm/ffitarget.h47
-rw-r--r--libffi/src/arm/sysv.S127
3 files changed, 349 insertions, 0 deletions
diff --git a/libffi/src/arm/ffi.c b/libffi/src/arm/ffi.c
new file mode 100644
index 0000000..37e3838
--- /dev/null
+++ b/libffi/src/arm/ffi.c
@@ -0,0 +1,175 @@
+/* -----------------------------------------------------------------------
+ ffi.c - Copyright (c) 1998 Red Hat, Inc.
+
+ ARM 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>
+
+/* 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 void **p_argv;
+ register char *argp;
+ register ffi_type **p_arg;
+
+ argp = stack;
+
+ if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) {
+ *(void **) argp = ecif->rvalue;
+ argp += 4;
+ }
+
+ p_argv = ecif->avalue;
+
+ for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
+ (i != 0);
+ i--, p_arg++)
+ {
+ size_t z;
+
+ /* Align if necessary */
+ if (((*p_arg)->alignment - 1) & (unsigned) argp) {
+ argp = (char *) ALIGN(argp, (*p_arg)->alignment);
+ }
+
+ z = (*p_arg)->size;
+ if (z < sizeof(int))
+ {
+ 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);
+ }
+ }
+ else if (z == sizeof(int))
+ {
+ *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
+ }
+ else
+ {
+ memcpy(argp, *p_argv, z);
+ }
+ p_argv++;
+ argp += z;
+ }
+
+ return;
+}
+
+/* Perform machine dependent cif processing */
+ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
+{
+ /* Set the return type flag */
+ switch (cif->rtype->type)
+ {
+ case FFI_TYPE_VOID:
+ case FFI_TYPE_STRUCT:
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ cif->flags = (unsigned) cif->rtype->type;
+ break;
+
+ default:
+ cif->flags = FFI_TYPE_INT;
+ 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;
+ }
+}
diff --git a/libffi/src/arm/ffitarget.h b/libffi/src/arm/ffitarget.h
new file mode 100644
index 0000000..96f4bb2
--- /dev/null
+++ b/libffi/src/arm/ffitarget.h
@@ -0,0 +1,47 @@
+/* -----------------------------------------------------------------*-C-*-
+ ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
+ Target configuration macros for ARM.
+
+ 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
+
+#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
+
+/* ---- Definitions for closures ----------------------------------------- */
+
+#define FFI_CLOSURES 0
+#define FFI_NATIVE_RAW_API 0
+
+#endif
+
diff --git a/libffi/src/arm/sysv.S b/libffi/src/arm/sysv.S
new file mode 100644
index 0000000..0e41861
--- /dev/null
+++ b/libffi/src/arm/sysv.S
@@ -0,0 +1,127 @@
+/* -----------------------------------------------------------------------
+ sysv.S - Copyright (c) 1998 Red Hat, Inc.
+
+ ARM 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
+#ifdef __USER_LABEL_PREFIX__
+#define CONCAT1(a, b) CONCAT2(a, b)
+#define CONCAT2(a, b) a ## b
+
+/* Use the right prefix for global labels. */
+#define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
+#else
+#define CNAME(x) x
+#endif
+#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x):
+#endif
+
+.text
+
+ # a1: ffi_prep_args
+ # a2: &ecif
+ # a3: cif->bytes
+ # a4: fig->flags
+ # sp+0: ecif.rvalue
+ # sp+4: fn
+
+ # This assumes we are using gas.
+ENTRY(ffi_call_SYSV)
+ # Save registers
+ stmfd sp!, {a1-a4, fp, lr}
+ mov fp, sp
+
+ # Make room for all of the new args.
+ sub sp, fp, a3
+
+ # Place all of the ffi_prep_args in position
+ mov ip, a1
+ mov a1, sp
+ # a2 already set
+
+ # And call
+ mov lr, pc
+ mov pc, ip
+
+ # move first 4 parameters in registers
+ ldr a1, [sp, #0]
+ ldr a2, [sp, #4]
+ ldr a3, [sp, #8]
+ ldr a4, [sp, #12]
+
+ # and adjust stack
+ ldr ip, [fp, #8]
+ cmp ip, #16
+ movge ip, #16
+ add sp, sp, ip
+
+ # call function
+ mov lr, pc
+ ldr pc, [fp, #28]
+
+ # Remove the space we pushed for the args
+ mov sp, fp
+
+ # Load a3 with the pointer to storage for the return value
+ ldr a3, [sp, #24]
+
+ # Load a4 with the return type code
+ ldr a4, [sp, #12]
+
+ # If the return value pointer is NULL, assume no return value.
+ cmp a3, #0
+ beq epilogue
+
+# return INT
+ cmp a4, #FFI_TYPE_INT
+ streq a1, [a3]
+ beq epilogue
+
+# return FLOAT
+ cmp a4, #FFI_TYPE_FLOAT
+#ifdef __SOFTFP__
+ streq a1, [a3]
+#else
+ stfeqs f0, [a3]
+#endif
+ beq epilogue
+
+# return DOUBLE or LONGDOUBLE
+ cmp a4, #FFI_TYPE_DOUBLE
+#ifdef __SOFTFP__
+ stmeqia a3, {a1, a2}
+#else
+ stfeqd f0, [a3]
+#endif
+
+epilogue:
+ ldmfd sp!, {a1-a4, fp, pc}
+
+.ffi_call_SYSV_end:
+ .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
+