Parcourir la source

libffi: Add libffi 3.3-rc0

libffi 3.3-rc0 has much better RISC-V suppor then our single patch. Use
the RC release instead of a single patch.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Alistair Francis il y a 5 ans
Parent
commit
0237fef85b

+ 0 - 1983
recipes-support/libffi/files/0001-Add-riscv-support.patch

@@ -1,1983 +0,0 @@
-From ca569f8a61e1c127166862f32548a7671009b289 Mon Sep 17 00:00:00 2001
-From: Khem Raj <raj.khem@gmail.com>
-Date: Wed, 4 Oct 2017 11:08:06 -0700
-Subject: [PATCH] Add riscv support
-
-Signed-off-by: Khem Raj <raj.khem@gmail.com>
----
- Makefile.am                   |   4 +
- README.md                     |  23 ++
- configure.ac                  |   5 +-
- misc/parse_tests.py           |  50 +++
- misc/riscv-sim.exp            |   6 +
- misc/run_test.sh              |   3 +
- src/prep_cif.c                |   5 +-
- src/riscv/asm.py              |  37 ++
- src/riscv/ffi.c               | 746 ++++++++++++++++++++++++++++++++++++++++
- src/riscv/ffitarget.h         | 120 +++++++
- src/riscv/sysv.S              | 782 ++++++++++++++++++++++++++++++++++++++++++
- testsuite/Makefile.am         |   2 +-
- testsuite/libffi.call/many3.c |  59 ++++
- 13 files changed, 1837 insertions(+), 5 deletions(-)
- create mode 100644 README.md
- create mode 100644 misc/parse_tests.py
- create mode 100644 misc/riscv-sim.exp
- create mode 100644 misc/run_test.sh
- create mode 100644 src/riscv/asm.py
- create mode 100644 src/riscv/ffi.c
- create mode 100644 src/riscv/ffitarget.h
- create mode 100644 src/riscv/sysv.S
- create mode 100644 testsuite/libffi.call/many3.c
-
-Index: libffi-3.2.1/Makefile.am
-===================================================================
---- libffi-3.2.1.orig/Makefile.am
-+++ libffi-3.2.1/Makefile.am
-@@ -32,6 +32,7 @@ EXTRA_DIST = LICENSE ChangeLog.v1 Change
- 	 src/powerpc/asm.h src/powerpc/aix.S src/powerpc/darwin.S	\
- 	 src/powerpc/aix_closure.S src/powerpc/darwin_closure.S		\
- 	 src/powerpc/ffi_darwin.c src/powerpc/ffitarget.h		\
-+	 src/riscv/ffi.c src/riscv/ffitarget.h src/riscv/sysv.S		\
- 	 src/s390/ffi.c src/s390/sysv.S src/s390/ffitarget.h		\
- 	 src/sh/ffi.c src/sh/sysv.S src/sh/ffitarget.h src/sh64/ffi.c	\
- 	 src/sh64/sysv.S src/sh64/ffitarget.h src/sparc/v8.S		\
-@@ -122,6 +123,9 @@ endif
- if MIPS
- nodist_libffi_la_SOURCES += src/mips/ffi.c src/mips/o32.S src/mips/n32.S
- endif
-+if RISCV
-+nodist_libffi_la_SOURCES += src/riscv/ffi.c src/riscv/sysv.S
-+endif
- if BFIN
- nodist_libffi_la_SOURCES += src/bfin/ffi.c src/bfin/sysv.S
- endif
-Index: libffi-3.2.1/README.md
-===================================================================
---- /dev/null
-+++ libffi-3.2.1/README.md
-@@ -0,0 +1,23 @@
-+RISC-V Port of libffi
-+=====================
-+
-+Compile and run:
-+
-+```
-+./configure --host=riscv64-unknown-elf
-+make
-+```
-+
-+Run tests in Spike:
-+
-+```
-+make check RUNTESTFLAGS="--target_board=riscv-sim --all"
-+```
-+
-+Run an individual test:
-+
-+Go to `testsuite/libffi.call` directory and run:
-+
-+```
-+../../misc/run_test.sh <test_name.c>
-+```
-Index: libffi-3.2.1/configure.ac
-===================================================================
---- libffi-3.2.1.orig/configure.ac
-+++ libffi-3.2.1/configure.ac
-@@ -260,7 +260,9 @@ case "$host" in
-   powerpc*-*-rtems*)
- 	TARGET=POWERPC; TARGETDIR=powerpc
- 	;;
--
-+  riscv*-*-*)
-+	TARGET=RISCV; TARGETDIR=riscv
-+	;;
-   s390-*-* | s390x-*-*)
- 	TARGET=S390; TARGETDIR=s390
- 	;;
-@@ -298,6 +300,7 @@ if test $TARGETDIR = unknown; then
- fi
- 
- AM_CONDITIONAL(MIPS, test x$TARGET = xMIPS)
-+AM_CONDITIONAL(RISCV, test x$TARGET = xRISCV)
- AM_CONDITIONAL(BFIN, test x$TARGET = xBFIN)
- AM_CONDITIONAL(SPARC, test x$TARGET = xSPARC)
- AM_CONDITIONAL(X86, test x$TARGET = xX86)
-Index: libffi-3.2.1/misc/parse_tests.py
-===================================================================
---- /dev/null
-+++ libffi-3.2.1/misc/parse_tests.py
-@@ -0,0 +1,50 @@
-+#!/bin/python
-+
-+import sys
-+
-+def print_help():
-+    print "Usage: python " + sys.argv[0] + " <test result file>"
-+
-+if len(sys.argv) != 2:
-+    exit(1)
-+
-+summary = ""
-+passed = []
-+failed = []
-+fname = sys.argv[1]
-+f = open(fname, 'r')
-+for l in f.readlines():
-+    if l.startswith("PASS"):
-+        z = l.split()
-+        if not z[1] in passed: 
-+            passed.append(z[1])
-+    elif l.startswith("FAIL"):
-+        z = l.split()
-+        if not z[1] in failed: 
-+            failed.append(z[1])
-+    elif l.startswith("#"):
-+        summary += l
-+
-+i = 0
-+while i < len(passed):
-+    if passed[i] in failed:
-+        del passed[i]
-+        continue
-+    i += 1
-+
-+p_num = len(passed)
-+f_num = len(failed)
-+total = p_num + f_num
-+
-+print "---TEST FILES PASSED---"
-+for t in passed: print t
-+print
-+print "---TEST FILES FAILED---"
-+for t in failed: print t
-+print
-+print "------TEST SUMMARY------"
-+print "Passed: " + str(p_num) + " (" + str(round(float(p_num)/total*100, 1)) + "%)"
-+print "Failed: " + str(f_num) + " (" + str(round(float(f_num)/total*100, 1)) + "%)"
-+print "Total:  " + str(total)
-+print 
-+print summary
-Index: libffi-3.2.1/misc/riscv-sim.exp
-===================================================================
---- /dev/null
-+++ libffi-3.2.1/misc/riscv-sim.exp
-@@ -0,0 +1,6 @@
-+load_generic_config "sim"
-+set_board_info sim "spike pk"
-+set_board_info compiler "[find_gcc]"
-+set_board_info ldflags "-static"
-+set_board_info gdb,nosignals 1
-+set_board_info is_simulator 1
-Index: libffi-3.2.1/misc/run_test.sh
-===================================================================
---- /dev/null
-+++ libffi-3.2.1/misc/run_test.sh
-@@ -0,0 +1,3 @@
-+#/bin/bash
-+riscv64-unknown-elf-gcc -g -I../../riscv64-unknown-elf/include -I../../riscv64-unknown-elf -L../../riscv64-unknown-elf/.libs/ $1 -lffi 
-+spike pk a.out
-Index: libffi-3.2.1/src/prep_cif.c
-===================================================================
---- libffi-3.2.1.orig/src/prep_cif.c
-+++ libffi-3.2.1/src/prep_cif.c
-@@ -143,8 +143,8 @@ ffi_status FFI_HIDDEN ffi_prep_cif_core(
-   /* Perform a sanity check on the return type */
-   FFI_ASSERT_VALID_TYPE(cif->rtype);
- 
--  /* x86, x86-64 and s390 stack space allocation is handled in prep_machdep. */
--#if !defined FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION
-+  /* x86, x86-64, s390, and riscv stack space allocation is handled in prep_machdep. */
-+#if !defined M68K && !defined X86_ANY && !defined S390 && !defined PA && (defined __riscv && __riscv_xlen != 64)
-   /* Make space for the return structure pointer */
-   if (cif->rtype->type == FFI_TYPE_STRUCT
- #ifdef SPARC
-@@ -205,7 +205,6 @@ ffi_status FFI_HIDDEN ffi_prep_cif_core(
- 	  if (bytes <= 6*4 && bytes + STACK_ARG_SIZE((*ptr)->size) > 6*4)
- 	    bytes = 6*4;
- #endif
--
- 	  bytes += STACK_ARG_SIZE((*ptr)->size);
- 	}
- #endif
-Index: libffi-3.2.1/src/riscv/asm.py
-===================================================================
---- /dev/null
-+++ libffi-3.2.1/src/riscv/asm.py
-@@ -0,0 +1,37 @@
-+#!/bin/python
-+
-+def set_args_64(i):
-+    return """
-+####################
-+## SET ARGUMENT """ + str(i) + """ ##
-+####################
-+
-+set_arg""" + str(i) + """:
-+    srli    t1, t0, FFI_FLAG_BITS_X""" + str(i) + """ # Shift to get the bits for this argument
-+    andi    t1, t1, 3               # Mask out the bits for this argument
-+    
-+    # when its zero, it means its just a word-sized int/ptr
-+    bne     t1, zero, set_arg""" + str(i) + """_float 
-+    REG_L   a""" + str(i) + """, FFI_SIZEOF_ARG_X""" + str(i) + """(sp) # load argument
-+    j       set_arg""" + str(i+1) + """
-+    
-+set_arg""" + str(i) + """_float:
-+    addi    t1, t1, -1
-+    
-+    # when its zero, it means its just a word-sized float
-+    bne     t1, zero, set_arg""" + str(i) + """_double
-+    flw     fa""" + str(i) + """, FFI_SIZEOF_ARG_X""" + str(i) + """(sp) # load argument
-+    j       set_arg""" + str(i+1) + """
-+    
-+set_arg""" + str(i) + """_double:
-+    # otherwise it must be a double we're dealing with
-+    fld     fa""" + str(i) + """, FFI_SIZEOF_ARG_X""" + str(i) + """(sp)
-+"""
-+
-+def gen64_setargs_string():
-+    setargs = ""
-+    for i in range(8):
-+        setargs += set_args_64(i)
-+    return setargs
-+
-+print gen64_setargs_string()
-Index: libffi-3.2.1/src/riscv/ffi.c
-===================================================================
---- /dev/null
-+++ libffi-3.2.1/src/riscv/ffi.c
-@@ -0,0 +1,746 @@
-+/* -----------------------------------------------------------------------
-+   ffi.c - Copyright (c) 2015 Michael Knyszek <mknyszek@berkeley.edu>
-+                         2015 Andrew Waterman <waterman@cs.berkeley.edu>
-+   Based on MIPS N32/64 port
-+   
-+   RISC-V 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.
-+   ----------------------------------------------------------------------- */
-+
-+#include <ffi.h>
-+#include <ffi_common.h>
-+
-+#include <stdlib.h>
-+#include <stdint.h>
-+
-+#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG)
-+
-+/* 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(char *stack, extended_cif *ecif, int bytes, int flags)
-+{
-+    int i;
-+    void **p_argv;
-+    char *argp, *cpy_struct;
-+    ffi_type **p_arg;
-+    
-+    argp = stack;
-+    cpy_struct = stack + ALIGN(bytes, 16);
-+
-+    memset(stack, 0, bytes);
-+
-+    if (ecif->cif->rstruct_flag != 0)
-+    {
-+        *(ffi_arg *) argp = (ffi_arg) ecif->rvalue;
-+        argp += sizeof(ffi_arg);
-+    }
-+    
-+    p_argv = ecif->avalue;
-+
-+    for (i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs; i++, p_arg++)
-+    {
-+        size_t z;
-+        unsigned int a;
-+
-+        /* Align if necessary. */
-+        a = (*p_arg)->alignment;
-+        if (a < sizeof(ffi_arg))
-+            a = sizeof(ffi_arg);
-+
-+        if ((a - 1) & (unsigned long) argp)
-+        {
-+            argp = (char *) ALIGN(argp, a);
-+        }
-+
-+        z = (*p_arg)->size;
-+        if (z <= sizeof(ffi_arg))
-+        {
-+            int type = (*p_arg)->type;
-+            z = sizeof(ffi_arg);
-+
-+            /* The size of a pointer depends on the ABI */
-+            if (type == FFI_TYPE_POINTER)
-+            #if defined(__riscv) && __riscv_xlen == 64
-+                type = FFI_TYPE_SINT64;
-+            #else
-+                type = FFI_TYPE_SINT32;
-+            #endif
-+            
-+            if (i < 8 && (ecif->cif->abi == FFI_RV32_SOFT_FLOAT || ecif->cif->abi == FFI_RV64_SOFT_FLOAT))
-+            {
-+                switch (type)
-+                {
-+                    case FFI_TYPE_FLOAT:
-+                        type = FFI_TYPE_UINT32;
-+                        break;
-+                    case FFI_TYPE_DOUBLE:
-+                        type = FFI_TYPE_UINT64;
-+                        break;
-+                    default:
-+                        break;
-+                }
-+            }
-+            
-+            switch (type)
-+            {
-+                case FFI_TYPE_SINT8:
-+                    *(ffi_arg *)argp = *(SINT8 *)(* p_argv);
-+                    break;
-+
-+                case FFI_TYPE_UINT8:
-+                    *(ffi_arg *)argp = *(UINT8 *)(* p_argv);
-+                    break;
-+
-+                case FFI_TYPE_SINT16:
-+                    *(ffi_arg *)argp = *(SINT16 *)(* p_argv);
-+                    break;
-+
-+                case FFI_TYPE_UINT16:
-+                    *(ffi_arg *)argp = *(UINT16 *)(* p_argv);
-+                    break;
-+
-+                case FFI_TYPE_SINT32:
-+                    *(ffi_arg *)argp = *(SINT32 *)(* p_argv);
-+                    break;
-+
-+                case FFI_TYPE_UINT32:
-+                    *(ffi_arg *)argp = *(UINT32 *)(* p_argv);
-+                    break;
-+                    
-+                case FFI_TYPE_SINT64:
-+                    *(ffi_arg *)argp = *(SINT64 *)(* p_argv);
-+                    break;
-+
-+                case FFI_TYPE_UINT64:
-+                    *(ffi_arg *)argp = *(UINT64 *)(* p_argv);
-+                    break;
-+
-+                /* This can only happen with 64bit slots. */
-+                case FFI_TYPE_FLOAT:
-+                    *(float *) argp = *(float *)(* p_argv);
-+                    break;
-+
-+                /* Handle structures. */
-+                default:
-+                    memcpy(argp, *p_argv, (*p_arg)->size);
-+                    break;
-+            }
-+        }
-+        else if (z <= 2*sizeof(ffi_arg))
-+        {
-+            /* Check if the data will fit within the register space.
-+               Handle it if it doesn't. */
-+            
-+            unsigned long end = (unsigned long) argp + z;
-+            unsigned long cap = (unsigned long) stack + bytes;
-+            
-+            if (end <= cap)
-+                memcpy(argp, *p_argv, z);
-+            else
-+            {
-+                unsigned long portion = cap - (unsigned long)argp;
-+                
-+                memcpy(argp, *p_argv, portion);
-+                argp = stack;
-+                z -= portion;
-+                memcpy(argp, (void*)((unsigned long)(*p_argv) + portion), z);
-+            }
-+        }
-+        else if(i < 8 && z > 2*sizeof(ffi_arg))
-+        {
-+            /* It's too big to pass in any registers or on the stack, 
-+               so we pass a pointer, and copy the struct to pass by value.
-+               But, we can't _just_ copy it onto the stack! We need to actually
-+               make sure it gets onto the "bottom" (really the top, high memory
-+               addresses) of the stack frame... */
-+            
-+            /* Update pointer to where our struct location on the stack is */
-+            cpy_struct -= ALIGN(z, a);
-+            
-+            memcpy(cpy_struct, *p_argv, z);
-+            
-+            /* Pass pointer in register */
-+            *(ffi_arg *)argp = (ffi_arg) cpy_struct;
-+            
-+            z = sizeof(ffi_arg);
-+        }
-+        else
-+        {
-+            /* Just some big struct, pass it by value by copying it onto
-+               the stack. */
-+            memcpy(argp, *p_argv, z);
-+        }
-+        
-+        p_argv++;
-+        argp += z;
-+    }
-+}
-+
-+/* This code traverses structure definitions 
-+   and generates the appropriate flags. */
-+
-+static unsigned calc_riscv_struct_flags(int soft_float, ffi_type *arg, size_t size, unsigned *loc, unsigned *arg_reg)
-+{
-+    unsigned flags = 0;
-+    unsigned index = 0;
-+    ffi_type *e;
-+    
-+    if (soft_float)
-+        return 0;
-+    
-+    /* The struct is too big to pass on the stack, so we pass it by reference */
-+    if (size > 2 * FFI_SIZEOF_ARG)
-+    {
-+        (*arg_reg)++;
-+        return 0;
-+    }
-+    
-+    while ((e = arg->elements[index]))
-+    {
-+        /* Align this object. */
-+        *loc = ALIGN(*loc, e->alignment);
-+        
-+        if (e->type == FFI_TYPE_DOUBLE)
-+        {
-+            /* Already aligned to FFI_SIZEOF_ARG. */
-+            *arg_reg = *loc / FFI_SIZEOF_ARG;
-+            
-+            if (*arg_reg > 7)
-+                break;
-+            
-+            flags += (FFI_TYPE_DOUBLE << (*arg_reg * FFI_FLAG_BITS));
-+            *loc += e->size;
-+        }
-+        else
-+            *loc += e->size;
-+        
-+        index++;
-+    }
-+    
-+    /* Next Argument register at alignment of FFI_SIZEOF_ARG. */
-+    *arg_reg = ALIGN(*loc, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
-+    
-+    return flags;
-+}
-+
-+/* The flags output of this routine should match the various struct cases
-+   described in ffitarget.h */
-+
-+static unsigned calc_riscv_return_struct_flags(int soft_float, ffi_type *arg)
-+{
-+    unsigned flags = 0;
-+    unsigned small = FFI_TYPE_SMALLSTRUCT;
-+    ffi_type *e;
-+    
-+    /* Returning structures under n32 is a tricky thing.
-+       A struct with only one or two floating point fields
-+       is returned in $f0 (and $f2 if necessary). Any other
-+       struct results at most 128 bits are returned in $2
-+       (the first 64 bits) and $3 (remainder, if necessary).
-+       Larger structs are handled normally. */
-+    
-+    if (arg->size > 2 * FFI_SIZEOF_ARG)
-+        return 0;
-+    
-+    if (arg->size > 8)
-+        small = FFI_TYPE_SMALLSTRUCT2;
-+    
-+    e = arg->elements[0];
-+    if (e->type == FFI_TYPE_DOUBLE)
-+        flags = FFI_TYPE_DOUBLE;
-+    else if (e->type == FFI_TYPE_FLOAT)
-+        flags = FFI_TYPE_FLOAT;
-+    
-+    if (flags && (e = arg->elements[1]))
-+    {
-+        if (e->type == FFI_TYPE_DOUBLE)
-+            flags += FFI_TYPE_DOUBLE << FFI_FLAG_BITS;
-+        else if (e->type == FFI_TYPE_FLOAT)
-+            flags += FFI_TYPE_FLOAT << FFI_FLAG_BITS;
-+        else
-+            return small;
-+        
-+        if (flags && (arg->elements[2]))
-+        {
-+            /* There are three arguments and the first two are
-+               floats! This must be passed the old way. */
-+            return small;
-+        }
-+        
-+        if (soft_float)
-+            flags += FFI_TYPE_STRUCT_SOFT;
-+    }
-+    else if (!flags)
-+        return small;
-+    
-+    return flags;
-+}
-+
-+/* Generate the flags word for processing arguments and 
-+   putting them into their proper registers in the 
-+   assembly routine. */
-+
-+void ffi_prep_cif_machdep_flags(ffi_cif *cif, unsigned int isvariadic, unsigned int nfixedargs)
-+{
-+    int type;
-+    unsigned arg_reg = 0;
-+    unsigned loc = 0;
-+    unsigned count = (cif->nargs < 8) ? cif->nargs : 8;
-+    unsigned index = 0;
-+    
-+    unsigned int struct_flags = 0;
-+    int soft_float = cif->abi == FFI_RV64_SOFT_FLOAT || cif->abi == FFI_RV32_SOFT_FLOAT;;
-+    
-+    cif->flags = 0;
-+    
-+    if (cif->rtype->type == FFI_TYPE_STRUCT)
-+    {
-+        struct_flags = calc_riscv_return_struct_flags(soft_float, cif->rtype);
-+        if (struct_flags == 0)
-+        {
-+            /* This means that the structure is being passed as
-+               a hidden argument */
-+            arg_reg = 1;
-+            count = (cif->nargs < 7) ? cif->nargs : 7;
-+            cif->rstruct_flag = !0;
-+        }
-+        else
-+            cif->rstruct_flag = 0;
-+    }
-+    else
-+        cif->rstruct_flag = 0;
-+    
-+    /* Set the first 8 existing argument types in the flag bit string
-+     * 
-+     * We only describe the two argument types we care about:
-+     * - Whether or not its a float/double
-+     * - Whether or not its a struct
-+     * 
-+     * This is is two bits per argument accounting for the first 16 bits
-+     * of cif->flags.
-+     * 
-+     * The last 16 bits are just used to describe the return type
-+     * 
-+     * FFI_FLAG_BITS = 2
-+     */
-+    
-+    while (count-- > 0 && arg_reg < 8)
-+    {
-+        type = (cif->arg_types)[index]->type;
-+        
-+        /* Handle float argument types for soft float case */
-+        if (soft_float || (isvariadic && arg_reg >= nfixedargs))
-+        {
-+            switch (type)
-+            {
-+                case FFI_TYPE_FLOAT:
-+                    type = FFI_TYPE_UINT32;
-+                    break;
-+                case FFI_TYPE_DOUBLE:
-+                    type = FFI_TYPE_UINT64;
-+                    break;
-+                default:
-+                    break;
-+            }
-+        }
-+        switch (type)
-+        {
-+            case FFI_TYPE_FLOAT:  /* = 2 = 0b10 */
-+            case FFI_TYPE_DOUBLE: /* = 3 = 0b11 */
-+                cif->flags += ((cif->arg_types)[index]->type << (arg_reg * FFI_FLAG_BITS));
-+                arg_reg++;
-+                break;
-+            case FFI_TYPE_STRUCT:
-+                loc = arg_reg * FFI_SIZEOF_ARG;
-+                cif->flags += calc_riscv_struct_flags(soft_float, (cif->arg_types)[index], (cif->arg_types)[index]->size, &loc, &arg_reg);
-+                break;
-+            default:
-+                arg_reg++;
-+                break;
-+        }
-+        index++;
-+    }
-+    
-+    /* Set the return type flag */
-+    
-+    type = cif->rtype->type;
-+    
-+    /* Handle float return types for soft float case */
-+    if (soft_float)
-+    {
-+        switch (type)
-+        {
-+            case FFI_TYPE_FLOAT:
-+                type = FFI_TYPE_UINT32;
-+                break;
-+            case FFI_TYPE_DOUBLE:
-+                type = FFI_TYPE_UINT64;
-+                break;
-+            default:
-+                break;
-+        }
-+    }
-+    
-+    switch (type)
-+    {
-+        case FFI_TYPE_STRUCT:
-+            if (struct_flags != 0)
-+            {
-+                /* The structure is returned via some tricky mechanism */
-+                cif->flags += FFI_TYPE_STRUCT << (FFI_FLAG_BITS * 8);
-+                cif->flags += struct_flags << (4 + (FFI_FLAG_BITS * 8));
-+            }
-+            /* else the structure is returned through a hidden
-+               first argument. Do nothing, 'cause FFI_TYPE_VOID is 0 */
-+            break;
-+        case FFI_TYPE_VOID:
-+            /* Do nothing, 'cause FFI_TYPE_VOID is 0 */
-+            break;
-+        case FFI_TYPE_FLOAT:
-+        case FFI_TYPE_DOUBLE:
-+            cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 8);
-+            break;
-+        case FFI_TYPE_SINT32:
-+        case FFI_TYPE_UINT32:
-+            cif->flags += FFI_TYPE_SINT32 << (FFI_FLAG_BITS * 8);
-+            break;
-+        default:
-+            cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 8);
-+            break;
-+    }
-+}
-+
-+/* Count how big our argspace is in bytes. Here, we always
-+   allocate at least 8 pointer words and handle big structs
-+   being passed in registers. */
-+
-+void ffi_prep_cif_machdep_bytes(ffi_cif *cif)
-+{
-+    int i;
-+    ffi_type **ptr;
-+    unsigned bytes = 0, extra_bytes = 0;
-+    
-+    if (cif->rtype->type == FFI_TYPE_STRUCT)
-+        bytes = STACK_ARG_SIZE(sizeof(void*));
-+    
-+    for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
-+    {
-+        /* Add any padding if necessary */
-+        if (((*ptr)->alignment - 1) & bytes)
-+            bytes = (unsigned)ALIGN(bytes, (*ptr)->alignment);
-+
-+        /* When we pass big structs in registers, we copy it onto the stack and assign a pointer to it */
-+        if ((*ptr)->size > 2 * FFI_SIZEOF_ARG && bytes < 8 * FFI_SIZEOF_ARG)
-+        {
-+            bytes += sizeof(void*);
-+            extra_bytes += STACK_ARG_SIZE((*ptr)->size);
-+        }
-+        else
-+        {
-+            bytes += STACK_ARG_SIZE((*ptr)->size);
-+        }
-+    }
-+
-+    if (bytes < 8 * FFI_SIZEOF_ARG)
-+        bytes = 8 * FFI_SIZEOF_ARG;
-+    
-+    bytes += extra_bytes;
-+    
-+    cif->bytes = bytes;
-+}
-+
-+/* Perform machine dependent cif processing */
-+
-+ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
-+{
-+    ffi_prep_cif_machdep_bytes(cif);
-+    ffi_prep_cif_machdep_flags(cif, 0, 0);
-+    cif->isvariadic = 0;
-+    return FFI_OK;
-+}
-+
-+/* Perform machine dependent cif processing when we have a variadic function */
-+
-+ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned int nfixedargs, unsigned int ntotalargs)
-+{
-+    ffi_prep_cif_machdep_bytes(cif);
-+    ffi_prep_cif_machdep_flags(cif, 1, nfixedargs);
-+    cif->isvariadic = 1;
-+    return FFI_OK;
-+}
-+
-+/* Low level routine for calling RV64 functions */
-+extern int ffi_call_asm(void (*)(char *, extended_cif *, int, int), 
-+                         extended_cif *, unsigned, unsigned, 
-+                         unsigned *, void (*)(void))
-+                         __attribute__((visibility("hidden")));
-+
-+void ffi_call(ffi_cif *cif, void (*fn)(void), 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;
-+    
-+    ffi_call_asm(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn);
-+}
-+
-+#if FFI_CLOSURES
-+
-+extern void ffi_closure_asm(void) __attribute__((visibility("hidden")));
-+
-+ffi_status ffi_prep_closure_loc(ffi_closure *closure, ffi_cif *cif, void (*fun)(ffi_cif*,void*,void**,void*), void *user_data, void *codeloc)
-+{
-+    unsigned int *tramp = (unsigned int *) &closure->tramp[0];
-+    
-+    uintptr_t fn = (uintptr_t) ffi_closure_asm;
-+    FFI_ASSERT(tramp == codeloc);
-+    
-+    /* Remove when more than just rv64 is supported */
-+    if (cif->abi != FFI_RV64)
-+        return FFI_BAD_ABI;
-+    
-+    if (cif->abi == FFI_RV32 || cif->abi == FFI_RV32_SOFT_FLOAT || fn < 0x7ffff000U)
-+    {
-+        /* auipc t0, 0 (i.e. t0 <- codeloc) */
-+        tramp[0] = 0x00000297;
-+        /* lui t1, %hi(fn) */
-+        tramp[1] = 0x00000337 | ((fn + 0x800) & 0xFFFFF000);
-+        /* jalr x0, t1, %lo(fn) */
-+        tramp[2] = 0x00030067 | ((fn & 0xFFF) << 20);
-+        /* nops */
-+        tramp[3] = 0x00000013;
-+        tramp[4] = 0x00000013;
-+        tramp[5] = 0x00000013;
-+    }
-+    else
-+    {
-+        /* auipc t0, 0 (i.e. t0 <- codeloc) */
-+        tramp[0] = 0x00000297;
-+        /* ld t1, 16(t0) */
-+        tramp[1] = 0x0102b303;
-+        /* jalr x0, t1, %lo(fn) */
-+        tramp[2] = 0x00030067;
-+        /* nop */
-+        tramp[3] = 0x00000013;
-+        /* fn */
-+        tramp[4] = fn;
-+        tramp[5] = fn >> 32;
-+    }
-+    
-+    closure->cif = cif;
-+    closure->fun = fun;
-+    closure->user_data = user_data;
-+    __builtin___clear_cache(codeloc, codeloc + FFI_TRAMPOLINE_SIZE);
-+    
-+    return FFI_OK;
-+}
-+
-+static void copy_struct(char *target, unsigned offset, ffi_abi abi, ffi_type *type, int argn, unsigned arg_offset, ffi_arg *ar, ffi_arg *fpr, int soft_float)
-+{
-+    ffi_type **elt_typep = type->elements;
-+    
-+    while(*elt_typep)
-+    {
-+        ffi_type *elt_type = *elt_typep;
-+        unsigned o;
-+        char *tp;
-+        char *argp;
-+        char *fpp;
-+        
-+        o = ALIGN(offset, elt_type->alignment);
-+        arg_offset += o - offset;
-+        offset = o;
-+        argn += arg_offset / sizeof(ffi_arg);
-+        arg_offset = arg_offset % sizeof(ffi_arg);
-+        argp = (char *)(ar + argn);
-+        fpp = (char *)(argn >= 8 ? ar + argn : fpr + argn);
-+        tp = target + offset;
-+        
-+        if (elt_type->type == FFI_TYPE_DOUBLE && !soft_float)
-+            *(double *)tp = *(double *)fpp;
-+        else
-+            memcpy(tp, argp + arg_offset, elt_type->size);
-+        
-+        offset += elt_type->size;
-+        arg_offset += elt_type->size;
-+        elt_typep++;
-+        argn += arg_offset / sizeof(ffi_arg);
-+        arg_offset = arg_offset % sizeof(ffi_arg);
-+    }
-+}
-+
-+/*
-+* Decodes the arguments to a function, which will be stored on the
-+* stack. AR is the pointer to the beginning of the integer
-+* arguments. FPR is a pointer to the area where floating point
-+* registers have been saved.
-+*
-+* RVALUE is the location where the function return value will be
-+* stored. CLOSURE is the prepared closure to invoke.
-+*
-+* This function should only be called from assembly, which is in
-+* turn called from a trampoline.
-+*
-+* Returns the function return flags.
-+*
-+*/
-+int ffi_closure_riscv_inner(ffi_closure *closure, void *rvalue, ffi_arg *ar, ffi_arg *fpr)
-+{
-+    ffi_cif *cif;
-+    void **avaluep;
-+    ffi_arg *avalue;
-+    ffi_type **arg_types;
-+    int i, avn, argn;
-+    int soft_float;
-+    ffi_arg *argp;
-+    size_t z;
-+    
-+    cif = closure->cif;
-+    soft_float = cif->abi == FFI_RV64_SOFT_FLOAT || cif->abi == FFI_RV32_SOFT_FLOAT;
-+    avalue = alloca(cif->nargs * sizeof (ffi_arg));
-+    avaluep = alloca(cif->nargs * sizeof (ffi_arg));
-+    argn = 0;
-+    
-+    if (cif->rstruct_flag)
-+    {
-+        rvalue = (void *)ar[0];
-+        argn = 1;
-+    }
-+    
-+    i = 0;
-+    avn = cif->nargs;
-+    arg_types = cif->arg_types;
-+    
-+    while (i < avn)
-+    {
-+        z = arg_types[i]->size;
-+        if (arg_types[i]->type == FFI_TYPE_FLOAT || arg_types[i]->type == FFI_TYPE_DOUBLE || arg_types[i]->type == FFI_TYPE_LONGDOUBLE)
-+        {
-+            argp = (argn >= 8 || cif->isvariadic || soft_float) ? ar + argn : fpr + argn;
-+            if ((arg_types[i]->type == FFI_TYPE_LONGDOUBLE) && ((uintptr_t)argp & (arg_types[i]->alignment-1)))
-+            {
-+                argp = (ffi_arg*)ALIGN(argp, arg_types[i]->alignment);
-+                argn++;
-+            }
-+            avaluep[i] = (char *) argp;
-+        }
-+        else
-+        {
-+            unsigned type = arg_types[i]->type;
-+            
-+            if (arg_types[i]->alignment > sizeof(ffi_arg))
-+                argn = ALIGN(argn, arg_types[i]->alignment / sizeof(ffi_arg));
-+            
-+            argp = ar + argn;
-+            
-+            /* The size of a pointer depends on the ABI */
-+            if (type == FFI_TYPE_POINTER)
-+                type = (cif->abi == FFI_RV64 || cif->abi == FFI_RV64_SOFT_FLOAT) ? FFI_TYPE_SINT64 : FFI_TYPE_SINT32;
-+            if (soft_float && type == FFI_TYPE_FLOAT)
-+                type = FFI_TYPE_UINT32;
-+            
-+            switch (type)
-+            {
-+                case FFI_TYPE_SINT8:
-+                    avaluep[i] = &avalue[i];
-+                    *(SINT8 *) &avalue[i] = (SINT8) *argp;
-+                    break;
-+                    
-+                case FFI_TYPE_UINT8:
-+                    avaluep[i] = &avalue[i];
-+                    *(UINT8 *) &avalue[i] = (UINT8) *argp;
-+                    break;
-+                    
-+                case FFI_TYPE_SINT16:
-+                    avaluep[i] = &avalue[i];
-+                    *(SINT16 *) &avalue[i] = (SINT16) *argp;
-+                    break;
-+                    
-+                case FFI_TYPE_UINT16:
-+                    avaluep[i] = &avalue[i];
-+                    *(UINT16 *) &avalue[i] = (UINT16) *argp;
-+                    break;
-+                    
-+                case FFI_TYPE_SINT32:
-+                    avaluep[i] = &avalue[i];
-+                    *(SINT32 *) &avalue[i] = (SINT32) *argp;
-+                    break;
-+                    
-+                case FFI_TYPE_UINT32:
-+                    avaluep[i] = &avalue[i];
-+                    *(UINT32 *) &avalue[i] = (UINT32) *argp;
-+                    break;
-+                    
-+                case FFI_TYPE_SINT64:
-+                    avaluep[i] = &avalue[i];
-+                    *(SINT64 *) &avalue[i] = (SINT64) *argp;
-+                    break;
-+                    
-+                case FFI_TYPE_UINT64:
-+                    avaluep[i] = &avalue[i];
-+                    *(UINT64 *) &avalue[i] = (UINT64) *argp;
-+                    break;
-+                    
-+                case FFI_TYPE_STRUCT:
-+                    if (argn < 8 && arg_types[i]->size <= 2*sizeof(ffi_arg))
-+                    {
-+                        /* Allocate space to copy structs that were passed in registers */
-+                        avaluep[i] = alloca(arg_types[i]->size);
-+                        copy_struct(avaluep[i], 0, cif->abi, arg_types[i], argn, 0, ar, fpr, soft_float);
-+                        break;
-+                    }
-+                    else
-+                    {
-+                        /* The struct was too big to be passed in registers, so it was passed on the stack 
-+                           with pointers in the registers. We need to properly pass the pointer AND set
-+                           the correct size to increment by! */
-+                        avaluep[i] = (void *) *argp;
-+                        z = 1;
-+                        break;
-+                    }
-+                    
-+                /* Else fall through. */
-+                default:
-+                    avaluep[i] = (char *) argp;
-+                    break;
-+            }
-+        }
-+        argn += ALIGN(z, sizeof(ffi_arg)) / sizeof(ffi_arg);
-+        i++;
-+    }
-+    
-+    /* Invoke the closure. */
-+    (closure->fun) (cif, rvalue, avaluep, closure->user_data);
-+    return cif->flags >> (FFI_FLAG_BITS * 8);
-+}
-+
-+#endif /* FFI_CLOSURES */
-Index: libffi-3.2.1/src/riscv/ffitarget.h
-===================================================================
---- /dev/null
-+++ libffi-3.2.1/src/riscv/ffitarget.h
-@@ -0,0 +1,120 @@
-+/* -----------------------------------------------------------------*-C-*-
-+   ffitarget.h - 2014 Michael Knyszek
-+   
-+   Target configuration macros for RISC-V.
-+
-+   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
-+
-+#if defined(__riscv) && __riscv_xlen != 64
-+# error We currently only support RV64.
-+#endif
-+
-+#ifdef __LP64__
-+# define FFI_SIZEOF_ARG 8
-+#else
-+# define FFI_SIZEOF_ARG 4
-+#endif
-+
-+#define FFI_FLAG_BITS 2
-+
-+#ifndef LIBFFI_ASM
-+
-+typedef unsigned long ffi_arg; 
-+typedef   signed long ffi_sarg;
-+
-+typedef enum ffi_abi {
-+  FFI_FIRST_ABI = 0,
-+  FFI_RV32,
-+  FFI_RV32_SOFT_FLOAT,
-+  FFI_RV64,
-+  FFI_RV64_SOFT_FLOAT,
-+  FFI_LAST_ABI,
-+
-+#if defined(__riscv) && __riscv_xlen == 64
-+  #ifdef __riscv_soft_float
-+    FFI_DEFAULT_ABI = FFI_RV64_SOFT_FLOAT
-+  #else
-+    FFI_DEFAULT_ABI = FFI_RV64
-+  #endif
-+#else
-+  #ifdef __riscv_soft_float
-+    FFI_DEFAULT_ABI = FFI_RV32_SOFT_FLOAT
-+  #else
-+    FFI_DEFAULT_ABI = FFI_RV32
-+  #endif
-+#endif /* __riscv_soft_float */
-+} ffi_abi;
-+
-+#else
-+
-+#if defined(__riscv) && __riscv_xlen == 64
-+  #define REG_S sd
-+  #define REG_L ld
-+#else
-+  #define REG_S sw
-+  #define REG_L lw
-+#endif
-+
-+#endif /* LIBFFI_ASM */
-+
-+#define FFI_ARGS_D FFI_TYPE_DOUBLE
-+#define FFI_ARGS_F FFI_TYPE_FLOAT
-+#define FFI_ARGS_DD ((FFI_TYPE_DOUBLE << FFI_FLAG_BITS) + FFI_TYPE_DOUBLE)
-+#define FFI_ARGS_FF ((FFI_TYPE_FLOAT << FFI_FLAG_BITS) + FFI_TYPE_FLOAT)
-+#define FFI_ARGS_FD ((FFI_TYPE_DOUBLE << FFI_FLAG_BITS) + FFI_TYPE_FLOAT)
-+#define FFI_ARGS_DF ((FFI_TYPE_FLOAT << FFI_FLAG_BITS) + FFI_TYPE_DOUBLE)
-+#define FFI_TYPE_SMALLSTRUCT FFI_TYPE_UINT8
-+#define FFI_TYPE_SMALLSTRUCT2 FFI_TYPE_SINT8
-+#define FFI_TYPE_STRUCT_D (FFI_TYPE_STRUCT + (FFI_ARGS_D << 4))
-+#define FFI_TYPE_STRUCT_F (FFI_TYPE_STRUCT + (FFI_ARGS_F << 4))
-+#define FFI_TYPE_STRUCT_DD (FFI_TYPE_STRUCT + (FFI_ARGS_DD << 4))
-+#define FFI_TYPE_STRUCT_FF (FFI_TYPE_STRUCT + (FFI_ARGS_FF << 4))
-+#define FFI_TYPE_STRUCT_FD (FFI_TYPE_STRUCT + (FFI_ARGS_FD << 4))
-+#define FFI_TYPE_STRUCT_DF (FFI_TYPE_STRUCT + (FFI_ARGS_DF << 4))
-+#define FFI_TYPE_STRUCT_SMALL (FFI_TYPE_STRUCT + (5 << 4))
-+#define FFI_TYPE_STRUCT_SMALL2 (FFI_TYPE_STRUCT + (6 << 4))
-+#define FFI_TYPE_STRUCT_D_SOFT (FFI_TYPE_STRUCT_D + 256)
-+#define FFI_TYPE_STRUCT_F_SOFT (FFI_TYPE_STRUCT_F + 256)
-+#define FFI_TYPE_STRUCT_DD_SOFT (FFI_TYPE_STRUCT_DD + 256)
-+#define FFI_TYPE_STRUCT_FF_SOFT (FFI_TYPE_STRUCT_FF + 256)
-+#define FFI_TYPE_STRUCT_FD_SOFT (FFI_TYPE_STRUCT_FD + 256)
-+#define FFI_TYPE_STRUCT_DF_SOFT (FFI_TYPE_STRUCT_DF + 256)
-+#define FFI_TYPE_STRUCT_SOFT 16
-+
-+/* ---- Definitions for closures ----------------------------------------- */
-+
-+#define FFI_CLOSURES 1
-+#define FFI_TRAMPOLINE_SIZE 24
-+#define FFI_NATIVE_RAW_API 0
-+#define FFI_EXTRA_CIF_FIELDS unsigned rstruct_flag; char isvariadic
-+#define FFI_TARGET_SPECIFIC_VARIADIC 1
-+
-+#endif
-+
-Index: libffi-3.2.1/src/riscv/sysv.S
-===================================================================
---- /dev/null
-+++ libffi-3.2.1/src/riscv/sysv.S
-@@ -0,0 +1,782 @@
-+/* -----------------------------------------------------------------------
-+   ffi.c - Copyright (c) 2015 Michael Knyszek <mknyszek@berkeley.edu>
-+                         2015 Andrew Waterman <waterman@cs.berkeley.edu>
-+   Based on MIPS N32/64 port
-+   
-+   RISC-V 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>
-+    
-+#define callback a0
-+#define ecif     a1
-+#define bytes    a2
-+#define flags    a3
-+#define rvalue   a4
-+#define fn       a5
-+#define fp       s0
-+
-+#define FFI_SIZEOF_ARG_X0 (0 * FFI_SIZEOF_ARG)
-+#define FFI_SIZEOF_ARG_X1 (1 * FFI_SIZEOF_ARG)
-+#define FFI_SIZEOF_ARG_X2 (2 * FFI_SIZEOF_ARG)
-+#define FFI_SIZEOF_ARG_X3 (3 * FFI_SIZEOF_ARG)
-+#define FFI_SIZEOF_ARG_X4 (4 * FFI_SIZEOF_ARG)
-+#define FFI_SIZEOF_ARG_X5 (5 * FFI_SIZEOF_ARG)
-+#define FFI_SIZEOF_ARG_X6 (6 * FFI_SIZEOF_ARG)
-+#define FFI_SIZEOF_ARG_X7 (7 * FFI_SIZEOF_ARG)
-+#define FFI_SIZEOF_ARG_X8 (8 * FFI_SIZEOF_ARG)
-+
-+#define ARG_MASK 65535
-+
-+#define FFI_FLAG_BITS_X0 (0 * FFI_FLAG_BITS)
-+#define FFI_FLAG_BITS_X1 (1 * FFI_FLAG_BITS)
-+#define FFI_FLAG_BITS_X2 (2 * FFI_FLAG_BITS)
-+#define FFI_FLAG_BITS_X3 (3 * FFI_FLAG_BITS)
-+#define FFI_FLAG_BITS_X4 (4 * FFI_FLAG_BITS)
-+#define FFI_FLAG_BITS_X5 (5 * FFI_FLAG_BITS)
-+#define FFI_FLAG_BITS_X6 (6 * FFI_FLAG_BITS)
-+#define FFI_FLAG_BITS_X7 (7 * FFI_FLAG_BITS)
-+
-+# Stack pointer needs to be 16-byte aligned, so frame size is rounded up
-+#define SIZEOF_FRAME (6 * FFI_SIZEOF_ARG)
-+
-+    .text
-+    .align  2
-+    .globl  ffi_call_asm
-+    .type   ffi_call_asm, @function
-+ffi_call_asm:
-+    .cfi_startproc
-+    
-+    ### Prologue
-+    
-+    # a0 - ffi_prep_args pointer
-+    # a1 - extended_cif pointer
-+    # a2 - bytes
-+    # a3 - flags
-+    # a4 - rvalue
-+    # a5 - function ptr
-+    
-+    add     sp, sp, -SIZEOF_FRAME   # move stack pointer by frame size
-+                                    # must be 16-byte aligned 
-+    
-+    # stack ptr points to first argument on stack,
-+    # but there should be no arguments on the stack
-+    
-+    .cfi_def_cfa_offset SIZEOF_FRAME
-+    
-+    REG_S   ra,      FFI_SIZEOF_ARG_X5(sp)   # save return address
-+    REG_S   fp,      FFI_SIZEOF_ARG_X4(sp)   # save frame pointer
-+    REG_S   flags,   FFI_SIZEOF_ARG_X3(sp)   # save flags
-+    REG_S   fn,      FFI_SIZEOF_ARG_X2(sp)   # save function pointer
-+    REG_S   rvalue,  FFI_SIZEOF_ARG_X1(sp)   # save return value pointer
-+    
-+    .cfi_offset 1, -8
-+    .cfi_offset 8, -16
-+    
-+    add     fp, sp, SIZEOF_FRAME     # new frame pointer is old stack pointer
-+    
-+    .cfi_def_cfa 8, 0
-+    
-+    add     t4, callback, zero       # function ptr to prep_args
-+    
-+    # Here we're setting up our argspace and its size
-+    
-+    add     t0, bytes, 15      # make sure it is aligned 
-+    andi    t0, t0,   -16      # to a 16 byte boundry
-+
-+thirtytwo:
-+    sub     sp, sp, t0 # move the stack pointer to reflect the arg space
-+    
-+    # a0 is the stack with proper arg space allocated
-+    add     a0, sp, zero
-+    
-+    # a1 is ecif
-+    # a2 is bytes
-+    # a3 is flags
-+
-+    jalr    t4  # call ffi_prep_args
-+    
-+    REG_L   t0, -FFI_SIZEOF_ARG_X3(fp)  # load the flags word
-+    srli    t2, t0, 16                 # shift our return type into t2
-+    
-+    li      t1, ARG_MASK
-+    and     t0, t0, t1                 # mask out the arg types into t0
-+
-+    # time to load the arguments for the call
-+
-+#ifndef __riscv_soft_float
-+
-+####################
-+## SET ARGUMENT 0 ##
-+####################
-+
-+set_arg0:
-+    srli    t1, t0, FFI_FLAG_BITS_X0 # Shift to get the bits for this argument
-+    andi    t1, t1, 3               # Mask out the bits for this argument
-+    
-+    # when its zero, it means its just a word-sized int/ptr
-+    bne     t1, zero, set_arg0_float 
-+    REG_L   a0, FFI_SIZEOF_ARG_X0(sp) # load argument
-+    j       set_arg1
-+    
-+set_arg0_float:
-+    addi    t1, t1, -2
-+    
-+    # when its zero, it means its just a word-sized float
-+    bne     t1, zero, set_arg0_double
-+    flw     fa0, FFI_SIZEOF_ARG_X0(sp) # load argument
-+    j       set_arg1
-+    
-+set_arg0_double:
-+    # otherwise it must be a double we're dealing with
-+    fld     fa0, FFI_SIZEOF_ARG_X0(sp)
-+
-+####################
-+## SET ARGUMENT 1 ##
-+####################
-+
-+set_arg1:
-+    srli    t1, t0, FFI_FLAG_BITS_X1 # Shift to get the bits for this argument
-+    andi    t1, t1, 3               # Mask out the bits for this argument
-+    
-+    # when its zero, it means its just a word-sized int/ptr
-+    bne     t1, zero, set_arg1_float 
-+    REG_L   a1, FFI_SIZEOF_ARG_X1(sp) # load argument
-+    j       set_arg2
-+    
-+set_arg1_float:
-+    addi    t1, t1, -2
-+    
-+    # when its zero, it means its just a word-sized float
-+    bne     t1, zero, set_arg1_double
-+    flw     fa1, FFI_SIZEOF_ARG_X1(sp) # load argument
-+    j       set_arg2
-+    
-+set_arg1_double:
-+    # otherwise it must be a double we're dealing with
-+    fld     fa1, FFI_SIZEOF_ARG_X1(sp)
-+
-+####################
-+## SET ARGUMENT 2 ##
-+####################
-+
-+set_arg2:
-+    srli    t1, t0, FFI_FLAG_BITS_X2 # Shift to get the bits for this argument
-+    andi    t1, t1, 3               # Mask out the bits for this argument
-+    
-+    # when its zero, it means its just a word-sized int/ptr
-+    bne     t1, zero, set_arg2_float 
-+    REG_L   a2, FFI_SIZEOF_ARG_X2(sp) # load argument
-+    j       set_arg3
-+    
-+set_arg2_float:
-+    addi    t1, t1, -2
-+    
-+    # when its zero, it means its just a word-sized float
-+    bne     t1, zero, set_arg2_double
-+    flw     fa2, FFI_SIZEOF_ARG_X2(sp) # load argument
-+    j       set_arg3
-+    
-+set_arg2_double:
-+    # otherwise it must be a double we're dealing with
-+    fld     fa2, FFI_SIZEOF_ARG_X2(sp)
-+
-+####################
-+## SET ARGUMENT 3 ##
-+####################
-+
-+set_arg3:
-+    srli    t1, t0, FFI_FLAG_BITS_X3 # Shift to get the bits for this argument
-+    andi    t1, t1, 3               # Mask out the bits for this argument
-+    
-+    # when its zero, it means its just a word-sized int/ptr
-+    bne     t1, zero, set_arg3_float 
-+    REG_L   a3, FFI_SIZEOF_ARG_X3(sp) # load argument
-+    j       set_arg4
-+    
-+set_arg3_float:
-+    addi    t1, t1, -2
-+    
-+    # when its zero, it means its just a word-sized float
-+    bne     t1, zero, set_arg3_double
-+    flw     fa3, FFI_SIZEOF_ARG_X3(sp) # load argument
-+    j       set_arg4
-+    
-+set_arg3_double:
-+    # otherwise it must be a double we're dealing with
-+    fld     fa3, FFI_SIZEOF_ARG_X3(sp)
-+
-+####################
-+## SET ARGUMENT 4 ##
-+####################
-+
-+set_arg4:
-+    srli    t1, t0, FFI_FLAG_BITS_X4 # Shift to get the bits for this argument
-+    andi    t1, t1, 3               # Mask out the bits for this argument
-+    
-+    # when its zero, it means its just a word-sized int/ptr
-+    bne     t1, zero, set_arg4_float 
-+    REG_L   a4, FFI_SIZEOF_ARG_X4(sp) # load argument
-+    j       set_arg5
-+    
-+set_arg4_float:
-+    addi    t1, t1, -2
-+    
-+    # when its zero, it means its just a word-sized float
-+    bne     t1, zero, set_arg4_double
-+    flw     fa4, FFI_SIZEOF_ARG_X4(sp) # load argument
-+    j       set_arg5
-+    
-+set_arg4_double:
-+    # otherwise it must be a double we're dealing with
-+    fld     fa4, FFI_SIZEOF_ARG_X4(sp)
-+
-+####################
-+## SET ARGUMENT 5 ##
-+####################
-+
-+set_arg5:
-+    srli    t1, t0, FFI_FLAG_BITS_X5 # Shift to get the bits for this argument
-+    andi    t1, t1, 3               # Mask out the bits for this argument
-+    
-+    # when its zero, it means its just a word-sized int/ptr
-+    bne     t1, zero, set_arg5_float 
-+    REG_L   a5, FFI_SIZEOF_ARG_X5(sp) # load argument
-+    j       set_arg6
-+    
-+set_arg5_float:
-+    addi    t1, t1, -2
-+    
-+    # when its zero, it means its just a word-sized float
-+    bne     t1, zero, set_arg5_double
-+    flw     fa5, FFI_SIZEOF_ARG_X5(sp) # load argument
-+    j       set_arg6
-+    
-+set_arg5_double:
-+    # otherwise it must be a double we're dealing with
-+    fld     fa5, FFI_SIZEOF_ARG_X5(sp)
-+
-+####################
-+## SET ARGUMENT 6 ##
-+####################
-+
-+set_arg6:
-+    srli    t1, t0, FFI_FLAG_BITS_X6 # Shift to get the bits for this argument
-+    andi    t1, t1, 3               # Mask out the bits for this argument
-+    
-+    # when its zero, it means its just a word-sized int/ptr
-+    bne     t1, zero, set_arg6_float 
-+    REG_L   a6, FFI_SIZEOF_ARG_X6(sp) # load argument
-+    j       set_arg7
-+    
-+set_arg6_float:
-+    addi    t1, t1, -2
-+    
-+    # when its zero, it means its just a word-sized float
-+    bne     t1, zero, set_arg6_double
-+    flw     fa6, FFI_SIZEOF_ARG_X6(sp) # load argument
-+    j       set_arg7
-+    
-+set_arg6_double:
-+    # otherwise it must be a double we're dealing with
-+    fld     fa6, FFI_SIZEOF_ARG_X6(sp)
-+
-+####################
-+## SET ARGUMENT 7 ##
-+####################
-+
-+set_arg7:
-+    srli    t1, t0, FFI_FLAG_BITS_X7 # Shift to get the bits for this argument
-+    andi    t1, t1, 3               # Mask out the bits for this argument
-+    
-+    # when its zero, it means its just a word-sized int/ptr
-+    bne     t1, zero, set_arg7_float 
-+    REG_L   a7, FFI_SIZEOF_ARG_X7(sp) # load argument
-+    j       call_it
-+    
-+set_arg7_float:
-+    addi    t1, t1, -2
-+    
-+    # when its zero, it means its just a word-sized float
-+    bne     t1, zero, set_arg7_double
-+    flw     fa7, FFI_SIZEOF_ARG_X7(sp) # load argument
-+    j       call_it
-+    
-+set_arg7_double:
-+    # otherwise it must be a double we're dealing with
-+    fld     fa7, FFI_SIZEOF_ARG_X7(sp)
-+    
-+#else
-+
-+## START RISCV SOFT-FLOAT LOADING ##
-+
-+    # In the soft-float case, we have no primitive datatype
-+    # that has a size of >8 bytes. Therefore, we can 
-+    # just load everything quite easily and nicely.
-+
-+    REG_L   a0, FFI_SIZEOF_ARG_X0(sp) # load argument
-+    REG_L   a1, FFI_SIZEOF_ARG_X1(sp) # load argument
-+    REG_L   a2, FFI_SIZEOF_ARG_X2(sp) # load argument
-+    REG_L   a3, FFI_SIZEOF_ARG_X3(sp) # load argument
-+    REG_L   a4, FFI_SIZEOF_ARG_X4(sp) # load argument
-+    REG_L   a5, FFI_SIZEOF_ARG_X5(sp) # load argument
-+    REG_L   a6, FFI_SIZEOF_ARG_X6(sp) # load argument
-+    REG_L   a7, FFI_SIZEOF_ARG_X7(sp) # load argument
-+
-+#endif  
-+
-+call_it:
-+    # First, we fix the stack pointer to point to the first argument
-+    # passed on the stack.
-+    add     sp, sp, FFI_SIZEOF_ARG_X8
-+
-+    # Load the function pointer
-+    REG_L   t4, -FFI_SIZEOF_ARG_X4(fp)
-+
-+    # When the return value pointer is NULL, assume no return value.
-+    REG_L   t1, -FFI_SIZEOF_ARG_X5(fp)
-+    beq     t1, zero, return_void
-+    
-+    # is the return type an int? if not, jump ahead
-+    ori     t3, zero, FFI_TYPE_INT
-+    bne     t2, t3,   return_int32
-+    
-+    jalr    t4 # call the function
-+    
-+    # We reload the return pointer because it was in a temp reg and
-+    # there was just a function call.
-+    REG_L   t0, -FFI_SIZEOF_ARG_X5(fp)
-+    REG_S   a0, 0(t0)
-+    j       epilogue
-+
-+return_int32:
-+    ori     t3, zero, FFI_TYPE_SINT32
-+#ifndef __riscv_soft_float
-+    bne     t2, t3, return_float
-+#else
-+    bne     t2, t3, return_struct_d_soft
-+#endif
-+    
-+    jalr    t4 # call the function
-+    
-+    # We reload the return pointer because it was in a temp reg and
-+    # there was just a function call.
-+    REG_L   t0, -FFI_SIZEOF_ARG_X5(fp)
-+    sw      a0, 0(t0)
-+    j       epilogue
-+    
-+#ifndef __riscv_soft_float
-+return_float:
-+    # is the return type a float? if not, jump ahead
-+    ori     t3, zero, FFI_TYPE_FLOAT
-+    bne     t2, t3, return_double
-+    
-+    jalr    t4 # call the function
-+    
-+    # We reload the return pointer because it was in a temp reg and
-+    # there was just a function call.
-+    REG_L   t0,  -FFI_SIZEOF_ARG_X5(fp)
-+    fsw     fa0, FFI_SIZEOF_ARG_X0(t0)
-+    j       epilogue
-+
-+return_double:
-+    # is the return type a double? if not, give up
-+    ori     t3, zero, FFI_TYPE_DOUBLE
-+    bne     t2, t3, return_struct_d
-+    
-+    jalr    t4 # call the function
-+    
-+    # We reload the return pointer because it was in a temp reg and
-+    # there was just a function call.
-+    REG_L   t0,  -FFI_SIZEOF_ARG_X5(fp)
-+    fsd     fa0, FFI_SIZEOF_ARG_X0(t0)
-+    j       epilogue
-+
-+### Handle struct special cases (hard float)
-+
-+  # Here the struct to return is less than
-+  # or equal to 2 pointer-words in size. We
-+  # need to specifically handle the floats/doubles.
-+
-+return_struct_d:
-+    # is the return type a struct with a double? if not, give up
-+    ori     t3, zero, FFI_TYPE_STRUCT_D
-+    bne     t2, t3,   return_struct_f
-+    
-+    jalr    t4 # call the function
-+    
-+    # We reload the return pointer because it was in a temp reg and
-+    # there was just a function call.
-+    REG_L   t0,  -FFI_SIZEOF_ARG_X5(fp)
-+    fsd     fa0, FFI_SIZEOF_ARG_X0(t0)
-+    j       epilogue
-+    
-+return_struct_f:
-+    # is the return type a struct with a float? if not, give up
-+    ori     t3, zero, FFI_TYPE_STRUCT_F
-+    bne     t2, t3,   return_struct_d_d
-+    
-+    jalr    t4 # call the function
-+    
-+    # We reload the return pointer because it was in a temp reg and
-+    # there was just a function call.
-+    REG_L   t0,  -FFI_SIZEOF_ARG_X5(fp)
-+    fsw     fa0, FFI_SIZEOF_ARG_X0(t0)
-+    j       epilogue
-+    
-+return_struct_d_d:
-+    # is the return type a struct with two doubles? if not, give up
-+    ori     t3, zero, FFI_TYPE_STRUCT_DD
-+    bne     t2, t3,   return_struct_f_f
-+    
-+    jalr    t4 # call the function
-+    
-+    # We reload the return pointer because it was in a temp reg and
-+    # there was just a function call.
-+    REG_L   t0,  -FFI_SIZEOF_ARG_X5(fp)
-+    fsd     fa0, FFI_SIZEOF_ARG_X0(t0)
-+    fsd     fa1, FFI_SIZEOF_ARG_X1(t0)
-+    j       epilogue
-+    
-+return_struct_f_f:
-+    # is the return type a struct with two floats? if not, give up
-+    ori     t3, zero, FFI_TYPE_STRUCT_FF
-+    bne     t2, t3,   return_struct_d_f
-+    
-+    jalr    t4 # call the function
-+    
-+    # We reload the return pointer because it was in a temp reg and
-+    # there was just a function call.
-+    REG_L   t0,  -FFI_SIZEOF_ARG_X5(fp)
-+    fsw     fa0, FFI_SIZEOF_ARG_X0(t0)
-+    fsw     fa1, FFI_SIZEOF_ARG_X1(t0)
-+    j       epilogue
-+    
-+return_struct_d_f:
-+    # is the return type a struct with a double then float? if not, give up
-+    ori     t3, zero, FFI_TYPE_STRUCT_DF
-+    bne     t2, t3,   return_struct_f_d
-+    
-+    jalr    t4 # call the function
-+    
-+    # We reload the return pointer because it was in a temp reg and
-+    # there was just a function call.
-+    REG_L   t0,  -FFI_SIZEOF_ARG_X5(fp)
-+    fsd     fa0, FFI_SIZEOF_ARG_X0(t0)
-+    fsw     fa1, FFI_SIZEOF_ARG_X1(t0)
-+    j       epilogue
-+    
-+return_struct_f_d:
-+    # is the return type a struct with a float then double? if not, give up
-+    ori     t3, zero, FFI_TYPE_STRUCT_FD
-+    bne     t2, t3,   return_struct_small
-+    
-+    jalr    t4 # call the function
-+    
-+    # We reload the return pointer because it was in a temp reg and
-+    # there was just a function call.
-+    REG_L   t0,  -FFI_SIZEOF_ARG_X5(fp)
-+    fsw     fa0, FFI_SIZEOF_ARG_X0(t0)
-+    fsd     fa1, FFI_SIZEOF_ARG_X1(t0)
-+    j       epilogue
-+    
-+#else
-+
-+### Handle struct special cases (soft float)
-+
-+  # Here the struct to return is less than
-+  # or equal to 2 pointer-words in size. We
-+  # need to specifically handle the floats/doubles.
-+
-+return_struct_d_soft:
-+    # is the return type a struct with a double? if not, give up
-+    ori     t3, zero, FFI_TYPE_STRUCT_D_SOFT
-+    bne     t2, t3,   return_struct_f_soft
-+    
-+    jalr    t4 # call the function
-+    
-+    # We reload the return pointer because it was in a temp reg and
-+    # there was just a function call.
-+    REG_L   t0,  -FFI_SIZEOF_ARG_X5(fp)
-+    sd      a0,  FFI_SIZEOF_ARG_X0(t0)
-+    j       epilogue
-+    
-+return_struct_f_soft:
-+    # is the return type a struct with a float? if not, give up
-+    ori     t3, zero, FFI_TYPE_STRUCT_F_SOFT
-+    bne     t2, t3,   return_struct_d_d_soft
-+    
-+    jalr    t4 # call the function
-+    
-+    # We reload the return pointer because it was in a temp reg and
-+    # there was just a function call.
-+    REG_L   t0,  -FFI_SIZEOF_ARG_X5(fp)
-+    sw      a0,  FFI_SIZEOF_ARG_X0(t0)
-+    j       epilogue
-+    
-+return_struct_d_d_soft:
-+    # is the return type a struct with two doubles? if not, give up
-+    ori     t3, zero, FFI_TYPE_STRUCT_DD_SOFT
-+    bne     t2, t3,   return_struct_f_f_soft
-+    
-+    jalr    t4 # call the function
-+    
-+    # We reload the return pointer because it was in a temp reg and
-+    # there was just a function call.
-+    REG_L   t0,  -FFI_SIZEOF_ARG_X5(fp)
-+    sd      a0,  FFI_SIZEOF_ARG_X0(t0)
-+    sd      a1,  FFI_SIZEOF_ARG_X1(t0)
-+    j       epilogue
-+    
-+return_struct_f_f_soft:
-+    # is the return type a struct with two floats? if not, give up
-+    ori     t3, zero, FFI_TYPE_STRUCT_FF_SOFT
-+    bne     t2, t3,   return_struct_d_f_soft
-+    
-+    jalr    t4 # call the function
-+    
-+    # We reload the return pointer because it was in a temp reg and
-+    # there was just a function call.
-+    REG_L   t0,  -FFI_SIZEOF_ARG_X5(fp)
-+    sw      a0,  FFI_SIZEOF_ARG_X0(t0)
-+    sw      a1,  FFI_SIZEOF_ARG_X1(t0)
-+    j       epilogue
-+    
-+return_struct_d_f_soft:
-+    # is the return type a struct with a double then float? if not, give up
-+    ori     t3, zero, FFI_TYPE_STRUCT_DF_SOFT
-+    bne     t2, t3,   return_struct_f_d_soft
-+    
-+    jalr    t4 # call the function
-+    
-+    # We reload the return pointer because it was in a temp reg and
-+    # there was just a function call.
-+    REG_L   t0,  -FFI_SIZEOF_ARG_X5(fp)
-+    sd      a0,  FFI_SIZEOF_ARG_X0(t0)
-+    sw      a1,  FFI_SIZEOF_ARG_X1(t0)
-+    j       epilogue
-+    
-+return_struct_f_d_soft:
-+    # is the return type a struct with a float then double? if not, give up
-+    ori     t3, zero, FFI_TYPE_STRUCT_FD_SOFT
-+    bne     t2, t3,   return_struct_small
-+    
-+    jalr    t4 # call the function
-+    
-+    # We reload the return pointer because it was in a temp reg and
-+    # there was just a function call.
-+    REG_L   t0,  -FFI_SIZEOF_ARG_X5(fp)
-+    sw      a0,  FFI_SIZEOF_ARG_X0(t0)
-+    sd      a1,  FFI_SIZEOF_ARG_X1(t0)
-+    j       epilogue
-+    
-+#endif    
-+
-+### Handle struct special cases (tiny structs)
-+
-+return_struct_small:
-+    # is the return type a struct with a float then double? if not, give up
-+    ori     t3, zero, FFI_TYPE_STRUCT_SMALL
-+    bne     t2, t3,   return_struct_small2
-+    
-+    jalr    t4 # call the function
-+    
-+    # We reload the return pointer because it was in a temp reg and
-+    # there was just a function call.
-+    REG_L   t0,  -FFI_SIZEOF_ARG_X5(fp)
-+    REG_S   a0,  FFI_SIZEOF_ARG_X0(t0)
-+    j       epilogue
-+    
-+return_struct_small2:
-+    # is the return type a struct with a float then double? if not, give up
-+    ori     t3, zero, FFI_TYPE_STRUCT_SMALL2
-+    bne     t2, t3,   return_struct
-+    
-+    jalr    t4 # call the function
-+    
-+    # We reload the return pointer because it was in a temp reg and
-+    # there was just a function call.
-+    REG_L   t0,  -FFI_SIZEOF_ARG_X5(fp)
-+    REG_S   a0,  FFI_SIZEOF_ARG_X0(t0)
-+    REG_S   a1,  FFI_SIZEOF_ARG_X1(t0)
-+    j       epilogue
-+    
-+### Any other struct is returned through memory
-+return_struct: 
-+return_void:   
-+    jalr    t4 # call the function
-+   
-+epilogue:   
-+    add     sp, fp, zero               # Fix stack pointer
-+    REG_L   fp, -FFI_SIZEOF_ARG_X2(sp)  # Restore frame pointer
-+    REG_L   ra, -FFI_SIZEOF_ARG_X1(sp)  # Restore return address      
-+    jr      ra
-+    
-+    .cfi_endproc
-+    .size   ffi_call_asm, .-ffi_call_asm
-+
-+    
-+/* ffi_closure_asm. Expects address of the passed-in ffi_closure in t0. */
-+
-+#define SIZEOF_FRAME2 (20 * FFI_SIZEOF_ARG)
-+#define A7_OFF2       (19 * FFI_SIZEOF_ARG)
-+#define A6_OFF2       (18 * FFI_SIZEOF_ARG)
-+#define A5_OFF2       (17 * FFI_SIZEOF_ARG)
-+#define A4_OFF2       (16 * FFI_SIZEOF_ARG)
-+#define A3_OFF2       (15 * FFI_SIZEOF_ARG)
-+#define A2_OFF2       (14 * FFI_SIZEOF_ARG)
-+#define A1_OFF2       (13 * FFI_SIZEOF_ARG)
-+#define A0_OFF2       (12 * FFI_SIZEOF_ARG)
-+#define FA7_OFF2      (11 * FFI_SIZEOF_ARG)
-+#define FA6_OFF2      (10 * FFI_SIZEOF_ARG)
-+#define FA5_OFF2      ( 9 * FFI_SIZEOF_ARG)
-+#define FA4_OFF2      ( 8 * FFI_SIZEOF_ARG)
-+#define FA3_OFF2      ( 7 * FFI_SIZEOF_ARG)
-+#define FA2_OFF2      ( 6 * FFI_SIZEOF_ARG)
-+#define FA1_OFF2      ( 5 * FFI_SIZEOF_ARG)
-+#define FA0_OFF2      ( 4 * FFI_SIZEOF_ARG)
-+#define V1_OFF2       ( 3 * FFI_SIZEOF_ARG)
-+#define V0_OFF2       ( 2 * FFI_SIZEOF_ARG)
-+#define RA_OFF2       ( 1 * FFI_SIZEOF_ARG)
-+
-+    .align 2
-+    .globl ffi_closure_asm
-+    .type ffi_closure_asm, @function
-+ffi_closure_asm:
-+    .cfi_startproc
-+
-+    addi    sp,  sp, -SIZEOF_FRAME2
-+    
-+    .cfi_def_cfa_offset SIZEOF_FRAME2
-+    
-+    REG_S   ra,  RA_OFF2(sp) # Save return address
-+    
-+    .cfi_offset  1, -19*FFI_SIZEOF_ARG
-+    .cfi_def_cfa 2, SIZEOF_FRAME2
-+    
-+    # Store all possible argument registers. If there are more than
-+    # fit in registers, then they were stored on the stack.
-+    REG_S   a0,  A0_OFF2(sp)
-+    REG_S   a1,  A1_OFF2(sp)
-+    REG_S   a2,  A2_OFF2(sp)
-+    REG_S   a3,  A3_OFF2(sp)
-+    REG_S   a4,  A4_OFF2(sp)
-+    REG_S   a5,  A5_OFF2(sp)
-+    REG_S   a6,  A6_OFF2(sp)
-+    REG_S   a7,  A7_OFF2(sp)
-+    
-+    # Store all possible float/double registers.
-+    fsd     fa0, FA0_OFF2(sp)
-+    fsd     fa1, FA1_OFF2(sp)
-+    fsd     fa2, FA2_OFF2(sp)
-+    fsd     fa3, FA3_OFF2(sp)
-+    fsd     fa4, FA4_OFF2(sp)
-+    fsd     fa5, FA5_OFF2(sp)
-+    fsd     fa6, FA6_OFF2(sp)
-+    fsd     fa7, FA7_OFF2(sp)
-+    
-+    # Call ffi_closure_riscv_inner to do the real work.
-+    move    a0, t0 # Pointer to the ffi_closure
-+    addi    a1, sp, V0_OFF2
-+    addi    a2, sp, A0_OFF2
-+    addi    a3, sp, FA0_OFF2
-+    call    ffi_closure_riscv_inner
-+    
-+    # Return flags are in a0
-+    li      t0, FFI_TYPE_INT
-+    bne     a0, t0, cls_retint32
-+    REG_L   a0, V0_OFF2(sp)
-+    j       cls_epilogue
-+    
-+cls_retint32:
-+    li      t0, FFI_TYPE_SINT32
-+    bne     a0, t0, cls_retfloat
-+    lw      a0, V0_OFF2(sp)
-+    j       cls_epilogue
-+    
-+cls_retfloat:
-+    li      t0, FFI_TYPE_FLOAT
-+    bne     a0, t0, cls_retdouble
-+    flw     fa0, V0_OFF2(sp)
-+    j       cls_epilogue
-+    
-+cls_retdouble:
-+    li      t0,  FFI_TYPE_DOUBLE
-+    bne     a0,  t0, cls_retstruct_d
-+    fld     fa0, V0_OFF2(sp)
-+    j       cls_epilogue
-+    
-+cls_retstruct_d:
-+    li      t0,  FFI_TYPE_STRUCT_D
-+    bne     a0,  t0, cls_retstruct_f
-+    fld     fa0, V0_OFF2(sp)
-+    j       cls_epilogue
-+    
-+cls_retstruct_f:
-+    li      t0,  FFI_TYPE_STRUCT_F
-+    bne     a0,  t0, cls_retstruct_d_d
-+    flw     fa0, V0_OFF2(sp)
-+    j       cls_epilogue
-+    
-+cls_retstruct_d_d:
-+    li      t0,  FFI_TYPE_STRUCT_DD
-+    bne     a0,  t0, cls_retstruct_f_f
-+    fld     fa0, V0_OFF2(sp)
-+    fld     fa1, V1_OFF2(sp)
-+    j       cls_epilogue
-+    
-+cls_retstruct_f_f:
-+    li      t0,  FFI_TYPE_STRUCT_FF
-+    bne     a0,  t0, cls_retstruct_d_f
-+    flw     fa0, V0_OFF2(sp)
-+    flw     fa1, V1_OFF2(sp)
-+    j       cls_epilogue
-+    
-+cls_retstruct_d_f:
-+    li      t0,  FFI_TYPE_STRUCT_DF
-+    bne     a0,  t0, cls_retstruct_f_d
-+    fld     fa0, V0_OFF2(sp)
-+    flw     fa1, V1_OFF2(sp)
-+    j       cls_epilogue
-+    
-+cls_retstruct_f_d:
-+    li      t0,  FFI_TYPE_STRUCT_FD
-+    bne     a0,  t0, cls_retstruct_small2
-+    flw     fa0, V0_OFF2(sp)
-+    fld     fa1, V1_OFF2(sp)
-+    j       cls_epilogue
-+    
-+cls_retstruct_small2:
-+    REG_L   a0, V0_OFF2(sp)
-+    REG_L   a1, V1_OFF2(sp)
-+    
-+# Epilogue
-+cls_epilogue:
-+    REG_L   ra, RA_OFF2(sp) # Restore return address
-+    addi    sp, sp, SIZEOF_FRAME2
-+    ret
-+    
-+    .cfi_endproc
-+    .size ffi_closure_asm, .-ffi_closure_asm
-Index: libffi-3.2.1/testsuite/Makefile.am
-===================================================================
---- libffi-3.2.1.orig/testsuite/Makefile.am
-+++ libffi-3.2.1/testsuite/Makefile.am
-@@ -34,7 +34,7 @@ libffi.call/cls_12byte.c libffi.call/cls
- libffi.call/cls_align_longdouble_split2.c libffi.call/return_dbl2.c	\
- libffi.call/return_fl3.c libffi.call/stret_medium.c			\
- libffi.call/nested_struct6.c libffi.call/closure_fn3.c			\
--libffi.call/float3.c libffi.call/many2.c				\
-+libffi.call/float3.c libffi.call/many2.c libffi.call/many3.c		\
- libffi.call/closure_simple.c libffi.call/cls_align_uint16.c		\
- libffi.call/cls_9byte1.c libffi.call/closure_fn6.c			\
- libffi.call/cls_double_va.c libffi.call/cls_align_pointer.c		\
-Index: libffi-3.2.1/testsuite/libffi.call/many3.c
-===================================================================
---- /dev/null
-+++ libffi-3.2.1/testsuite/libffi.call/many3.c
-@@ -0,0 +1,59 @@
-+/* Area:	ffi_call
-+   Purpose:	Check return value int, with many arguments
-+   Limitations:	none.
-+   PR:		none.
-+   Originator:	From the original ffitest.c  */
-+
-+/* { dg-do run } */
-+#include "ffitest.h"
-+
-+#include <stdlib.h>
-+//#include <int.h>
-+#include <math.h>
-+
-+static int ABI_ATTR many(int f1, int f2, int f3, int f4, int f5, int f6, int f7, int f8, int f9, int f10, int f11, int f12, int f13)
-+{
-+#if 0
-+  printf("%f %f %f %f %f %f %f %f %f %f %f %f %f\n",
-+	 (double) f1, (double) f2, (double) f3, (double) f4, (double) f5, 
-+	 (double) f6, (double) f7, (double) f8, (double) f9, (double) f10,
-+	 (double) f11, (double) f12, (double) f13);
-+#endif
-+
-+  return f1+f2+f3+f4+f5+f6+f7+f8+f9+f10+f11+f12+f13;
-+}
-+
-+int main (void)
-+{
-+  ffi_cif cif;
-+  ffi_type *args[13];
-+  void *values[13];
-+  int fa[13];
-+  int f, ff;
-+  int i;
-+
-+  for (i = 0; i < 13; i++)
-+    {
-+      args[i] = &ffi_type_sint;
-+      values[i] = &fa[i];
-+      fa[i] = (int) i;
-+    }
-+
-+    /* Initialize the cif */
-+    CHECK(ffi_prep_cif(&cif, ABI_NUM, 13,
-+		       &ffi_type_sint, args) == FFI_OK);
-+
-+    ffi_call(&cif, FFI_FN(many), &f, values);
-+
-+    ff =  many(fa[0], fa[1],
-+	       fa[2], fa[3],
-+	       fa[4], fa[5],
-+	       fa[6], fa[7],
-+	       fa[8], fa[9],
-+	       fa[10],fa[11],fa[12]);
-+
-+    if (f == ff)
-+      exit(0);
-+    else
-+      abort();
-+}

