Group :: Sistema/Bibliotecas
RPM: libffcall
Main Changelog Spec Patches Sources Download Gear Bugs e FR Repocop
Patch: libffcall-2.4-e2k.patch
Download
Download
From 6c8a45113b96867a45881b4c70b3c1611ce58b37 Mon Sep 17 00:00:00 2001
From: Ilya Kurdyukov <jpegqs@gmail.com>
Date: Tue, 28 Dec 2021 18:06:12 +0700
Subject: [PATCH] libffcall-2.4 e2k support
LCC >= 1.25.18 or LCC >= 1.26.04 is required
for __clear_cache() to work properly
---
avcall/Makefile.in | 3 ++
avcall/avcall-e2k.c | 79 +++++++++++++++++++++++++++++
avcall/avcall-internal.h | 37 ++++++++++++++
callback/trampoline_r/test1.c | 3 ++
callback/trampoline_r/trampoline.c | 40 ++++++++++++++-
callback/vacall_r/Makefile.in | 3 ++
trampoline/trampoline.c | 43 +++++++++++++++-
vacall/Makefile.in | 3 ++
vacall/vacall-e2k.c | 81 ++++++++++++++++++++++++++++++
vacall/vacall-internal.h | 29 +++++++++++
10 files changed, 319 insertions(+), 2 deletions(-)
create mode 100644 avcall/avcall-e2k.c
create mode 100644 vacall/vacall-e2k.c
diff --git a/avcall/Makefile.in b/avcall/Makefile.in
index 466023d..0a646ee 100644
--- a/avcall/Makefile.in
+++ b/avcall/Makefile.in
@@ -164,6 +164,9 @@ avcall-arm64.s : $(srcdir)/avcall-arm64-macro.S $(srcdir)/avcall-arm64-macos-mac
esac; \
$(CPP) $(ASPFLAGS) -I$(srcdir)/../common $(srcdir)/$${input} | grep -v '^ *#line' | grep -v '^#' | sed -e 's,% ,%,g' -e 's,//,@,g' -e 's,\$$,#,g' > avcall-arm64.s
+avcall-e2k.lo : $(srcdir)/avcall-e2k.c
+ $(LIBTOOL_COMPILE) $(CC) -I$(srcdir)/.. $(CPPFLAGS) $(CFLAGS) -c $(srcdir)/avcall-e2k.c -o avcall-e2k.lo
+
avcall-powerpc.lo : avcall-powerpc.s
$(LIBTOOL_COMPILE) $(CC) @GCC_X_NONE@ -c avcall-powerpc.s
diff --git a/avcall/avcall-e2k.c b/avcall/avcall-e2k.c
new file mode 100644
index 0000000..a59c98b
--- /dev/null
+++ b/avcall/avcall-e2k.c
@@ -0,0 +1,79 @@
+/**
+ Copyright 2021 Ilya Kurdyukov <jpegqs@gmail.com> for BaseALT, Ltd
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+**/
+/*----------------------------------------------------------------------
+ Foreign function interface for Elbrus 2000 with LCC compiler.
+
+ This calls a C function with an argument list built up using macros
+ defined in avcall.h.
+ ----------------------------------------------------------------------*/
+#include "avcall-internal.h"
+#include <string.h>
+
+#define RETURN(TYPE) (*(TYPE*)l->raddr = (TYPE)ret.r[0]); break;
+
+typedef struct { __avword r[8]; } regs_t;
+
+#define STACK_EXTRA 8
+
+int
+avcall_call(av_alist* list)
+{
+ regs_t ret;
+ __av_alist* l = &AV_LIST_INNER(list);
+ /* make room for argument list */
+ __avword* argframe = __builtin_alloca((__AV_ALIST_WORDS - STACK_EXTRA) * sizeof(__avword));
+ int arglen = l->aptr - l->args;
+ __avword i;
+
+ /* skip the extra space generated by the compiler */
+ argframe -= STACK_EXTRA;
+
+ /* push function args onto stack */
+ for (i = 0; i < arglen; i++) argframe[i] = l->args[i];
+
+ /* call function */
+ ret = (*(regs_t(*)(regs_t))l->func)(*(regs_t*)argframe);
+
+ switch (l->rtype) {
+ case __AVvoid:
+ break;
+ case __AVchar:
+ case __AVschar:
+ case __AVuchar:
+ RETURN(char)
+ case __AVshort:
+ case __AVushort:
+ RETURN(short)
+ case __AVint:
+ case __AVuint:
+ case __AVfloat:
+ RETURN(int)
+ case __AVlong:
+ case __AVulong:
+ case __AVlonglong:
+ case __AVulonglong:
+ case __AVdouble:
+ RETURN(long)
+ case __AVvoidp:
+ RETURN(void*)
+ case __AVstruct:
+ if (l->rsize <= sizeof(ret)) *(regs_t*)argframe = ret;
+ memcpy(l->raddr, argframe, l->rsize);
+ break;
+ }
+ return 0;
+}
diff --git a/avcall/avcall-internal.h b/avcall/avcall-internal.h
index c878134..f36cb1f 100644
--- a/avcall/avcall-internal.h
+++ b/avcall/avcall-internal.h
@@ -1555,4 +1555,41 @@ extern void avcall_structcpy (void* dest, const void* src, unsigned long size, u
#endif
+#if defined(__e2k__)
+#define __av_start1(LIST,LIST_ARGS_END) \
+ (LIST).aptr = &(LIST).args[0],
+
+#define __av_word(LIST,VAL) \
+ ((LIST).aptr >= (LIST).eptr ? -1 : \
+ (*(LIST).aptr = (__avword)(VAL), (LIST).aptr++, 0))
+
+#define _av_double(LIST,VAL) \
+ ((LIST).aptr >= (LIST).eptr ? -1 : \
+ (*(double*)(LIST).aptr = (double)(VAL), (LIST).aptr++, 0))
+
+#define _av_float(LIST,VAL) \
+ ((LIST).aptr >= (LIST).eptr ? -1 : \
+ (*(float*)(LIST).aptr = (float)(VAL), \
+ ((float*)(LIST).aptr)[1] = 0, (LIST).aptr++, 0))
+
+#define __av_longlong __av_long
+#define __av_ulonglong __av_ulong
+
+#undef __av_start_struct2
+#define __av_start_struct2(LIST,TYPE_SIZE,TYPE_SPLITTABLE) 0
+
+#define __av_struct(LIST,TYPE_SIZE,TYPE_ALIGN,VAL) \
+ ((TYPE_SIZE) <= sizeof(__avword) \
+ ? ((LIST).aptr >= (LIST).eptr ? -1 : \
+ (__av_struct_copy(TYPE_SIZE,TYPE_ALIGN,(void*)(LIST).aptr,VAL), \
+ (LIST).aptr++, 0)) \
+ : ((__avword*)((((uintptr_t)(LIST).aptr+2*sizeof(__avword)-1) & -2*sizeof(__avword))+(TYPE_SIZE)) > (LIST).eptr \
+ ? -1 : \
+ ((LIST).aptr = (__avword*)(((uintptr_t)(LIST).aptr+2*sizeof(__avword)-1) & -2*sizeof(__avword)), \
+ __av_struct_copy(TYPE_SIZE,TYPE_ALIGN,(void*)(LIST).aptr,VAL), \
+ (LIST).aptr = (__avword*)(((uintptr_t)(LIST).aptr+(TYPE_SIZE)+sizeof(__avword)-1) & -sizeof(__avword)), \
+ 0)))
+#endif /* __e2k__ */
+
+
#endif /* _AVCALL_INTERNAL_H */
diff --git a/callback/trampoline_r/test1.c b/callback/trampoline_r/test1.c
index 4b2f9f8..c5feb27 100644
--- a/callback/trampoline_r/test1.c
+++ b/callback/trampoline_r/test1.c
@@ -81,6 +81,9 @@ register void* env __asm__("r10");
#if defined(__s390__) || defined(__s390x__)
register void* env __asm__("r0");
#endif
+#ifdef __e2k__
+register void* env __asm__("g16");
+#endif
#if defined(__riscv32__) || defined(__riscv64__)
register void* env __asm__("t2");
#endif
diff --git a/callback/trampoline_r/trampoline.c b/callback/trampoline_r/trampoline.c
index 5d4f8c2..0579369 100644
--- a/callback/trampoline_r/trampoline.c
+++ b/callback/trampoline_r/trampoline.c
@@ -326,6 +326,17 @@ static int open_noinherit (const char *filename, int flags, int mode)
#define TRAMP_LENGTH 32
#define TRAMP_ALIGN 8
#endif
+#ifdef __e2k__
+#define TRAMP_LENGTH 48
+#define TRAMP_ALIGN 64
+#ifdef EXECUTABLE_VIA_MALLOC_THEN_MPROTECT
+#undef EXECUTABLE_VIA_MALLOC_THEN_MPROTECT
+#define EXECUTABLE_VIA_MMAP
+#endif
+#ifndef MAP_VARIABLE
+#define MAP_VARIABLE 0
+#endif
+#endif
#ifndef TRAMP_BIAS
#define TRAMP_BIAS 0
@@ -1257,6 +1268,33 @@ __TR_function alloc_trampoline_r (__TR_function address, void* data0, void* data
(*(unsigned long *) (function +24))
#define tramp_data(function) \
(*(unsigned long *) (function +16))
+#endif
+#if defined(__e2k__)
+#define swaphilo(x) ((x) << 32 | (x) >> 32)
+ /* function:
+ * nop 7
+ * movtd,sm <address>, %ctpr1; ipd 2
+ * addd 0, <data>, %g16
+ *
+ * nop
+ *
+ * ct %ctpr1
+ */
+ *(long *) (function + 0) = 0x800000000C0013B3L;
+ *(long *) (function + 8) = 0x11C0DCF0E1C0DED1L;
+ *(long *) (function +16) = swaphilo((unsigned long) address);
+ *(long *) (function +24) = swaphilo((unsigned long) data);
+ *(long *) (function +32) = 0;
+ *(long *) (function +40) = 0xC000042000001001L;
+#define is_tramp(function) \
+ *(unsigned long *) (function + 0) == 0x800000000C0013B3L && \
+ *(unsigned long *) (function + 8) == 0x11C0DCF0E1C0DED1L && \
+ *(unsigned long *) (function +32) == 0 && \
+ *(unsigned long *) (function +40) == 0xC000042000001001L
+#define tramp_address(function) \
+ swaphilo(*(unsigned long *) (function +16))
+#define tramp_data(function) \
+ swaphilo(*(unsigned long *) (function +24))
#endif
/*
* data:
@@ -1382,7 +1420,7 @@ __TR_function alloc_trampoline_r (__TR_function address, void* data0, void* data
/* This assumes that the trampoline fits in at most two cache lines. */
__TR_clear_cache(function_x,function_x+TRAMP_CODE_LENGTH-1);
#endif
-#if defined(__arm__) || defined(__armhf__) || defined(__arm64__)
+#if defined(__arm__) || defined(__armhf__) || defined(__arm64__) || defined(__e2k__)
/* On ARM, cache flushing can only be done through a system call.
GCC implements it for Linux with EABI, through an "swi 0" with code
0xf0002. For other systems, it may be an "swi 0x9f0002",
diff --git a/callback/vacall_r/Makefile.in b/callback/vacall_r/Makefile.in
index 012f4d9..2223704 100644
--- a/callback/vacall_r/Makefile.in
+++ b/callback/vacall_r/Makefile.in
@@ -148,6 +148,9 @@ vacall-arm64.s : $(srcdir)/vacall-arm64-macro.S $(srcdir)/vacall-arm64-macos-mac
esac; \
$(CPP) $(ASPFLAGS) -I$(srcdir) -I$(srcdir)/../../common $(srcdir)/$${input} | grep -v '^ *#line' | grep -v '^#' | sed -e 's,% ,%,g' -e 's,//,@,g' -e 's,\$$,#,g' > vacall-arm64.s
+vacall-e2k.lo : $(srcdir)/../../vacall/vacall-e2k.c
+ $(LIBTOOL_COMPILE) $(CC) $(INCLUDES) -I$(srcdir)/../.. $(CPPFLAGS) $(CFLAGS) -DREENTRANT -c $(srcdir)/../../vacall/vacall-e2k.c -o vacall-e2k.lo
+
vacall-powerpc.lo : vacall-powerpc.s
$(LIBTOOL_COMPILE) $(CC) @GCC_X_NONE@ -c vacall-powerpc.s
diff --git a/trampoline/trampoline.c b/trampoline/trampoline.c
index 9b79e0d..a82dab3 100644
--- a/trampoline/trampoline.c
+++ b/trampoline/trampoline.c
@@ -330,6 +330,17 @@ static int open_noinherit (const char *filename, int flags, int mode)
#define TRAMP_LENGTH 48
#define TRAMP_ALIGN 8
#endif
+#ifdef __e2k__
+#define TRAMP_LENGTH 56
+#define TRAMP_ALIGN 64
+#ifdef EXECUTABLE_VIA_MALLOC_THEN_MPROTECT
+#undef EXECUTABLE_VIA_MALLOC_THEN_MPROTECT
+#define EXECUTABLE_VIA_MMAP
+#endif
+#ifndef MAP_VARIABLE
+#define MAP_VARIABLE 0
+#endif
+#endif
#ifndef TRAMP_BIAS
#define TRAMP_BIAS 0
@@ -1514,6 +1525,36 @@ trampoline_function_t alloc_trampoline (trampoline_function_t address, void** va
#define tramp_data(function) \
(*(unsigned long *) (function +24))
#endif
+#if defined(__e2k__)
+#define swaphilo(x) ((x) << 32 | (x) >> 32)
+ /* function:
+ * movtd,sm <address>, %ctpr1; ipd 2
+ * addd 0, <data>, %g16
+ *
+ * nop 7
+ * std 0, <variable>, %g16
+ *
+ * ct %ctpr1
+ */
+ *(long *) (function + 0) = 0x800000000C001033L;
+ *(long *) (function + 8) = 0x11C0DCF0E1C0DED1L;
+ *(long *) (function +16) = swaphilo((unsigned long) address);
+ *(long *) (function +24) = swaphilo((unsigned long) data);
+ *(long *) (function +32) = 0x27C0DCF010000391L;
+ *(long *) (function +40) = swaphilo((unsigned long) variable);
+ *(long *) (function +48) = 0xC000042000001001L;
+#define is_tramp(function) \
+ *(unsigned long *) (function + 0) == 0x800000000C001033L && \
+ *(unsigned long *) (function + 8) == 0x11C0DCF0E1C0DED1L && \
+ *(unsigned long *) (function +32) == 0x27C0DCF010000391L && \
+ *(unsigned long *) (function +48) == 0xC000042000001001L
+#define tramp_address(function) \
+ swaphilo(*(unsigned long *) (function +16))
+#define tramp_variable(function) \
+ swaphilo(*(unsigned long *) (function +40))
+#define tramp_data(function) \
+ swaphilo(*(unsigned long *) (function +24))
+#endif
/* 3. Set memory protection to "executable" */
@@ -1631,7 +1672,7 @@ trampoline_function_t alloc_trampoline (trampoline_function_t address, void** va
/* This assumes that the trampoline fits in at most two cache lines. */
__TR_clear_cache(function_x,function_x+TRAMP_CODE_LENGTH-1);
#endif
-#if defined(__arm__) || defined(__armhf__) || defined(__arm64__)
+#if defined(__arm__) || defined(__armhf__) || defined(__arm64__) || defined(__e2k__)
/* On ARM, cache flushing can only be done through a system call.
GCC implements it for Linux with EABI, through an "swi 0" with code
0xf0002. For other systems, it may be an "swi 0x9f0002",
diff --git a/vacall/Makefile.in b/vacall/Makefile.in
index ec31846..98b021a 100644
--- a/vacall/Makefile.in
+++ b/vacall/Makefile.in
@@ -144,6 +144,9 @@ vacall-arm64.s : $(srcdir)/vacall-arm64-macro.S $(srcdir)/vacall-arm64-macos-mac
esac; \
$(CPP) $(ASPFLAGS) -I$(srcdir)/../common $(srcdir)/$${input} | grep -v '^ *#line' | grep -v '^#' | sed -e 's,% ,%,g' -e 's,//,@,g' -e 's,\$$,#,g' > vacall-arm64.s
+vacall-e2k.@OBJEXT@ : $(srcdir)/vacall-e2k.c
+ $(CC) $(INCLUDES) -I$(srcdir)/.. $(CPPFLAGS) $(CFLAGS) -c $(srcdir)/vacall-e2k.c -o vacall-e2k.@OBJEXT@
+
vacall-powerpc.@OBJEXT@ : vacall-powerpc.s
$(CC) @GCC_X_NONE@ -c vacall-powerpc.s
diff --git a/vacall/vacall-e2k.c b/vacall/vacall-e2k.c
new file mode 100644
index 0000000..792de68
--- /dev/null
+++ b/vacall/vacall-e2k.c
@@ -0,0 +1,81 @@
+/* vacall function for e2k CPU */
+
+/*
+ Copyright 2021 Ilya Kurdyukov <jpegqs@gmail.com> for BaseALT, Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "vacall-internal.h"
+#include <string.h>
+
+#ifdef REENTRANT
+#define vacall_receiver callback_receiver
+typedef struct { void (*vacall_function) (void*,va_alist); void* arg; } env_t;
+register env_t* env __asm__("g16");
+#endif
+
+typedef struct { __vaword r[__VA_IARG_NUM]; } regs_t;
+
+#ifdef REENTRANT
+static
+#endif
+regs_t /* the return type is variable */
+vacall_receiver (regs_t iarg, regs_t sarg)
+{
+ __va_alist list;
+ regs_t *ret = (regs_t*)list.iarg;
+ /* Must be saved early to prevent the compiler
+ from saving "iarg" in the caller's stack frame. */
+ *ret = iarg;
+
+ /* Prepare the va_alist. */
+ list.flags = 0;
+ list.aptr = (long)(&sarg - 1);
+ list.sptr = (long)&sarg;
+ list.raddr = (void*)0;
+ list.rtype = __VAvoid;
+ /* Call vacall_function. The macros do all the rest. */
+#ifndef REENTRANT
+ (*vacall_function) (&list);
+#else /* REENTRANT */
+ (*env->vacall_function) (env->arg, &list);
+#endif
+
+ /* Put return value into proper register. */
+ switch (list.rtype) {
+ case __VAvoid: break;
+#define RET2(x, y) case __VA##x: ret->r[0] = (long)list.tmp._##y; break;
+#define RET(x) RET2(x, x)
+ RET(char) RET(schar) RET(uchar)
+ RET(short) RET(ushort)
+ RET(int) RET(uint)
+ RET(long) RET(ulong)
+ RET(longlong) RET(ulonglong)
+ RET2(float, uint)
+ RET2(double, ulong)
+ RET2(voidp, ptr)
+ case __VAstruct:
+ memcpy(list.rsize > sizeof(*ret) ? &sarg - 1 : ret, list.raddr, list.rsize);
+ }
+ return *ret;
+}
+
+#ifdef REENTRANT
+__vacall_r_t
+callback_get_receiver (void)
+{
+ return (__vacall_r_t)(void*)&callback_receiver;
+}
+#endif
diff --git a/vacall/vacall-internal.h b/vacall/vacall-internal.h
index c196348..09214ef 100644
--- a/vacall/vacall-internal.h
+++ b/vacall/vacall-internal.h
@@ -225,6 +225,11 @@ typedef struct vacall_alist
float farg[__VA_FARG_NUM];
double darg[__VA_FARG_NUM];
#endif
+#if defined(__e2k__)
+#define __VA_IARG_NUM 8
+ __vaword iarg[__VA_IARG_NUM];
+ uintptr_t sptr;
+#endif
} __va_alist;
@@ -1210,4 +1215,28 @@ typedef struct vacall_alist
extern void vacall_structcpy (void* dest, const void* src, unsigned long size, unsigned long alignment);
+#ifdef __e2k__
+#define __va_align_double(LIST)
+#define _va_arg_longlong _va_arg_long
+#define _va_arg_ulonglong _va_arg_ulong
+
+#define __va_arg_adjusted(LIST,TYPE_SIZE,TYPE_ALIGN) \
+ ((LIST)->aptr += __va_argsize(TYPE_SIZE), \
+ (LIST)->aptr > (LIST)->sptr \
+ ? (void*)((LIST)->aptr - __va_argsize(TYPE_SIZE)) \
+ : (void*)((uintptr_t)&(LIST)->iarg[__VA_IARG_NUM] + (LIST)->aptr - __va_argsize(TYPE_SIZE) - (LIST)->sptr) \
+ )
+#define __va_arg_struct(LIST,TYPE_SIZE,TYPE_ALIGN) \
+ (__va_align_struct(LIST,TYPE_SIZE,((TYPE_SIZE) > sizeof(__vaword) ? 2*sizeof(__vaword) : sizeof(__vaword))) \
+ __va_arg_adjusted(LIST,TYPE_SIZE,TYPE_ALIGN) \
+ )
+
+#undef __va_start_struct
+#define __va_start_struct(LIST,TYPE_SIZE,TYPE_ALIGN,TYPE_SPLITTABLE,FLAGS) \
+ (__va_start(LIST,__VAstruct,FLAGS), \
+ (LIST)->rsize = (TYPE_SIZE), \
+ (LIST)->raddr = (TYPE_SIZE) > sizeof((LIST)->iarg) ? (void*)((LIST)->sptr - sizeof((LIST)->iarg)) : (void*)(LIST)->iarg \
+ )
+#endif /* __e2k__ */
+
#endif /* _VACALL_INTERNAL_H */
--
2.17.1