summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthony Green <green@moxielogic.com>2013-03-16 07:46:38 -0400
committerAnthony Green <green@moxielogic.com>2013-03-16 07:46:38 -0400
commit2fb527a017a4943e176a489ff103231b86464b59 (patch)
tree4ee2a38cf74f561bb98d9fef2f22811b3a3630fa
parent211a9ebf4d1a9801e15e103566aed2b8c42790be (diff)
downloadlibffi-2fb527a017a4943e176a489ff103231b86464b59.tar.gz
Add Meta processor support
-rw-r--r--ChangeLog9
-rw-r--r--Makefile.am4
-rw-r--r--README8
-rw-r--r--configure.ac5
-rw-r--r--src/metag/ffi.c330
-rw-r--r--src/metag/ffitarget.h53
-rw-r--r--src/metag/sysv.S311
7 files changed, 719 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index 5e9e369..525e518 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,15 @@
* src/x86/ffi.c (ffi_prep_cif_machdep): Always align stack.
+2013-03-13 Markos Chandras <markos.chandras@imgtec.com>
+
+ * configure.ac: Add support for Imagination Technologies Meta.
+ * Makefile.am: Likewise.
+ * README: Add Imagination Technologies Meta details.
+ * src/metag/ffi.c: New.
+ * src/metag/ffitarget.h: Likewise.
+ * src/metag/sysv.S: Likewise.
+
2013-02-11 Anthony Green <green@moxielogic.com>
* configure.ac: Update release number to 3.0.12.
diff --git a/Makefile.am b/Makefile.am
index 8f1362a..cf5caa9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -38,6 +38,7 @@ EXTRA_DIST = LICENSE ChangeLog.v1 ChangeLog.libgcj configure.host \
src/frv/ffitarget.h src/dlmalloc.c src/tile/ffi.c \
src/tile/ffitarget.h src/tile/tile.S libtool-version \
src/xtensa/ffitarget.h src/xtensa/ffi.c src/xtensa/sysv.S \
+ src/metag/ffi.c src/metag/ffitarget.h src/metag/sysv.S \
ChangeLog.libffi m4/libtool.m4 m4/lt~obsolete.m4 \
m4/ltoptions.m4 m4/ltsugar.m4 m4/ltversion.m4 \
m4/ltversion.m4 src/arm/gentramp.sh src/debug.c msvcc.sh \
@@ -208,6 +209,9 @@ endif
if XTENSA
nodist_libffi_la_SOURCES += src/xtensa/sysv.S src/xtensa/ffi.c
endif
+if METAG
+nodist_libffi_la_SOURCES += src/metag/sysv.S src/metag/ffi.c
+endif
libffi_convenience_la_SOURCES = $(libffi_la_SOURCES)
nodist_libffi_convenience_la_SOURCES = $(nodist_libffi_la_SOURCES)
diff --git a/README b/README
index 82b2104..f1a68f2 100644
--- a/README
+++ b/README
@@ -1,7 +1,7 @@
Status
======
-libffi-3.0.12 was released on February 11, 2013. Check the libffi web
+libffi-3.0.13 was released on March 16, 2013. Check the libffi web
page for updates: <URL:http://sourceware.org/libffi/>.
@@ -63,6 +63,7 @@ tested:
| M68K | FreeMiNT | GCC |
| M68K | Linux | GCC |
| M68K | RTEMS | GCC |
+| Meta | Linux | GCC |
| MicroBlaze | Linux | GCC |
| MIPS | IRIX | GCC |
| MIPS | Linux | GCC |
@@ -162,6 +163,11 @@ History
See the ChangeLog files for details.
+3.0.13 Mar-16-13
+
+ Add Meta support.
+ Fix stack alignment bug on 32-bit x86.
+
3.0.12 Feb-11-13
Add Moxie support.
Add AArch64 support.
diff --git a/configure.ac b/configure.ac
index 428d938..99a2f22 100644
--- a/configure.ac
+++ b/configure.ac
@@ -199,6 +199,10 @@ case "$host" in
TARGET=MOXIE; TARGETDIR=moxie
;;
+ metag-*-*)
+ TARGET=METAG; TARGETDIR=metag
+ ;;
+
mips-sgi-irix5.* | mips-sgi-irix6.* | mips*-*-rtems*)
TARGET=MIPS; TARGETDIR=mips
;;
@@ -278,6 +282,7 @@ AM_CONDITIONAL(IA64, test x$TARGET = xIA64)
AM_CONDITIONAL(M32R, test x$TARGET = xM32R)
AM_CONDITIONAL(M68K, test x$TARGET = xM68K)
AM_CONDITIONAL(MICROBLAZE, test x$TARGET = xMICROBLAZE)
+AM_CONDITIONAL(METAG, test x$TARGET = xMETAG)
AM_CONDITIONAL(MOXIE, test x$TARGET = xMOXIE)
AM_CONDITIONAL(POWERPC, test x$TARGET = xPOWERPC)
AM_CONDITIONAL(POWERPC_AIX, test x$TARGET = xPOWERPC_AIX)
diff --git a/src/metag/ffi.c b/src/metag/ffi.c
new file mode 100644
index 0000000..46b383e
--- /dev/null
+++ b/src/metag/ffi.c
@@ -0,0 +1,330 @@
+/* ----------------------------------------------------------------------
+ ffi.c - Copyright (c) 2013 Imagination Technologies
+
+ Meta 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 SIMON POSNJAK 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 MIN(a,b) (((a) < (b)) ? (a) : (b))
+
+/*
+ * ffi_prep_args is called by the assembly routine once stack space has been
+ * allocated for the function's arguments
+ */
+
+unsigned int ffi_prep_args(char *stack, extended_cif *ecif)
+{
+ register unsigned int i;
+ register void **p_argv;
+ register char *argp;
+ register ffi_type **p_arg;
+
+ argp = stack;
+
+ /* Store return value */
+ if ( ecif->cif->flags == FFI_TYPE_STRUCT ) {
+ argp -= 4;
+ *(void **) argp = ecif->rvalue;
+ }
+
+ p_argv = ecif->avalue;
+
+ /* point to next location */
+ for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; (i != 0); i--, p_arg++, p_argv++)
+ {
+ size_t z;
+
+ /* Move argp to address of argument */
+ z = (*p_arg)->size;
+ argp -= z;
+
+ /* Align if necessary */
+ argp = (char *) ALIGN_DOWN(ALIGN_DOWN(argp, (*p_arg)->alignment), 4);
+
+ 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);
+ case FFI_TYPE_STRUCT:
+ memcpy(argp, *p_argv, (*p_arg)->size);
+ break;
+ default:
+ FFI_ASSERT(0);
+ }
+ } else if ( z == sizeof(int)) {
+ *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
+ } else {
+ memcpy(argp, *p_argv, z);
+ }
+ }
+
+ /* return the size of the arguments to be passed in registers,
+ padded to an 8 byte boundary to preserve stack alignment */
+ return ALIGN(MIN(stack - argp, 6*4), 8);
+}
+
+/* Perform machine dependent cif processing */
+ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
+{
+ ffi_type **ptr;
+ unsigned i, bytes = 0;
+
+ for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) {
+ if ((*ptr)->size == 0)
+ return FFI_BAD_TYPEDEF;
+
+ /* Perform a sanity check on the argument type, do this
+ check after the initialization. */
+ FFI_ASSERT_VALID_TYPE(*ptr);
+
+ /* Add any padding if necessary */
+ if (((*ptr)->alignment - 1) & bytes)
+ bytes = ALIGN(bytes, (*ptr)->alignment);
+
+ bytes += ALIGN((*ptr)->size, 4);
+ }
+
+ /* Ensure arg space is aligned to an 8-byte boundary */
+ bytes = ALIGN(bytes, 8);
+
+ /* Make space for the return structure pointer */
+ if (cif->rtype->type == FFI_TYPE_STRUCT) {
+ bytes += sizeof(void*);
+
+ /* Ensure stack is aligned to an 8-byte boundary */
+ bytes = ALIGN(bytes, 8);
+ }
+
+ cif->bytes = bytes;
+
+ /* Set the return type flag */
+ switch (cif->rtype->type) {
+ case FFI_TYPE_VOID:
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ cif->flags = (unsigned) cif->rtype->type;
+ break;
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT64:
+ cif->flags = (unsigned) FFI_TYPE_SINT64;
+ break;
+ case FFI_TYPE_STRUCT:
+ /* Meta can store return values which are <= 64 bits */
+ if (cif->rtype->size <= 4)
+ /* Returned to D0Re0 as 32-bit value */
+ cif->flags = (unsigned)FFI_TYPE_INT;
+ else if ((cif->rtype->size > 4) && (cif->rtype->size <= 8))
+ /* Returned valued is stored to D1Re0|R0Re0 */
+ cif->flags = (unsigned)FFI_TYPE_DOUBLE;
+ else
+ /* value stored in memory */
+ cif->flags = (unsigned)FFI_TYPE_STRUCT;
+ break;
+ default:
+ cif->flags = (unsigned)FFI_TYPE_INT;
+ break;
+ }
+ return FFI_OK;
+}
+
+extern void ffi_call_SYSV(void (*fn)(void), extended_cif *, unsigned, unsigned, double *);
+
+/*
+ * Exported in API. Entry point
+ * cif -> ffi_cif object
+ * fn -> function pointer
+ * rvalue -> pointer to return value
+ * avalue -> vector of void * pointers pointing to memory locations holding the
+ * arguments
+ */
+void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+{
+ extended_cif ecif;
+
+ int small_struct = (((cif->flags == FFI_TYPE_INT) || (cif->flags == FFI_TYPE_DOUBLE)) && (cif->rtype->type == FFI_TYPE_STRUCT));
+ ecif.cif = cif;
+ ecif.avalue = avalue;
+
+ double temp;
+
+ /*
+ * 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->flags == FFI_TYPE_STRUCT))
+ ecif.rvalue = alloca(cif->rtype->size);
+ else if (small_struct)
+ ecif.rvalue = &temp;
+ else
+ ecif.rvalue = rvalue;
+
+ switch (cif->abi) {
+ case FFI_SYSV:
+ ffi_call_SYSV(fn, &ecif, cif->bytes, cif->flags, ecif.rvalue);
+ break;
+ default:
+ FFI_ASSERT(0);
+ break;
+ }
+
+ if (small_struct)
+ memcpy (rvalue, &temp, cif->rtype->size);
+}
+
+/* private members */
+
+static void ffi_prep_incoming_args_SYSV (char *, void **, void **,
+ ffi_cif*, float *);
+
+void ffi_closure_SYSV (ffi_closure *);
+
+/* Do NOT change that without changing the FFI_TRAMPOLINE_SIZE */
+extern unsigned int ffi_metag_trampoline[10]; /* 10 instructions */
+
+/* end of private members */
+
+/*
+ * __tramp: trampoline memory location
+ * __fun: assembly routine
+ * __ctx: memory location for wrapper
+ *
+ * At this point, tramp[0] == __ctx !
+ */
+void ffi_init_trampoline(unsigned char *__tramp, unsigned int __fun, unsigned int __ctx) {
+ memcpy (__tramp, ffi_metag_trampoline, sizeof(ffi_metag_trampoline));
+ *(unsigned int*) &__tramp[40] = __ctx;
+ *(unsigned int*) &__tramp[44] = __fun;
+ /* This will flush the instruction cache */
+ __builtin_meta2_cachewd(&__tramp[0], 1);
+ __builtin_meta2_cachewd(&__tramp[47], 1);
+}
+
+
+
+/* the cif must already be prepared */
+
+ffi_status
+ffi_prep_closure_loc (ffi_closure *closure,
+ ffi_cif* cif,
+ void (*fun)(ffi_cif*,void*,void**,void*),
+ void *user_data,
+ void *codeloc)
+{
+ void (*closure_func)(ffi_closure*) = NULL;
+
+ if (cif->abi == FFI_SYSV)
+ closure_func = &ffi_closure_SYSV;
+ else
+ return FFI_BAD_ABI;
+
+ ffi_init_trampoline(
+ (unsigned char*)&closure->tramp[0],
+ (unsigned int)closure_func,
+ (unsigned int)codeloc);
+
+ closure->cif = cif;
+ closure->user_data = user_data;
+ closure->fun = fun;
+
+ return FFI_OK;
+}
+
+
+/* This function is jumped to by the trampoline */
+unsigned int ffi_closure_SYSV_inner (closure, respp, args, vfp_args)
+ ffi_closure *closure;
+ void **respp;
+ void *args;
+ void *vfp_args;
+{
+ ffi_cif *cif;
+ void **arg_area;
+
+ cif = closure->cif;
+ arg_area = (void**) alloca (cif->nargs * sizeof (void*));
+
+ /*
+ * This call will initialize ARG_AREA, such that each
+ * element in that array points to the corresponding
+ * value on the stack; and if the function returns
+ * a structure, it will re-set RESP to point to the
+ * structure return address.
+ */
+ ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif, vfp_args);
+
+ (closure->fun) ( cif, *respp, arg_area, closure->user_data);
+
+ return cif->flags;
+}
+
+static void ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
+ void **avalue, ffi_cif *cif,
+ float *vfp_stack)
+{
+ register unsigned int i;
+ register void **p_argv;
+ register char *argp;
+ register ffi_type **p_arg;
+
+ /* stack points to original arguments */
+ argp = stack;
+
+ /* Store return value */
+ if ( cif->flags == FFI_TYPE_STRUCT ) {
+ argp -= 4;
+ *rvalue = *(void **) argp;
+ }
+
+ p_argv = avalue;
+
+ for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) {
+ size_t z;
+ size_t alignment;
+
+ alignment = (*p_arg)->alignment;
+ if (alignment < 4)
+ alignment = 4;
+ if ((alignment - 1) & (unsigned)argp)
+ argp = (char *) ALIGN(argp, alignment);
+
+ z = (*p_arg)->size;
+ *p_argv = (void*) argp;
+ p_argv++;
+ argp -= z;
+ }
+ return;
+}
diff --git a/src/metag/ffitarget.h b/src/metag/ffitarget.h
new file mode 100644
index 0000000..7b9dbeb
--- /dev/null
+++ b/src/metag/ffitarget.h
@@ -0,0 +1,53 @@
+/* -----------------------------------------------------------------*-C-*-
+ ffitarget.h - Copyright (c) 2013 Imagination Technologies Ltd.
+ Target configuration macros for Meta
+
+ 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 AUTHORS OR COPYRIGHT
+ HOLDERS 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_H
+#error "Please do not include ffitarget.h directly into your source. Use ffi.h instead."
+#endif
+
+#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 1
+#define FFI_TRAMPOLINE_SIZE 48
+#define FFI_NATIVE_RAW_API 0
+
+#endif
+
diff --git a/src/metag/sysv.S b/src/metag/sysv.S
new file mode 100644
index 0000000..b4b2a3b
--- /dev/null
+++ b/src/metag/sysv.S
@@ -0,0 +1,311 @@
+/* -----------------------------------------------------------------------
+ sysv.S - Copyright (c) 2013 Imagination Technologies Ltd.
+
+ Meta 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 AUTHORS OR COPYRIGHT
+ HOLDERS 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
+
+#ifdef __ELF__
+#define LSYM(x) .x
+#else
+#define LSYM(x) x
+#endif
+
+.macro call_reg x=
+ .text
+ .balign 4
+ mov D1RtP, \x
+ swap D1RtP, PC
+.endm
+
+! Save register arguments
+.macro SAVE_ARGS
+ .text
+ .balign 4
+ setl [A0StP++], D0Ar6, D1Ar5
+ setl [A0StP++], D0Ar4, D1Ar3
+ setl [A0StP++], D0Ar2, D1Ar1
+.endm
+
+! Save retrun, frame pointer and other regs
+.macro SAVE_REGS regs=
+ .text
+ .balign 4
+ setl [A0StP++], D0FrT, D1RtP
+ ! Needs to be a pair of regs
+ .ifnc "\regs",""
+ setl [A0StP++], \regs
+ .endif
+.endm
+
+! Declare a global function
+.macro METAG_FUNC_START name
+ .text
+ .balign 4
+ ENTRY(\name)
+.endm
+
+! Return registers from the stack. Reverse SAVE_REGS operation
+.macro RET_REGS regs=, cond=
+ .ifnc "\regs", ""
+ getl \regs, [--A0StP]
+ .endif
+ getl D0FrT, D1RtP, [--A0StP]
+.endm
+
+! Return arguments
+.macro RET_ARGS
+ getl D0Ar2, D1Ar1, [--A0StP]
+ getl D0Ar4, D1Ar3, [--A0StP]
+ getl D0Ar6, D1Ar5, [--A0StP]
+.endm
+
+
+ ! D1Ar1: fn
+ ! D0Ar2: &ecif
+ ! D1Ar3: cif->bytes
+ ! D0Ar4: fig->flags
+ ! D1Ar5: ecif.rvalue
+
+ ! This assumes we are using GNU as
+METAG_FUNC_START ffi_call_SYSV
+ ! Save argument registers
+
+ SAVE_ARGS
+
+ ! new frame
+ mov D0FrT, A0FrP
+ add A0FrP, A0StP, #0
+
+ ! Preserve the old frame pointer
+ SAVE_REGS "D1.5, D0.5"
+
+ ! Make room for new args. cifs->bytes is the total space for input
+ ! and return arguments
+
+ add A0StP, A0StP, D1Ar3
+
+ ! Preserve cifs->bytes & fn
+ mov D0.5, D1Ar3
+ mov D1.5, D1Ar1
+
+ ! Place all of the ffi_prep_args in position
+ mov D1Ar1, A0StP
+
+ ! Call ffi_prep_args(stack, &ecif)
+#ifdef __PIC__
+ callr D1RtP, CNAME(ffi_prep_args@PLT)
+#else
+ callr D1RtP, CNAME(ffi_prep_args)
+#endif
+
+ ! Restore fn pointer
+
+ ! The foreign stack should look like this
+ ! XXXXX XXXXXX <--- stack pointer
+ ! FnArgN rvalue
+ ! FnArgN+2 FnArgN+1
+ ! FnArgN+4 FnArgN+3
+ ! ....
+ !
+
+ ! A0StP now points to the first (or return) argument + 4
+
+ ! Preserve cif->bytes
+ getl D0Ar2, D1Ar1, [--A0StP]
+ getl D0Ar4, D1Ar3, [--A0StP]
+ getl D0Ar6, D1Ar5, [--A0StP]
+
+ ! Place A0StP to the first argument again
+ add A0StP, A0StP, #24 ! That's because we loaded 6 regs x 4 byte each
+
+ ! A0FrP points to the initial stack without the reserved space for the
+ ! cifs->bytes, whilst A0StP points to the stack after the space allocation
+
+ ! fn was the first argument of ffi_call_SYSV.
+ ! The stack at this point looks like this:
+ !
+ ! A0StP(on entry to _SYSV) -> Arg6 Arg5 | low
+ ! Arg4 Arg3 |
+ ! Arg2 Arg1 |
+ ! A0FrP ----> D0FrtP D1RtP |
+ ! D1.5 D0.5 |
+ ! A0StP(bf prep_args) -> FnArgn FnArgn-1 |
+ ! FnArgn-2FnArgn-3 |
+ ! ................ | <= cifs->bytes
+ ! FnArg4 FnArg3 |
+ ! A0StP (prv_A0StP+cifs->bytes) FnArg2 FnArg1 | high
+ !
+ ! fn was in Arg1 so it's located in in A0FrP+#-0xC
+ !
+
+ ! D0Re0 contains the size of arguments stored in registers
+ sub A0StP, A0StP, D0Re0
+
+ ! Arg1 is the function pointer for the foreign call. This has been
+ ! preserved in D1.5
+
+ ! Time to call (fn). Arguments should be like this:
+ ! Arg1-Arg6 are loaded to regs
+ ! The rest of the arguments are stored in stack pointed by A0StP
+
+ call_reg D1.5
+
+ ! Reset stack.
+
+ mov A0StP, A0FrP
+
+ ! Load Arg1 with the pointer to storage for the return type
+ ! This was stored in Arg5
+
+ getd D1Ar1, [A0FrP+#-20]
+
+ ! Load D0Ar2 with the return type code. This was stored in Arg4 (flags)
+
+ getd D0Ar2, [A0FrP+#-16]
+
+ ! We are ready to start processing the return value
+ ! D0Re0 (and D1Re0) hold the return value
+
+ ! If the return value is NULL, assume no return value
+ cmp D1Ar1, #0
+ beq LSYM(Lepilogue)
+
+ ! return INT
+ cmp D0Ar2, #FFI_TYPE_INT
+ ! Sadly, there is no setd{cc} instruction so we need to workaround that
+ bne .INT64
+ setd [D1Ar1], D0Re0
+ b LSYM(Lepilogue)
+
+ ! return INT64
+.INT64:
+ cmp D0Ar2, #FFI_TYPE_SINT64
+ setleq [D1Ar1], D0Re0, D1Re0
+
+ ! return DOUBLE
+ cmp D0Ar2, #FFI_TYPE_DOUBLE
+ setl [D1AR1++], D0Re0, D1Re0
+
+LSYM(Lepilogue):
+ ! At this point, the stack pointer points right after the argument
+ ! saved area. We need to restore 4 regs, therefore we need to move
+ ! 16 bytes ahead.
+ add A0StP, A0StP, #16
+ RET_REGS "D1.5, D0.5"
+ RET_ARGS
+ getd D0Re0, [A0StP]
+ mov A0FrP, D0FrT
+ swap D1RtP, PC
+
+.ffi_call_SYSV_end:
+ .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
+
+
+/*
+ (called by ffi_metag_trampoline)
+ void ffi_closure_SYSV (ffi_closure*)
+
+ (called by ffi_closure_SYSV)
+ unsigned int FFI_HIDDEN
+ ffi_closure_SYSV_inner (closure,respp, args)
+ ffi_closure *closure;
+ void **respp;
+ void *args;
+*/
+
+METAG_FUNC_START ffi_closure_SYSV
+ ! We assume that D1Ar1 holds the address of the
+ ! ffi_closure struct. We will use that to fetch the
+ ! arguments. The stack pointer points to an empty space
+ ! and it is ready to store more data.
+
+ ! D1Ar1 is ready
+ ! Allocate stack space for return value
+ add A0StP, A0StP, #8
+ ! Store it to D0Ar2
+ sub D0Ar2, A0StP, #8
+
+ sub D1Ar3, A0FrP, #4
+
+ ! D1Ar3 contains the address of the original D1Ar1 argument
+ ! We need to subtract #4 later on
+
+ ! Preverve D0Ar2
+ mov D0.5, D0Ar2
+
+#ifdef __PIC__
+ callr D1RtP, CNAME(ffi_closure_SYSV_inner@PLT)
+#else
+ callr D1RtP, CNAME(ffi_closure_SYSV_inner)
+#endif
+
+ ! Check the return value and store it to D0.5
+ cmp D0Re0, #FFI_TYPE_INT
+ beq .Lretint
+ cmp D0Re0, #FFI_TYPE_DOUBLE
+ beq .Lretdouble
+.Lclosure_epilogue:
+ sub A0StP, A0StP, #8
+ RET_REGS "D1.5, D0.5"
+ RET_ARGS
+ swap D1RtP, PC
+
+.Lretint:
+ setd [D0.5], D0Re0
+ b .Lclosure_epilogue
+.Lretdouble:
+ setl [D0.5++], D0Re0, D1Re0
+ b .Lclosure_epilogue
+.ffi_closure_SYSV_end:
+.size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV)
+
+
+ENTRY(ffi_metag_trampoline)
+ SAVE_ARGS
+ ! New frame
+ mov A0FrP, A0StP
+ SAVE_REGS "D1.5, D0.5"
+ mov D0.5, PC
+ ! Load D1Ar1 the value of ffi_metag_trampoline
+ getd D1Ar1, [D0.5 + #8]
+ ! Jump to ffi_closure_SYSV
+ getd PC, [D0.5 + #12]