+ 0 - 2
recipes-support/libffi/libffi_3%.bbappend

@@ -1,2 +0,0 @@
-FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
-SRC_URI += "file://0001-Add-riscv-support.patch"

+ 30 - 0
recipes-support/libffi/libffi_3.3-rc0.bb

@@ -0,0 +1,30 @@
+SUMMARY = "A portable foreign function interface library"
+HOMEPAGE = "http://sourceware.org/libffi/"
+DESCRIPTION = "The `libffi' library provides a portable, high level programming interface to various calling \
+conventions.  This allows a programmer to call any function specified by a call interface description at run \
+time. FFI stands for Foreign Function Interface.  A foreign function interface is the popular name for the \
+interface that allows code written in one language to call code written in another language.  The `libffi' \
+library really only provides the lowest, machine dependent layer of a fully featured foreign function interface.  \
+A layer must exist above `libffi' that handles type conversions for values passed between the two languages."
+
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=3610bb17683a0089ed64055416b2ae1b"
+
+SRC_URI = "https://github.com/libffi/libffi/releases/download/v3.3-rc0/libffi-3.3-rc0.tar.gz"
+
+SRC_URI[md5sum] = "8d2a82a78faf10a5e53c27d986e8f04e"
+SRC_URI[sha256sum] = "403d67aabf1c05157855ea2b1d9950263fb6316536c8c333f5b9ab1eb2f20ecf"
+
+EXTRA_OECONF += "--disable-builddir"
+EXTRA_OEMAKE_class-target = "LIBTOOLFLAGS='--tag=CC'"
+inherit autotools texinfo
+
+FILES_${PN}-dev += "${libdir}/libffi-${PV}"
+
+# Doesn't compile in MIPS16e mode due to use of hand-written
+# assembly
+MIPS_INSTRUCTION_SET = "mips"
+
+BBCLASSEXTEND = "native nativesdk"
+
+COMPATIBLE_HOST = "(riscv64|riscv32).*-linux"