|
@@ -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();
|
|
|
-+}
|