I am using the same changes in Fedora RISC-V with GCC 8.0.1-0.19 (libffi patch + s/FFI_ALIGN/ALIGN/ + regen).
Note that libffi port is missing go closures support. Small things like hello world work fine, but utilities like "go" will complain with run- time error: fatal error: libgo built without FFI does not support reflect.Call or runtime.SetFinalizer" What is the current situation/resolution regarding GOARCH? GCC use RISCV64, but golang port uses RISCV. It would be nice to have a resolution before GCC 8 release is cut. david On Tue, 2018-03-20 at 11:50 +0100, Andreas Schwab wrote: > This is a backport of <https://github.com/libffi/libffi/commit/3840d4 > 9aaa> > (the only difference to upstream is s/FFI_ALIGN/ALIGN/, as we don't > have > commit bd72848c7a). This is needed for libgo. > > Andreas. > > * configure.host: Add RISC-V support. > * Makefile.am: Likewise. > * Makefile.in: Regenerate. > * src/riscv/ffi.c, src/riscv/ffitarget.h, src/riscv/sysv.S: New > files. > --- > libffi/Makefile.am | 2 + > libffi/Makefile.in | 25 ++- > libffi/configure.host | 5 + > libffi/src/riscv/ffi.c | 445 > +++++++++++++++++++++++++++++++++++++++++++ > libffi/src/riscv/ffitarget.h | 68 +++++++ > libffi/src/riscv/sysv.S | 214 +++++++++++++++++++++ > 6 files changed, 757 insertions(+), 2 deletions(-) > create mode 100644 libffi/src/riscv/ffi.c > create mode 100644 libffi/src/riscv/ffitarget.h > create mode 100644 libffi/src/riscv/sysv.S > > diff --git a/libffi/Makefile.am b/libffi/Makefile.am > index dc43328536..37f5ecaf3c 100644 > --- a/libffi/Makefile.am > +++ b/libffi/Makefile.am > @@ -138,6 +138,7 @@ noinst_HEADERS = \ > src/or1k/ffitarget.h > \ > src/pa/ffitarget.h > \ > src/powerpc/ffitarget.h src/powerpc/asm.h > src/powerpc/ffi_powerpc.h \ > + src/riscv/ffitarget.h > \ > src/s390/ffitarget.h > \ > src/sh/ffitarget.h > \ > src/sh64/ffitarget.h > \ > @@ -173,6 +174,7 @@ EXTRA_libffi_la_SOURCES = \ > src/powerpc/linux64_closure.S src/powerpc/ppc_closure.S > \ > src/powerpc/aix.S src/powerpc/darwin.S > src/powerpc/aix_closure.S \ > src/powerpc/darwin_closure.S src/powerpc/ffi_darwin.c > \ > + src/riscv/ffi.c src/riscv/sysv.S > \ > src/s390/ffi.c src/s390/sysv.S > \ > src/sh/ffi.c src/sh/sysv.S > \ > src/sh64/ffi.c src/sh64/sysv.S > \ > diff --git a/libffi/Makefile.in b/libffi/Makefile.in > index 8a99ee58b6..d395d3a8d3 100644 > --- a/libffi/Makefile.in > +++ b/libffi/Makefile.in > @@ -432,6 +432,7 @@ noinst_HEADERS = \ > src/or1k/ffitarget.h > \ > src/pa/ffitarget.h > \ > src/powerpc/ffitarget.h src/powerpc/asm.h > src/powerpc/ffi_powerpc.h \ > + src/riscv/ffitarget.h > \ > src/s390/ffitarget.h > \ > src/sh/ffitarget.h > \ > src/sh64/ffitarget.h > \ > @@ -467,6 +468,7 @@ EXTRA_libffi_la_SOURCES = \ > src/powerpc/linux64_closure.S src/powerpc/ppc_closure.S > \ > src/powerpc/aix.S src/powerpc/darwin.S > src/powerpc/aix_closure.S \ > src/powerpc/darwin_closure.S src/powerpc/ffi_darwin.c > \ > + src/riscv/ffi.c src/riscv/sysv.S > \ > src/s390/ffi.c src/s390/sysv.S > \ > src/sh/ffi.c src/sh/sysv.S > \ > src/sh64/ffi.c src/sh64/sysv.S > \ > @@ -831,6 +833,16 @@ src/powerpc/darwin_closure.lo: > src/powerpc/$(am__dirstamp) \ > src/powerpc/$(DEPDIR)/$(am__dirstamp) > src/powerpc/ffi_darwin.lo: src/powerpc/$(am__dirstamp) \ > src/powerpc/$(DEPDIR)/$(am__dirstamp) > +src/riscv/$(am__dirstamp): > + @$(MKDIR_P) src/riscv > + @: > src/riscv/$(am__dirstamp) > +src/riscv/$(DEPDIR)/$(am__dirstamp): > + @$(MKDIR_P) src/riscv/$(DEPDIR) > + @: > src/riscv/$(DEPDIR)/$(am__dirstamp) > +src/riscv/ffi.lo: src/riscv/$(am__dirstamp) \ > + src/riscv/$(DEPDIR)/$(am__dirstamp) > +src/riscv/sysv.lo: src/riscv/$(am__dirstamp) \ > + src/riscv/$(DEPDIR)/$(am__dirstamp) > src/s390/$(am__dirstamp): > @$(MKDIR_P) src/s390 > @: > src/s390/$(am__dirstamp) > @@ -1051,6 +1063,10 @@ mostlyclean-compile: > -rm -f src/prep_cif.lo > -rm -f src/raw_api.$(OBJEXT) > -rm -f src/raw_api.lo > + -rm -f src/riscv/ffi.$(OBJEXT) > + -rm -f src/riscv/ffi.lo > + -rm -f src/riscv/sysv.$(OBJEXT) > + -rm -f src/riscv/sysv.lo > -rm -f src/s390/ffi.$(OBJEXT) > -rm -f src/s390/ffi.lo > -rm -f src/s390/sysv.$(OBJEXT) > @@ -1167,6 +1183,8 @@ distclean-compile: > @AMDEP_TRUE@@am__include@ @am__quote@src/powerpc/$(DEPDIR)/linux64_c > losure.Plo@am__quote@ > @AMDEP_TRUE@@am__include@ @am__quote@src/powerpc/$(DEPDIR)/ppc_closu > re.Plo@am__quote@ > @AMDEP_TRUE@@am__include@ @am__quote@src/powerpc/$(DEPDIR)/sysv.Plo@ > am__quote@ > +@AMDEP_TRUE@@am__include@ @am__quote@src/riscv/$(DEPDIR)/ffi.Plo@am_ > _quote@ > +@AMDEP_TRUE@@am__include@ @am__quote@src/riscv/$(DEPDIR)/sysv.Plo@am > __quote@ > @AMDEP_TRUE@@am__include@ @am__quote@src/s390/$(DEPDIR)/ffi.Plo@am__ > quote@ > @AMDEP_TRUE@@am__include@ @am__quote@src/s390/$(DEPDIR)/sysv.Plo@am_ > _quote@ > @AMDEP_TRUE@@am__include@ @am__quote@src/sh/$(DEPDIR)/ffi.Plo@am__qu > ote@ > @@ -1268,6 +1286,7 @@ clean-libtool: > -rm -rf src/or1k/.libs src/or1k/_libs > -rm -rf src/pa/.libs src/pa/_libs > -rm -rf src/powerpc/.libs src/powerpc/_libs > + -rm -rf src/riscv/.libs src/riscv/_libs > -rm -rf src/s390/.libs src/s390/_libs > -rm -rf src/sh/.libs src/sh/_libs > -rm -rf src/sh64/.libs src/sh64/_libs > @@ -1672,6 +1691,8 @@ distclean-generic: > -rm -f src/pa/$(am__dirstamp) > -rm -f src/powerpc/$(DEPDIR)/$(am__dirstamp) > -rm -f src/powerpc/$(am__dirstamp) > + -rm -f src/riscv/$(DEPDIR)/$(am__dirstamp) > + -rm -f src/riscv/$(am__dirstamp) > -rm -f src/s390/$(DEPDIR)/$(am__dirstamp) > -rm -f src/s390/$(am__dirstamp) > -rm -f src/sh/$(DEPDIR)/$(am__dirstamp) > @@ -1701,7 +1722,7 @@ clean-am: clean-aminfo clean-generic clean- > libtool \ > > distclean: distclean-multi distclean-recursive > -rm -f $(am__CONFIG_DISTCLEAN_FILES) > - -rm -rf src/$(DEPDIR) src/aarch64/$(DEPDIR) > src/alpha/$(DEPDIR) src/arc/$(DEPDIR) src/arm/$(DEPDIR) > src/avr32/$(DEPDIR) src/bfin/$(DEPDIR) src/cris/$(DEPDIR) > src/frv/$(DEPDIR) src/ia64/$(DEPDIR) src/m32r/$(DEPDIR) > src/m68k/$(DEPDIR) src/m88k/$(DEPDIR) src/metag/$(DEPDIR) > src/microblaze/$(DEPDIR) src/mips/$(DEPDIR) src/moxie/$(DEPDIR) > src/nios2/$(DEPDIR) src/or1k/$(DEPDIR) src/pa/$(DEPDIR) > src/powerpc/$(DEPDIR) src/s390/$(DEPDIR) src/sh/$(DEPDIR) > src/sh64/$(DEPDIR) src/sparc/$(DEPDIR) src/tile/$(DEPDIR) > src/vax/$(DEPDIR) src/x86/$(DEPDIR) src/xtensa/$(DEPDIR) > + -rm -rf src/$(DEPDIR) src/aarch64/$(DEPDIR) > src/alpha/$(DEPDIR) src/arc/$(DEPDIR) src/arm/$(DEPDIR) > src/avr32/$(DEPDIR) src/bfin/$(DEPDIR) src/cris/$(DEPDIR) > src/frv/$(DEPDIR) src/ia64/$(DEPDIR) src/m32r/$(DEPDIR) > src/m68k/$(DEPDIR) src/m88k/$(DEPDIR) src/metag/$(DEPDIR) > src/microblaze/$(DEPDIR) src/mips/$(DEPDIR) src/moxie/$(DEPDIR) > src/nios2/$(DEPDIR) src/or1k/$(DEPDIR) src/pa/$(DEPDIR) > src/powerpc/$(DEPDIR) src/riscv/$(DEPDIR) src/s390/$(DEPDIR) > src/sh/$(DEPDIR) src/sh64/$(DEPDIR) src/sparc/$(DEPDIR) > src/tile/$(DEPDIR) src/vax/$(DEPDIR) src/x86/$(DEPDIR) > src/xtensa/$(DEPDIR) > -rm -f Makefile > distclean-am: clean-am distclean-compile distclean-generic \ > distclean-hdr distclean-libtool distclean-tags > @@ -1840,7 +1861,7 @@ installcheck-am: > maintainer-clean: maintainer-clean-multi maintainer-clean-recursive > -rm -f $(am__CONFIG_DISTCLEAN_FILES) > -rm -rf $(top_srcdir)/autom4te.cache > - -rm -rf src/$(DEPDIR) src/aarch64/$(DEPDIR) > src/alpha/$(DEPDIR) src/arc/$(DEPDIR) src/arm/$(DEPDIR) > src/avr32/$(DEPDIR) src/bfin/$(DEPDIR) src/cris/$(DEPDIR) > src/frv/$(DEPDIR) src/ia64/$(DEPDIR) src/m32r/$(DEPDIR) > src/m68k/$(DEPDIR) src/m88k/$(DEPDIR) src/metag/$(DEPDIR) > src/microblaze/$(DEPDIR) src/mips/$(DEPDIR) src/moxie/$(DEPDIR) > src/nios2/$(DEPDIR) src/or1k/$(DEPDIR) src/pa/$(DEPDIR) > src/powerpc/$(DEPDIR) src/s390/$(DEPDIR) src/sh/$(DEPDIR) > src/sh64/$(DEPDIR) src/sparc/$(DEPDIR) src/tile/$(DEPDIR) > src/vax/$(DEPDIR) src/x86/$(DEPDIR) src/xtensa/$(DEPDIR) > + -rm -rf src/$(DEPDIR) src/aarch64/$(DEPDIR) > src/alpha/$(DEPDIR) src/arc/$(DEPDIR) src/arm/$(DEPDIR) > src/avr32/$(DEPDIR) src/bfin/$(DEPDIR) src/cris/$(DEPDIR) > src/frv/$(DEPDIR) src/ia64/$(DEPDIR) src/m32r/$(DEPDIR) > src/m68k/$(DEPDIR) src/m88k/$(DEPDIR) src/metag/$(DEPDIR) > src/microblaze/$(DEPDIR) src/mips/$(DEPDIR) src/moxie/$(DEPDIR) > src/nios2/$(DEPDIR) src/or1k/$(DEPDIR) src/pa/$(DEPDIR) > src/powerpc/$(DEPDIR) src/riscv/$(DEPDIR) src/s390/$(DEPDIR) > src/sh/$(DEPDIR) src/sh64/$(DEPDIR) src/sparc/$(DEPDIR) > src/tile/$(DEPDIR) src/vax/$(DEPDIR) src/x86/$(DEPDIR) > src/xtensa/$(DEPDIR) > -rm -f Makefile > maintainer-clean-am: distclean-am maintainer-clean-aminfo \ > maintainer-clean-generic maintainer-clean-vti > diff --git a/libffi/configure.host b/libffi/configure.host > index 24fbfc438f..786b32c5bb 100644 > --- a/libffi/configure.host > +++ b/libffi/configure.host > @@ -195,6 +195,11 @@ case "${host}" in > TARGET=POWERPC; TARGETDIR=powerpc > ;; > > + riscv*-*) > + TARGET=RISCV; TARGETDIR=riscv > + SOURCES="ffi.c sysv.S" > + ;; > + > s390-*-* | s390x-*-*) > TARGET=S390; TARGETDIR=s390 > SOURCES="ffi.c sysv.S" > diff --git a/libffi/src/riscv/ffi.c b/libffi/src/riscv/ffi.c > new file mode 100644 > index 0000000000..b664ee7d4e > --- /dev/null > +++ b/libffi/src/riscv/ffi.c > @@ -0,0 +1,445 @@ > +/* --------------------------------------------------------------- > -------- > + ffi.c - Copyright (c) 2015 Michael Knyszek <mknys...@berkeley.edu > > > + 2015 Andrew Waterman <waterman@cs.berkeley. > edu> > + 2018 Stef O'Rear <sore...@gmail.com> > + 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> > + > +#if __riscv_float_abi_double > +#define ABI_FLEN 64 > +#define ABI_FLOAT double > +#elif __riscv_float_abi_single > +#define ABI_FLEN 32 > +#define ABI_FLOAT float > +#endif > + > +#define NARGREG 8 > +#define STKALIGN 16 > +#define MAXCOPYARG (2 * sizeof(double)) > + > +typedef struct call_context > +{ > +#if ABI_FLEN > + ABI_FLOAT fa[8]; > +#endif > + size_t a[8]; > + /* used by the assembly code to in-place construct its own stack > frame */ > + char frame[16]; > +} call_context; > + > +typedef struct call_builder > +{ > + call_context *aregs; > + int used_integer; > + int used_float; > + size_t *used_stack; > +} call_builder; > + > +/* integer (not pointer) less than ABI XLEN */ > +/* FFI_TYPE_INT does not appear to be used */ > +#if __SIZEOF_POINTER__ == 8 > +#define IS_INT(type) ((type) >= FFI_TYPE_UINT8 && (type) <= > FFI_TYPE_SINT64) > +#else > +#define IS_INT(type) ((type) >= FFI_TYPE_UINT8 && (type) <= > FFI_TYPE_SINT32) > +#endif > + > +#if ABI_FLEN > +typedef struct { > + char as_elements, type1, offset2, type2; > +} float_struct_info; > + > +#if ABI_FLEN >= 64 > +#define IS_FLOAT(type) ((type) >= FFI_TYPE_FLOAT && (type) <= > FFI_TYPE_DOUBLE) > +#else > +#define IS_FLOAT(type) ((type) == FFI_TYPE_FLOAT) > +#endif > + > +static ffi_type **flatten_struct(ffi_type *in, ffi_type **out, > ffi_type **out_end) { > + int i; > + if (out == out_end) return out; > + if (in->type != FFI_TYPE_STRUCT) { > + *(out++) = in; > + } else { > + for (i = 0; in->elements[i]; i++) > + out = flatten_struct(in->elements[i], out, out_end); > + } > + return out; > +} > + > +/* Structs with at most two fields after flattening, one of which is > of > + floating point type, are passed in multiple registers if > sufficient > + registers are available. */ > +static float_struct_info struct_passed_as_elements(call_builder *cb, > ffi_type *top) { > + float_struct_info ret = {0, 0, 0, 0}; > + ffi_type *fields[3]; > + int num_floats, num_ints; > + int num_fields = flatten_struct(top, fields, fields + 3) - > fields; > + > + if (num_fields == 1) { > + if (IS_FLOAT(fields[0]->type)) { > + ret.as_elements = 1; > + ret.type1 = fields[0]->type; > + } > + } else if (num_fields == 2) { > + num_floats = IS_FLOAT(fields[0]->type) + IS_FLOAT(fields[1]- > >type); > + num_ints = IS_INT(fields[0]->type) + IS_INT(fields[1]- > >type); > + if (num_floats == 0 || num_floats + num_ints != 2) > + return ret; > + if (cb->used_float + num_floats > NARGREG || cb- > >used_integer + (2 - num_floats) > NARGREG) > + return ret; > + if (!IS_FLOAT(fields[0]->type) && !IS_FLOAT(fields[1]- > >type)) > + return ret; > + > + ret.type1 = fields[0]->type; > + ret.type2 = fields[1]->type; > + ret.offset2 = ALIGN(fields[0]->size, fields[1]->alignment); > + ret.as_elements = 1; > + } > + > + return ret; > +} > +#endif > + > +/* allocates a single register, float register, or XLEN-sized stack > slot to a datum */ > +static void marshal_atom(call_builder *cb, int type, void *data) { > + size_t value = 0; > + switch (type) { > + case FFI_TYPE_UINT8: value = *(uint8_t *)data; break; > + case FFI_TYPE_SINT8: value = *(int8_t *)data; break; > + case FFI_TYPE_UINT16: value = *(uint16_t *)data; break; > + case FFI_TYPE_SINT16: value = *(int16_t *)data; break; > + /* 32-bit quantities are always sign-extended in the ABI */ > + case FFI_TYPE_UINT32: value = *(int32_t *)data; break; > + case FFI_TYPE_SINT32: value = *(int32_t *)data; break; > +#if __SIZEOF_POINTER__ == 8 > + case FFI_TYPE_UINT64: value = *(uint64_t *)data; break; > + case FFI_TYPE_SINT64: value = *(int64_t *)data; break; > +#endif > + case FFI_TYPE_POINTER: value = *(size_t *)data; break; > + > + /* float values may be recoded in an implementation-defined > way > + by hardware conforming to 2.1 or earlier, so use asm to > + reinterpret floats as doubles */ > +#if ABI_FLEN >= 32 > + case FFI_TYPE_FLOAT: > + asm("" : "=f"(cb->aregs->fa[cb->used_float++]) : > "0"(*(float *)data)); > + return; > +#endif > +#if ABI_FLEN >= 64 > + case FFI_TYPE_DOUBLE: > + asm("" : "=f"(cb->aregs->fa[cb->used_float++]) : > "0"(*(double *)data)); > + return; > +#endif > + default: FFI_ASSERT(0); break; > + } > + > + if (cb->used_integer == NARGREG) { > + *cb->used_stack++ = value; > + } else { > + cb->aregs->a[cb->used_integer++] = value; > + } > +} > + > +static void unmarshal_atom(call_builder *cb, int type, void *data) { > + size_t value; > + switch (type) { > +#if ABI_FLEN >= 32 > + case FFI_TYPE_FLOAT: > + asm("" : "=f"(*(float *)data) : "0"(cb->aregs->fa[cb- > >used_float++])); > + return; > +#endif > +#if ABI_FLEN >= 64 > + case FFI_TYPE_DOUBLE: > + asm("" : "=f"(*(double *)data) : "0"(cb->aregs->fa[cb- > >used_float++])); > + return; > +#endif > + } > + > + if (cb->used_integer == NARGREG) { > + value = *cb->used_stack++; > + } else { > + value = cb->aregs->a[cb->used_integer++]; > + } > + > + switch (type) { > + case FFI_TYPE_UINT8: *(uint8_t *)data = value; break; > + case FFI_TYPE_SINT8: *(uint8_t *)data = value; break; > + case FFI_TYPE_UINT16: *(uint16_t *)data = value; break; > + case FFI_TYPE_SINT16: *(uint16_t *)data = value; break; > + case FFI_TYPE_UINT32: *(uint32_t *)data = value; break; > + case FFI_TYPE_SINT32: *(uint32_t *)data = value; break; > +#if __SIZEOF_POINTER__ == 8 > + case FFI_TYPE_UINT64: *(uint64_t *)data = value; break; > + case FFI_TYPE_SINT64: *(uint64_t *)data = value; break; > +#endif > + case FFI_TYPE_POINTER: *(size_t *)data = value; break; > + default: FFI_ASSERT(0); break; > + } > +} > + > +/* adds an argument to a call, or a not by reference return value */ > +static void marshal(call_builder *cb, ffi_type *type, int var, void > *data) { > + size_t realign[2]; > + > +#if ABI_FLEN > + if (!var && type->type == FFI_TYPE_STRUCT) { > + float_struct_info fsi = struct_passed_as_elements(cb, type); > + if (fsi.as_elements) { > + marshal_atom(cb, fsi.type1, data); > + if (fsi.offset2) > + marshal_atom(cb, fsi.type2, ((char*)data) + > fsi.offset2); > + return; > + } > + } > + > + if (!var && cb->used_float < NARGREG && IS_FLOAT(type->type)) { > + marshal_atom(cb, type->type, data); > + return; > + } > +#endif > + > + if (type->size > 2 * __SIZEOF_POINTER__) { > + /* pass by reference */ > + marshal_atom(cb, FFI_TYPE_POINTER, &data); > + } else if (IS_INT(type->type) || type->type == FFI_TYPE_POINTER) > { > + marshal_atom(cb, type->type, data); > + } else { > + /* overlong integers, soft-float floats, and structs without > special > + float handling are treated identically from this point on > */ > + > + /* variadics are aligned even in registers */ > + if (type->alignment > __SIZEOF_POINTER__) { > + if (var) > + cb->used_integer = ALIGN(cb->used_integer, 2); > + cb->used_stack = (size_t *)ALIGN(cb->used_stack, > 2*__SIZEOF_POINTER__); > + } > + > + memcpy(realign, data, type->size); > + if (type->size > 0) > + marshal_atom(cb, FFI_TYPE_POINTER, realign); > + if (type->size > __SIZEOF_POINTER__) > + marshal_atom(cb, FFI_TYPE_POINTER, realign + 1); > + } > +} > + > +/* for arguments passed by reference returns the pointer, otherwise > the arg is copied (up to MAXCOPYARG bytes) */ > +static void *unmarshal(call_builder *cb, ffi_type *type, int var, > void *data) { > + size_t realign[2]; > + void *pointer; > + > +#if ABI_FLEN > + if (!var && type->type == FFI_TYPE_STRUCT) { > + float_struct_info fsi = struct_passed_as_elements(cb, type); > + if (fsi.as_elements) { > + unmarshal_atom(cb, fsi.type1, data); > + if (fsi.offset2) > + unmarshal_atom(cb, fsi.type2, ((char*)data) + > fsi.offset2); > + return data; > + } > + } > + > + if (!var && cb->used_float < NARGREG && IS_FLOAT(type->type)) { > + unmarshal_atom(cb, type->type, data); > + return data; > + } > +#endif > + > + if (type->size > 2 * __SIZEOF_POINTER__) { > + /* pass by reference */ > + unmarshal_atom(cb, FFI_TYPE_POINTER, (char*)&pointer); > + return pointer; > + } else if (IS_INT(type->type) || type->type == FFI_TYPE_POINTER) > { > + unmarshal_atom(cb, type->type, data); > + return data; > + } else { > + /* overlong integers, soft-float floats, and structs without > special > + float handling are treated identically from this point on > */ > + > + /* variadics are aligned even in registers */ > + if (type->alignment > __SIZEOF_POINTER__) { > + if (var) > + cb->used_integer = ALIGN(cb->used_integer, 2); > + cb->used_stack = (size_t *)ALIGN(cb->used_stack, > 2*__SIZEOF_POINTER__); > + } > + > + if (type->size > 0) > + unmarshal_atom(cb, FFI_TYPE_POINTER, realign); > + if (type->size > __SIZEOF_POINTER__) > + unmarshal_atom(cb, FFI_TYPE_POINTER, realign + 1); > + memcpy(data, realign, type->size); > + return data; > + } > +} > + > +static int passed_by_ref(call_builder *cb, ffi_type *type, int var) > { > +#if ABI_FLEN > + if (!var && type->type == FFI_TYPE_STRUCT) { > + float_struct_info fsi = struct_passed_as_elements(cb, type); > + if (fsi.as_elements) return 0; > + } > +#endif > + > + return type->size > 2 * __SIZEOF_POINTER__; > +} > + > +/* Perform machine dependent cif processing */ > +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) { > + cif->riscv_nfixedargs = cif->nargs; > + 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) { > + cif->riscv_nfixedargs = nfixedargs; > + return FFI_OK; > +} > + > +/* Low level routine for calling functions */ > +extern void ffi_call_asm(void *stack, struct call_context *regs, > void (*fn)(void)) FFI_HIDDEN; > + > +void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void > **avalue) > +{ > + /* this is a conservative estimate, assuming a complex return > value and > + that all remaining arguments are long long / __int128 */ > + size_t arg_bytes = cif->nargs <= 3 ? 0 : > + ALIGN(2 * sizeof(size_t) * (cif->nargs - 3), STKALIGN); > + size_t rval_bytes = 0; > + if (rvalue == NULL && cif->rtype->size > 2*__SIZEOF_POINTER__) > + rval_bytes = ALIGN(cif->rtype->size, STKALIGN); > + size_t alloc_size = arg_bytes + rval_bytes + > sizeof(call_context); > + > + /* the assembly code will deallocate all stack data at lower > addresses > + than the argument region, so we need to allocate the frame > and the > + return value after the arguments in a single allocation */ > + size_t alloc_base; > + /* Argument region must be 16-byte aligned */ > + if (_Alignof(max_align_t) >= STKALIGN) { > + /* since sizeof long double is normally 16, the compiler > will > + guarantee alloca alignment to at least that much */ > + alloc_base = (size_t)alloca(alloc_size); > + } else { > + alloc_base = ALIGN(alloca(alloc_size + STKALIGN - 1), > STKALIGN); > + } > + > + if (rval_bytes) > + rvalue = (void*)(alloc_base + arg_bytes); > + > + call_builder cb; > + cb.used_float = cb.used_integer = 0; > + cb.aregs = (call_context*)(alloc_base + arg_bytes + rval_bytes); > + cb.used_stack = (void*)alloc_base; > + > + int return_by_ref = passed_by_ref(&cb, cif->rtype, 0); > + if (return_by_ref) > + marshal(&cb, &ffi_type_pointer, 0, &rvalue); > + > + int i; > + for (i = 0; i < cif->nargs; i++) > + marshal(&cb, cif->arg_types[i], i >= cif->riscv_nfixedargs, > avalue[i]); > + > + ffi_call_asm((void*)alloc_base, cb.aregs, fn); > + > + cb.used_float = cb.used_integer = 0; > + if (!return_by_ref && rvalue) > + unmarshal(&cb, cif->rtype, 0, rvalue); > +} > + > +extern void ffi_closure_asm(void) FFI_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) > +{ > + uint32_t *tramp = (uint32_t *) &closure->tramp[0]; > + uint64_t fn = (uint64_t) (uintptr_t) ffi_closure_asm; > + > + if (cif->abi <= FFI_FIRST_ABI || cif->abi >= FFI_LAST_ABI) > + return FFI_BAD_ABI; > + > + /* we will call ffi_closure_inner with codeloc, not closure, but > as long > + as the memory is readable it should work */ > + > + tramp[0] = 0x00000317; /* auipc t1, 0 (i.e. t0 <- codeloc) */ > +#if __SIZEOF_POINTER__ == 8 > + tramp[1] = 0x01033383; /* ld t2, 16(t1) */ > +#else > + tramp[1] = 0x01032383; /* lw t2, 16(t1) */ > +#endif > + tramp[2] = 0x00038067; /* jr t2 */ > + tramp[3] = 0x00000013; /* nop */ > + 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; > +} > + > +/* Called by the assembly code with aregs pointing to saved argument > registers > + and stack pointing to the stacked arguments. Return values > passed in > + registers will be reloaded from aregs. */ > +void FFI_HIDDEN ffi_closure_inner(size_t *stack, call_context > *aregs, ffi_closure *closure) { > + ffi_cif *cif = closure->cif; > + void **avalue = alloca(cif->nargs * sizeof(void*)); > + /* storage for arguments which will be copied by > unmarshal(). We could > + theoretically avoid the copies in many cases and use at most > 128 bytes > + of memory, but allocating disjoint storage for each argument > is > + simpler. */ > + char *astorage = alloca(cif->nargs * MAXCOPYARG); > + void *rvalue; > + call_builder cb; > + int return_by_ref; > + int i; > + > + cb.aregs = aregs; > + cb.used_integer = cb.used_float = 0; > + cb.used_stack = stack; > + > + return_by_ref = passed_by_ref(&cb, cif->rtype, 0); > + if (return_by_ref) > + unmarshal(&cb, &ffi_type_pointer, 0, &rvalue); > + else > + rvalue = alloca(cif->rtype->size); > + > + for (i = 0; i < cif->nargs; i++) > + avalue[i] = unmarshal(&cb, cif->arg_types[i], > + i >= cif->riscv_nfixedargs, astorage + i*MAXCOPYARG); > + > + (closure->fun)(cif, rvalue, avalue, closure->user_data); > + > + if (!return_by_ref && cif->rtype->type != FFI_TYPE_VOID) { > + cb.used_integer = cb.used_float = 0; > + marshal(&cb, cif->rtype, 0, rvalue); > + } > +} > diff --git a/libffi/src/riscv/ffitarget.h > b/libffi/src/riscv/ffitarget.h > new file mode 100644 > index 0000000000..fcaa899153 > --- /dev/null > +++ b/libffi/src/riscv/ffitarget.h > @@ -0,0 +1,68 @@ > +/* --------------------------------------------------------------- > --*-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 > + > +#ifndef __riscv > +#error "libffi was configured for a RISC-V target but this does not > appear to be a RISC-V compiler." > +#endif > + > +#ifndef LIBFFI_ASM > + > +typedef unsigned long ffi_arg; > +typedef signed long ffi_sarg; > + > +/* FFI_UNUSED_NN and riscv_unused are to maintain ABI compatibility > with a > + distributed Berkeley patch from 2014, and can be removed at > SONAME bump */ > +typedef enum ffi_abi { > + FFI_FIRST_ABI = 0, > + FFI_SYSV, > + FFI_UNUSED_1, > + FFI_UNUSED_2, > + FFI_UNUSED_3, > + FFI_LAST_ABI, > + > + FFI_DEFAULT_ABI = FFI_SYSV > +} ffi_abi; > + > +#endif /* LIBFFI_ASM */ > + > +/* ---- Definitions for closures --------------------------------- > -------- */ > + > +#define FFI_CLOSURES 1 > +#define FFI_TRAMPOLINE_SIZE 24 > +#define FFI_NATIVE_RAW_API 0 > +#define FFI_EXTRA_CIF_FIELDS unsigned riscv_nfixedargs; unsigned > riscv_unused; > +#define FFI_TARGET_SPECIFIC_VARIADIC > + > +#endif > + > diff --git a/libffi/src/riscv/sysv.S b/libffi/src/riscv/sysv.S > new file mode 100644 > index 0000000000..2d098651d0 > --- /dev/null > +++ b/libffi/src/riscv/sysv.S > @@ -0,0 +1,214 @@ > +/* --------------------------------------------------------------- > -------- > + ffi.c - Copyright (c) 2015 Michael Knyszek <mknys...@berkeley.edu > > > + 2015 Andrew Waterman <waterman@cs.berkeley. > edu> > + 2018 Stef O'Rear <sore...@gmail.com> > + > + 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 aliases so that we can handle all ABIs uniformly */ > + > +#if __SIZEOF_POINTER__ == 8 > +#define PTRS 8 > +#define LARG ld > +#define SARG sd > +#else > +#define PTRS 4 > +#define LARG lw > +#define SARG sw > +#endif > + > +#if __riscv_float_abi_double > +#define FLTS 8 > +#define FLARG fld > +#define FSARG fsd > +#elif __riscv_float_abi_single > +#define FLTS 4 > +#define FLARG flw > +#define FSARG fsw > +#else > +#define FLTS 0 > +#endif > + > +#define fp s0 > + > + .text > + .globl ffi_call_asm > + .type ffi_call_asm, @function > + .hidden ffi_call_asm > +/* > + struct call_context { > + floatreg fa[8]; > + intreg a[8]; > + intreg pad[rv32 ? 2 : 0]; > + intreg save_fp, save_ra; > + } > + void ffi_call_asm(size_t *stackargs, struct call_context *regargs, > + void (*fn)(void)); > +*/ > + > +#define FRAME_LEN (8 * FLTS + 8 * PTRS + 16) > + > +ffi_call_asm: > + .cfi_startproc > + > + /* > + We are NOT going to set up an ordinary stack frame. In order > to pass > + the stacked args to the called function, we adjust our stack > pointer to > + a0, which is in the _caller's_ alloca area. We establish our > own stack > + frame at the end of the call_context. > + > + Anything below the arguments will be freed at this point, > although we > + preserve the call_context so that it can be read back in the > caller. > + */ > + > + .cfi_def_cfa 11, FRAME_LEN # interim CFA based on a1 > + SARG fp, FRAME_LEN - 2*PTRS(a1) > + .cfi_offset 8, -2*PTRS > + SARG ra, FRAME_LEN - 1*PTRS(a1) > + .cfi_offset 1, -1*PTRS > + > + addi fp, a1, FRAME_LEN > + mv sp, a0 > + .cfi_def_cfa 8, 0 # our frame is fully set up > + > + # Load arguments > + mv t1, a2 > + > +#if FLTS > + FLARG fa0, -FRAME_LEN+0*FLTS(fp) > + FLARG fa1, -FRAME_LEN+1*FLTS(fp) > + FLARG fa2, -FRAME_LEN+2*FLTS(fp) > + FLARG fa3, -FRAME_LEN+3*FLTS(fp) > + FLARG fa4, -FRAME_LEN+4*FLTS(fp) > + FLARG fa5, -FRAME_LEN+5*FLTS(fp) > + FLARG fa6, -FRAME_LEN+6*FLTS(fp) > + FLARG fa7, -FRAME_LEN+7*FLTS(fp) > +#endif > + > + LARG a0, -FRAME_LEN+8*FLTS+0*PTRS(fp) > + LARG a1, -FRAME_LEN+8*FLTS+1*PTRS(fp) > + LARG a2, -FRAME_LEN+8*FLTS+2*PTRS(fp) > + LARG a3, -FRAME_LEN+8*FLTS+3*PTRS(fp) > + LARG a4, -FRAME_LEN+8*FLTS+4*PTRS(fp) > + LARG a5, -FRAME_LEN+8*FLTS+5*PTRS(fp) > + LARG a6, -FRAME_LEN+8*FLTS+6*PTRS(fp) > + LARG a7, -FRAME_LEN+8*FLTS+7*PTRS(fp) > + > + /* Call */ > + jalr t1 > + > + /* Save return values - only a0/a1 (fa0/fa1) are used */ > +#if FLTS > + FSARG fa0, -FRAME_LEN+0*FLTS(fp) > + FSARG fa1, -FRAME_LEN+1*FLTS(fp) > +#endif > + > + SARG a0, -FRAME_LEN+8*FLTS+0*PTRS(fp) > + SARG a1, -FRAME_LEN+8*FLTS+1*PTRS(fp) > + > + /* Restore and return */ > + addi sp, fp, -FRAME_LEN > + .cfi_def_cfa 2, FRAME_LEN > + LARG ra, -1*PTRS(fp) > + .cfi_restore 1 > + LARG fp, -2*PTRS(fp) > + .cfi_restore 8 > + ret > + .cfi_endproc > + .size ffi_call_asm, .-ffi_call_asm > + > + > +/* > + ffi_closure_asm. Expects address of the passed-in ffi_closure in > t1. > + void ffi_closure_inner(size_t *stackargs, struct call_context > *regargs, > + ffi_closure *closure); > +*/ > + > + .globl ffi_closure_asm > + .hidden ffi_closure_asm > + .type ffi_closure_asm, @function > +ffi_closure_asm: > + .cfi_startproc > + > + addi sp, sp, -FRAME_LEN > + .cfi_def_cfa_offset FRAME_LEN > + > + /* make a frame */ > + SARG fp, FRAME_LEN - 2*PTRS(sp) > + .cfi_offset 8, -2*PTRS > + SARG ra, FRAME_LEN - 1*PTRS(sp) > + .cfi_offset 1, -1*PTRS > + addi fp, sp, FRAME_LEN > + > + /* save arguments */ > +#if FLTS > + FSARG fa0, 0*FLTS(sp) > + FSARG fa1, 1*FLTS(sp) > + FSARG fa2, 2*FLTS(sp) > + FSARG fa3, 3*FLTS(sp) > + FSARG fa4, 4*FLTS(sp) > + FSARG fa5, 5*FLTS(sp) > + FSARG fa6, 6*FLTS(sp) > + FSARG fa7, 7*FLTS(sp) > +#endif > + > + SARG a0, 8*FLTS+0*PTRS(sp) > + SARG a1, 8*FLTS+1*PTRS(sp) > + SARG a2, 8*FLTS+2*PTRS(sp) > + SARG a3, 8*FLTS+3*PTRS(sp) > + SARG a4, 8*FLTS+4*PTRS(sp) > + SARG a5, 8*FLTS+5*PTRS(sp) > + SARG a6, 8*FLTS+6*PTRS(sp) > + SARG a7, 8*FLTS+7*PTRS(sp) > + > + /* enter C */ > + addi a0, sp, FRAME_LEN > + mv a1, sp > + mv a2, t1 > + > + call ffi_closure_inner > + > + /* return values */ > +#if FLTS > + FLARG fa0, 0*FLTS(sp) > + FLARG fa1, 1*FLTS(sp) > +#endif > + > + LARG a0, 8*FLTS+0*PTRS(sp) > + LARG a1, 8*FLTS+1*PTRS(sp) > + > + /* restore and return */ > + LARG ra, FRAME_LEN-1*PTRS(sp) > + .cfi_restore 1 > + LARG fp, FRAME_LEN-2*PTRS(sp) > + .cfi_restore 8 > + addi sp, sp, FRAME_LEN > + .cfi_def_cfa_offset 0 > + ret > + .cfi_endproc > + .size ffi_closure_asm, .-ffi_closure_asm > -- > 2.16.2 > >