* [RFC v4 00/11] Native Library Calls
@ 2023-08-08 14:17 Yeqi Fu
2023-08-08 14:17 ` [RFC v4 01/11] build: Implement logic for sharing cross-building config files Yeqi Fu
` (10 more replies)
0 siblings, 11 replies; 31+ messages in thread
From: Yeqi Fu @ 2023-08-08 14:17 UTC (permalink / raw)
To: alex.bennee; +Cc: richard.henderson, qemu-devel, Yeqi Fu
Executing a program under QEMU's user mode subjects the entire
program, including all library calls, to translation. It's important
to understand that many of these library functions are optimized
specifically for the guest architecture. Therefore, their
translation might not yield the most efficient execution.
When the semantics of a library function are well defined, we can
capitalize on this by substituting the translated version with a call
to the native equivalent function.
To achieve tangible results, focus should be given to functions such
as memory-related ('mem*') and string-related ('str*') functions.
These subsets of functions often have the most significant effect
on overall performance, making them optimal candidates for
optimization.
Yeqi Fu (11):
build: Implement logic for sharing cross-building config files
build: Implement libnative library and the build machinery for
libnative
linux-user: Implement envlist_appendenv and add tests for envlist
linux-user: Implement native-bypass option support
linux-user/elfload: Add support for parsing symbols of native
libraries.
tcg: Add tcg opcodes and helpers for native library calls
target/i386: Add support for native library calls
target/mips: Add support for native library calls
target/arm: Add support for native library calls
tests/tcg/multiarch: Add nativecall.c test
docs/user: Add doc for native library calls
Makefile | 2 +
accel/tcg/tcg-runtime.h | 22 ++++
common-user/native/Makefile.include | 9 ++
common-user/native/Makefile.target | 22 ++++
common-user/native/libnative.c | 67 ++++++++++++
configs/targets/aarch64-linux-user.mak | 1 +
configs/targets/arm-linux-user.mak | 1 +
configs/targets/i386-linux-user.mak | 1 +
configs/targets/mips-linux-user.mak | 1 +
configs/targets/mips64-linux-user.mak | 1 +
configs/targets/x86_64-linux-user.mak | 1 +
configure | 96 ++++++++++++----
docs/user/index.rst | 1 +
docs/user/native_calls.rst | 90 +++++++++++++++
include/native/libnative.h | 8 ++
include/native/native.h | 9 ++
include/qemu/envlist.h | 13 +++
include/tcg/tcg-op-common.h | 11 ++
include/tcg/tcg.h | 9 ++
linux-user/elfload.c | 85 +++++++++++++-
linux-user/main.c | 38 +++++++
target/arm/tcg/translate-a64.c | 14 +++
target/arm/tcg/translate.c | 11 ++
target/i386/tcg/translate.c | 27 +++++
target/mips/tcg/translate.c | 21 +++-
tcg/tcg-op.c | 140 ++++++++++++++++++++++++
tests/tcg/multiarch/Makefile.target | 17 +++
tests/tcg/multiarch/native/nativecall.c | 98 +++++++++++++++++
tests/unit/meson.build | 1 +
tests/unit/test-envlist.c | 94 ++++++++++++++++
util/envlist.c | 71 ++++++++++--
31 files changed, 943 insertions(+), 39 deletions(-)
create mode 100644 common-user/native/Makefile.include
create mode 100644 common-user/native/Makefile.target
create mode 100644 common-user/native/libnative.c
create mode 100644 docs/user/native_calls.rst
create mode 100644 include/native/libnative.h
create mode 100644 include/native/native.h
create mode 100644 tests/tcg/multiarch/native/nativecall.c
create mode 100644 tests/unit/test-envlist.c
--
2.34.1
^ permalink raw reply [flat|nested] 31+ messages in thread
* [RFC v4 01/11] build: Implement logic for sharing cross-building config files
2023-08-08 14:17 [RFC v4 00/11] Native Library Calls Yeqi Fu
@ 2023-08-08 14:17 ` Yeqi Fu
2023-08-09 12:24 ` Manos Pitsidianakis
` (2 more replies)
2023-08-08 14:17 ` [RFC v4 02/11] build: Implement libnative library and the build machinery for libnative Yeqi Fu
` (9 subsequent siblings)
10 siblings, 3 replies; 31+ messages in thread
From: Yeqi Fu @ 2023-08-08 14:17 UTC (permalink / raw)
To: alex.bennee
Cc: richard.henderson, qemu-devel, Yeqi Fu, Paolo Bonzini,
Thomas Huth
Signed-off-by: Yeqi Fu <fufuyqqqqqq@gmail.com>
---
configure | 57 +++++++++++++++++++++++++++++++++----------------------
1 file changed, 34 insertions(+), 23 deletions(-)
diff --git a/configure b/configure
index 2b41c49c0d..a076583141 100755
--- a/configure
+++ b/configure
@@ -1751,56 +1751,67 @@ if test "$ccache_cpp2" = "yes"; then
echo "export CCACHE_CPP2=y" >> $config_host_mak
fi
-# tests/tcg configuration
-(config_host_mak=tests/tcg/config-host.mak
-mkdir -p tests/tcg
-echo "# Automatically generated by configure - do not modify" > $config_host_mak
-echo "SRC_PATH=$source_path" >> $config_host_mak
-echo "HOST_CC=$host_cc" >> $config_host_mak
+# Prepare the config files for cross building.
+# This process generates 'cross-build/<target>/config-target.mak' files.
+# These files are then symlinked to the directories that need them which
+# including the TCG tests (tests/tcg/<target>) and the libnative library
+# for linux-user (common/native/<target>/).
+mkdir -p cross-build
-# versioned checked in the main config_host.mak above
-if test -n "$gdb_bin"; then
- echo "HAVE_GDB_BIN=$gdb_bin" >> $config_host_mak
-fi
-if test "$plugins" = "yes" ; then
- echo "CONFIG_PLUGIN=y" >> $config_host_mak
-fi
-
-tcg_tests_targets=
for target in $target_list; do
arch=${target%%-*}
-
case $target in
xtensa*-linux-user)
- # the toolchain is not complete with headers, only build softmmu tests
+ # the toolchain for tests/tcg is not complete with headers
continue
;;
*-softmmu)
- test -f "$source_path/tests/tcg/$arch/Makefile.softmmu-target" || continue
qemu="qemu-system-$arch"
;;
*-linux-user|*-bsd-user)
qemu="qemu-$arch"
;;
esac
-
if probe_target_compiler $target || test -n "$container_image"; then
test -n "$container_image" && build_static=y
- mkdir -p "tests/tcg/$target"
- config_target_mak=tests/tcg/$target/config-target.mak
- ln -sf "$source_path/tests/tcg/Makefile.target" "tests/tcg/$target/Makefile"
+ mkdir -p "cross-build/$target"
+ config_target_mak=cross-build/$target/config-target.mak
echo "# Automatically generated by configure - do not modify" > "$config_target_mak"
echo "TARGET_NAME=$arch" >> "$config_target_mak"
echo "TARGET=$target" >> "$config_target_mak"
- write_target_makefile "build-tcg-tests-$target" >> "$config_target_mak"
+ write_target_makefile "$target" >> "$config_target_mak"
echo "BUILD_STATIC=$build_static" >> "$config_target_mak"
echo "QEMU=$PWD/$qemu" >> "$config_target_mak"
+ # get the interpreter prefix and the path of libnative required for native call tests
+ if [ -d "/usr/$(echo "$target_cc" | sed 's/-gcc//')" ]; then
+ echo "LD_PREFIX=/usr/$(echo "$target_cc" | sed 's/-gcc//')" >> "$config_target_mak"
+ fi
+
# will GDB work with these binaries?
if test "${gdb_arches#*$arch}" != "$gdb_arches"; then
echo "HOST_GDB_SUPPORTS_ARCH=y" >> "$config_target_mak"
fi
+ fi
+done
+
+# tests/tcg configuration
+(mkdir -p tests/tcg
+# create a symlink to the config-host.mak file in the tests/tcg
+ln -srf $config_host_mak tests/tcg/config-host.mak
+
+tcg_tests_targets=
+for target in $target_list; do
+ case $target in
+ *-softmmu)
+ test -f "$source_path/tests/tcg/$arch/Makefile.softmmu-target" || continue
+ ;;
+ esac
+ if test -f cross-build/$target/config-target.mak; then
+ mkdir -p "tests/tcg/$target"
+ ln -srf cross-build/$target/config-target.mak tests/tcg/$target/config-target.mak
+ ln -sf $source_path/tests/tcg/Makefile.target tests/tcg/$target/Makefile
echo "run-tcg-tests-$target: $qemu\$(EXESUF)" >> Makefile.prereqs
tcg_tests_targets="$tcg_tests_targets $target"
fi
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [RFC v4 02/11] build: Implement libnative library and the build machinery for libnative
2023-08-08 14:17 [RFC v4 00/11] Native Library Calls Yeqi Fu
2023-08-08 14:17 ` [RFC v4 01/11] build: Implement logic for sharing cross-building config files Yeqi Fu
@ 2023-08-08 14:17 ` Yeqi Fu
2023-08-09 15:18 ` Alex Bennée
2023-08-09 16:10 ` Richard Henderson
2023-08-08 14:17 ` [RFC v4 03/11] linux-user: Implement envlist_appendenv and add tests for envlist Yeqi Fu
` (8 subsequent siblings)
10 siblings, 2 replies; 31+ messages in thread
From: Yeqi Fu @ 2023-08-08 14:17 UTC (permalink / raw)
To: alex.bennee
Cc: richard.henderson, qemu-devel, Yeqi Fu, Paolo Bonzini,
Thomas Huth, Riku Voipio
This commit implements a shared library, where native functions are
rewritten as special instructions. At runtime, user programs load
the shared library, and special instructions are executed when
native functions are called.
Signed-off-by: Yeqi Fu <fufuyqqqqqq@gmail.com>
---
Makefile | 2 +
common-user/native/Makefile.include | 9 ++++
common-user/native/Makefile.target | 22 ++++++++++
common-user/native/libnative.c | 67 +++++++++++++++++++++++++++++
configure | 39 +++++++++++++++++
include/native/libnative.h | 8 ++++
6 files changed, 147 insertions(+)
create mode 100644 common-user/native/Makefile.include
create mode 100644 common-user/native/Makefile.target
create mode 100644 common-user/native/libnative.c
create mode 100644 include/native/libnative.h
diff --git a/Makefile b/Makefile
index 5d48dfac18..6f6147b40f 100644
--- a/Makefile
+++ b/Makefile
@@ -182,6 +182,8 @@ SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory --quiet)
include $(SRC_PATH)/tests/Makefile.include
+include $(SRC_PATH)/common-user/native/Makefile.include
+
all: recurse-all
ROMS_RULES=$(foreach t, all clean distclean, $(addsuffix /$(t), $(ROMS)))
diff --git a/common-user/native/Makefile.include b/common-user/native/Makefile.include
new file mode 100644
index 0000000000..40d20bcd4c
--- /dev/null
+++ b/common-user/native/Makefile.include
@@ -0,0 +1,9 @@
+.PHONY: build-native
+build-native: $(NATIVE_TARGETS:%=build-native-library-%)
+$(NATIVE_TARGETS:%=build-native-library-%): build-native-library-%:
+ $(call quiet-command, \
+ $(MAKE) -C common-user/native/$* $(SUBDIR_MAKEFLAGS), \
+ "BUILD","$* native library")
+# endif
+
+all: build-native
diff --git a/common-user/native/Makefile.target b/common-user/native/Makefile.target
new file mode 100644
index 0000000000..0c1241b368
--- /dev/null
+++ b/common-user/native/Makefile.target
@@ -0,0 +1,22 @@
+# -*- Mode: makefile -*-
+#
+# Library for native calls
+#
+
+all:
+-include ../../config-host.mak
+-include config-target.mak
+
+CFLAGS+=-O1 -fPIC -shared -fno-stack-protector -I$(SRC_PATH)/include -D$(TARGET_NAME)
+LDFLAGS+=
+
+SRC = $(SRC_PATH)/common-user/native/libnative.c
+LIBNATIVE = libnative.so
+
+all: $(LIBNATIVE)
+
+$(LIBNATIVE): $(SRC)
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(EXTRA_NATIVE_CALL_FLAGS) $< -o $@ $(LDFLAGS)
+
+clean:
+ rm -f $(LIBNATIVE)
diff --git a/common-user/native/libnative.c b/common-user/native/libnative.c
new file mode 100644
index 0000000000..662ae6fbfe
--- /dev/null
+++ b/common-user/native/libnative.c
@@ -0,0 +1,67 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "native/libnative.h"
+
+#define WRAP_NATIVE() \
+ do { \
+ __asm__ volatile(__CALL_EXPR : : : "memory"); \
+ } while (0)
+
+#if defined(i386) || defined(x86_64)
+/*
+ * An unused instruction is utilized to mark a native call.
+ */
+#define __CALL_EXPR ".byte 0x0f, 0xff;"
+#endif
+
+#if defined(arm) || defined(aarch64)
+/*
+ * HLT is an invalid instruction for userspace and usefully has 16
+ * bits of spare immeadiate data which we can stuff data in.
+ */
+#define __CALL_EXPR "hlt 0xffff;"
+#endif
+
+#if defined(mips) || defined(mips64)
+/*
+ * The syscall instruction contains 20 unused bits, which are typically
+ * set to 0. These bits can be used to store non-zero data,
+ * distinguishing them from a regular syscall instruction.
+ */
+#define __CALL_EXPR "syscall 0xffff;"
+#endif
+
+void *memcpy(void *dest, const void *src, size_t n)
+{
+ WRAP_NATIVE();
+}
+int memcmp(const void *s1, const void *s2, size_t n)
+{
+ WRAP_NATIVE();
+}
+void *memset(void *s, int c, size_t n)
+{
+ WRAP_NATIVE();
+}
+char *strncpy(char *dest, const char *src, size_t n)
+{
+ WRAP_NATIVE();
+}
+int strncmp(const char *s1, const char *s2, size_t n)
+{
+ WRAP_NATIVE();
+}
+char *strcpy(char *dest, const char *src)
+{
+ WRAP_NATIVE();
+}
+char *strcat(char *dest, const char *src)
+{
+ WRAP_NATIVE();
+}
+int strcmp(const char *s1, const char *s2)
+{
+ WRAP_NATIVE();
+}
diff --git a/configure b/configure
index a076583141..e02fc2c5c0 100755
--- a/configure
+++ b/configure
@@ -1822,6 +1822,45 @@ if test "$tcg" = "enabled"; then
fi
)
+# common-user/native configuration
+(mkdir -p common-user/native
+
+native_targets=
+for target in $target_list; do
+ case $target in
+ *-softmmu)
+ continue
+ ;;
+ esac
+
+ # native call is only supported on these architectures
+ arch=${target%%-*}
+ config_target_mak=common-user/native/$target/config-target.mak
+ case $arch in
+ i386|x86_64|arm|aarch64|mips|mips64)
+ if test -f cross-build/$target/config-target.mak; then
+ mkdir -p "common-user/native/$target"
+ ln -srf cross-build/$target/config-target.mak "$config_target_mak"
+ if test $arch = arm; then
+ echo "EXTRA_NATIVE_CALL_FLAGS=-marm" >> "$config_target_mak"
+ fi
+ if test $arch = $cpu || \
+ { test $arch = i386 && test $cpu = x86_64; } || \
+ { test $arch = arm && test $cpu = aarch64; } || \
+ { test $arch = mips && test $cpu = mips64; }; then
+ echo "LD_PREFIX=/" >> "$config_target_mak"
+ fi
+ echo "LIBNATIVE=$PWD/common-user/native/$target/libnative.so" >> "$config_target_mak"
+ ln -sf $source_path/common-user/native/Makefile.target common-user/native/$target/Makefile
+ native_targets="$native_targets $target"
+ fi
+ ;;
+ esac
+done
+
+echo "NATIVE_TARGETS=$native_targets" >> config-host.mak
+)
+
if test "$skip_meson" = no; then
cross="config-meson.cross.new"
meson_quote() {
diff --git a/include/native/libnative.h b/include/native/libnative.h
new file mode 100644
index 0000000000..ec990d8e5f
--- /dev/null
+++ b/include/native/libnative.h
@@ -0,0 +1,8 @@
+void *memset(void *s, int c, size_t n);
+void *memcpy(void *dest, const void *src, size_t n);
+char *strncpy(char *dest, const char *src, size_t n);
+int memcmp(const void *s1, const void *s2, size_t n);
+int strncmp(const char *s1, const char *s2, size_t n);
+char *strcpy(char *dest, const char *src);
+char *strcat(char *dest, const char *src);
+int strcmp(const char *s1, const char *s2);
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [RFC v4 03/11] linux-user: Implement envlist_appendenv and add tests for envlist
2023-08-08 14:17 [RFC v4 00/11] Native Library Calls Yeqi Fu
2023-08-08 14:17 ` [RFC v4 01/11] build: Implement logic for sharing cross-building config files Yeqi Fu
2023-08-08 14:17 ` [RFC v4 02/11] build: Implement libnative library and the build machinery for libnative Yeqi Fu
@ 2023-08-08 14:17 ` Yeqi Fu
2023-08-09 15:27 ` Alex Bennée
` (2 more replies)
2023-08-08 14:17 ` [RFC v4 04/11] linux-user: Implement native-bypass option support Yeqi Fu
` (7 subsequent siblings)
10 siblings, 3 replies; 31+ messages in thread
From: Yeqi Fu @ 2023-08-08 14:17 UTC (permalink / raw)
To: alex.bennee; +Cc: richard.henderson, qemu-devel, Yeqi Fu
Signed-off-by: Yeqi Fu <fufuyqqqqqq@gmail.com>
---
include/qemu/envlist.h | 13 ++++++
tests/unit/meson.build | 1 +
tests/unit/test-envlist.c | 94 +++++++++++++++++++++++++++++++++++++++
util/envlist.c | 71 ++++++++++++++++++++++++-----
4 files changed, 169 insertions(+), 10 deletions(-)
create mode 100644 tests/unit/test-envlist.c
diff --git a/include/qemu/envlist.h b/include/qemu/envlist.h
index 6006dfae44..9eb1459e79 100644
--- a/include/qemu/envlist.h
+++ b/include/qemu/envlist.h
@@ -1,12 +1,25 @@
#ifndef ENVLIST_H
#define ENVLIST_H
+#include "qemu/queue.h"
+
+struct envlist_entry {
+ const char *ev_var; /* actual env value */
+ QLIST_ENTRY(envlist_entry) ev_link;
+};
+
+struct envlist {
+ QLIST_HEAD(, envlist_entry) el_entries; /* actual entries */
+ size_t el_count; /* number of entries */
+};
+
typedef struct envlist envlist_t;
envlist_t *envlist_create(void);
void envlist_free(envlist_t *);
int envlist_setenv(envlist_t *, const char *);
int envlist_unsetenv(envlist_t *, const char *);
+int envlist_appendenv(envlist_t *, const char *, const char *);
int envlist_parse_set(envlist_t *, const char *);
int envlist_parse_unset(envlist_t *, const char *);
char **envlist_to_environ(const envlist_t *, size_t *);
diff --git a/tests/unit/meson.build b/tests/unit/meson.build
index 93977cc32d..9b25b45271 100644
--- a/tests/unit/meson.build
+++ b/tests/unit/meson.build
@@ -50,6 +50,7 @@ tests = {
'test-qapi-util': [],
'test-interval-tree': [],
'test-xs-node': [qom],
+ 'test-envlist': [],
}
if have_system or have_tools
diff --git a/tests/unit/test-envlist.c b/tests/unit/test-envlist.c
new file mode 100644
index 0000000000..d1e148f738
--- /dev/null
+++ b/tests/unit/test-envlist.c
@@ -0,0 +1,94 @@
+/*
+ * testenvlist unit-tests.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/envlist.h"
+
+static void envlist_create_free_test(void)
+{
+ envlist_t *testenvlist;
+
+ testenvlist = envlist_create();
+ g_assert(testenvlist != NULL);
+ g_assert(testenvlist->el_count == 0);
+
+ envlist_free(testenvlist);
+}
+
+static void envlist_set_unset_test(void)
+{
+ envlist_t *testenvlist;
+ const char *env = "TEST=123";
+ struct envlist_entry *entry;
+
+ testenvlist = envlist_create();
+ g_assert(envlist_setenv(testenvlist, env) == 0);
+ g_assert(testenvlist->el_count == 1);
+ entry = testenvlist->el_entries.lh_first;
+ g_assert_cmpstr(entry->ev_var, ==, "TEST=123");
+ g_assert(envlist_unsetenv(testenvlist, "TEST") == 0);
+ g_assert(testenvlist->el_count == 0);
+
+ envlist_free(testenvlist);
+}
+
+static void envlist_parse_set_unset_test(void)
+{
+ envlist_t *testenvlist;
+ const char *env = "TEST1=123,TEST2=456";
+
+ testenvlist = envlist_create();
+ g_assert(envlist_parse_set(testenvlist, env) == 0);
+ g_assert(testenvlist->el_count == 2);
+ g_assert(envlist_parse_unset(testenvlist, "TEST1,TEST2") == 0);
+ g_assert(testenvlist->el_count == 0);
+
+ envlist_free(testenvlist);
+}
+
+static void envlist_appendenv_test(void)
+{
+ envlist_t *testenvlist;
+ const char *env = "TEST=123";
+ struct envlist_entry *entry;
+
+ testenvlist = envlist_create();
+ g_assert(envlist_setenv(testenvlist, env) == 0);
+ g_assert(envlist_appendenv(testenvlist, "TEST=456", ";") == 0);
+ entry = testenvlist->el_entries.lh_first;
+ g_assert_cmpstr(entry->ev_var, ==, "TEST=123;456");
+
+ envlist_free(testenvlist);
+}
+
+static void envlist_to_environ_test(void)
+{
+ envlist_t *testenvlist;
+ const char *env = "TEST1=123,TEST2=456";
+ size_t count;
+ char **environ;
+
+ testenvlist = envlist_create();
+ g_assert(envlist_parse_set(testenvlist, env) == 0);
+ g_assert(testenvlist->el_count == 2);
+ environ = envlist_to_environ(testenvlist, &count);
+ g_assert(count == 2);
+ g_assert_cmpstr(environ[1], ==, "TEST1=123");
+ g_assert_cmpstr(environ[0], ==, "TEST2=456");
+
+ envlist_free(testenvlist);
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ g_test_add_func("/envlist/create_free", envlist_create_free_test);
+ g_test_add_func("/envlist/set_unset", envlist_set_unset_test);
+ g_test_add_func("/envlist/parse_set_unset", envlist_parse_set_unset_test);
+ g_test_add_func("/envlist/appendenv", envlist_appendenv_test);
+ g_test_add_func("/envlist/to_environ", envlist_to_environ_test);
+
+ return g_test_run();
+}
diff --git a/util/envlist.c b/util/envlist.c
index db937c0427..2570f0e30c 100644
--- a/util/envlist.c
+++ b/util/envlist.c
@@ -2,16 +2,6 @@
#include "qemu/queue.h"
#include "qemu/envlist.h"
-struct envlist_entry {
- const char *ev_var; /* actual env value */
- QLIST_ENTRY(envlist_entry) ev_link;
-};
-
-struct envlist {
- QLIST_HEAD(, envlist_entry) el_entries; /* actual entries */
- size_t el_count; /* number of entries */
-};
-
static int envlist_parse(envlist_t *envlist,
const char *env, int (*)(envlist_t *, const char *));
@@ -201,6 +191,67 @@ envlist_unsetenv(envlist_t *envlist, const char *env)
return (0);
}
+/*
+ * Appends environment value to envlist. If the environment
+ * variable already exists, the new value is appended to the
+ * existing one.
+ *
+ * Returns 0 in success, errno otherwise.
+ */
+int
+envlist_appendenv(envlist_t *envlist, const char *env, const char *separator)
+{
+ struct envlist_entry *entry = NULL;
+ const char *eq_sign;
+ size_t envname_len;
+
+ if ((envlist == NULL) || (env == NULL) || (separator == NULL)) {
+ return -EINVAL;
+ }
+
+ /* find out first equals sign in given env */
+ eq_sign = strchr(env, '=');
+ if (eq_sign == NULL) {
+ return -EINVAL;
+ }
+
+ if (strchr(eq_sign + 1, '=') != NULL) {
+ return -EINVAL;
+ }
+
+ envname_len = eq_sign - env + 1;
+
+ /*
+ * If there already exists variable with given name,
+ * we append the new value to the existing one.
+ */
+ for (entry = envlist->el_entries.lh_first; entry != NULL;
+ entry = entry->ev_link.le_next) {
+ if (strncmp(entry->ev_var, env, envname_len) == 0) {
+ break;
+ }
+ }
+
+ if (entry != NULL) {
+ char *new_env_value = NULL;
+ size_t new_env_len = strlen(entry->ev_var) + strlen(eq_sign)
+ + strlen(separator) + 1;
+ new_env_value = g_malloc(new_env_len);
+ strcpy(new_env_value, entry->ev_var);
+ strcat(new_env_value, separator);
+ strcat(new_env_value, eq_sign + 1);
+ g_free((char *)entry->ev_var);
+ entry->ev_var = new_env_value;
+ } else {
+ envlist->el_count++;
+ entry = g_malloc(sizeof(*entry));
+ entry->ev_var = g_strdup(env);
+ QLIST_INSERT_HEAD(&envlist->el_entries, entry, ev_link);
+ }
+
+ return 0;
+}
+
/*
* Returns given envlist as array of strings (in same form that
* global variable environ is). Caller must free returned memory
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [RFC v4 04/11] linux-user: Implement native-bypass option support
2023-08-08 14:17 [RFC v4 00/11] Native Library Calls Yeqi Fu
` (2 preceding siblings ...)
2023-08-08 14:17 ` [RFC v4 03/11] linux-user: Implement envlist_appendenv and add tests for envlist Yeqi Fu
@ 2023-08-08 14:17 ` Yeqi Fu
2023-08-09 15:42 ` Richard Henderson
2023-08-09 15:47 ` Alex Bennée
2023-08-08 14:17 ` [RFC v4 05/11] linux-user/elfload: Add support for parsing symbols of native libraries Yeqi Fu
` (6 subsequent siblings)
10 siblings, 2 replies; 31+ messages in thread
From: Yeqi Fu @ 2023-08-08 14:17 UTC (permalink / raw)
To: alex.bennee; +Cc: richard.henderson, qemu-devel, Yeqi Fu, Laurent Vivier
This commit implements the -native-bypass support in linux-user. The
native_calls_enabled() function can be true only when the
'-native-bypass' option is given.
Signed-off-by: Yeqi Fu <fufuyqqqqqq@gmail.com>
---
include/native/native.h | 9 +++++++++
linux-user/main.c | 38 ++++++++++++++++++++++++++++++++++++++
2 files changed, 47 insertions(+)
create mode 100644 include/native/native.h
diff --git a/include/native/native.h b/include/native/native.h
new file mode 100644
index 0000000000..62951fafb1
--- /dev/null
+++ b/include/native/native.h
@@ -0,0 +1,9 @@
+/*
+ * Check if the native bypass feature is enabled.
+ */
+#if defined(CONFIG_USER_ONLY) && defined(CONFIG_NATIVE_CALL)
+extern char *native_lib_path;
+#define native_bypass_enabled() native_lib_path ? true : false
+#else
+#define native_bypass_enabled() false
+#endif
diff --git a/linux-user/main.c b/linux-user/main.c
index dba67ffa36..86ea0191f7 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -60,6 +60,11 @@
#include "semihosting/semihost.h"
#endif
+#if defined(CONFIG_NATIVE_CALL)
+#include "native/native.h"
+char *native_lib_path;
+#endif
+
#ifndef AT_FLAGS_PRESERVE_ARGV0
#define AT_FLAGS_PRESERVE_ARGV0_BIT 0
#define AT_FLAGS_PRESERVE_ARGV0 (1 << AT_FLAGS_PRESERVE_ARGV0_BIT)
@@ -293,6 +298,17 @@ static void handle_arg_set_env(const char *arg)
free(r);
}
+#if defined(CONFIG_NATIVE_CALL)
+static void handle_arg_native_bypass(const char *arg)
+{
+ if (access(arg, F_OK) != 0) {
+ fprintf(stderr, "native library %s does not exist\n", arg);
+ exit(EXIT_FAILURE);
+ }
+ native_lib_path = strdup(arg);
+}
+#endif
+
static void handle_arg_unset_env(const char *arg)
{
char *r, *p, *token;
@@ -522,6 +538,10 @@ static const struct qemu_argument arg_table[] = {
"", "Generate a /tmp/perf-${pid}.map file for perf"},
{"jitdump", "QEMU_JITDUMP", false, handle_arg_jitdump,
"", "Generate a jit-${pid}.dump file for perf"},
+#if defined(CONFIG_NATIVE_CALL)
+ {"native-bypass", "QEMU_NATIVE_BYPASS", true, handle_arg_native_bypass,
+ "", "native bypass for library calls in user mode only."},
+#endif
{NULL, NULL, false, NULL, NULL, NULL}
};
@@ -834,6 +854,24 @@ int main(int argc, char **argv, char **envp)
}
}
+#if defined(CONFIG_NATIVE_CALL)
+ /* Set the library for native bypass */
+ if (native_lib_path) {
+ if (g_file_test(native_lib_path, G_FILE_TEST_EXISTS)) {
+ GString *lib = g_string_new(native_lib_path);
+ lib = g_string_prepend(lib, "LD_PRELOAD=");
+ if (envlist_appendenv(envlist, g_string_free(lib, false), ":")) {
+ fprintf(stderr,
+ "failed to append the native library to environment.\n");
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ fprintf(stderr, "native library %s does not exist.\n",
+ native_lib_path);
+ exit(EXIT_FAILURE);
+ }
+ }
+#endif
target_environ = envlist_to_environ(envlist, NULL);
envlist_free(envlist);
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [RFC v4 05/11] linux-user/elfload: Add support for parsing symbols of native libraries.
2023-08-08 14:17 [RFC v4 00/11] Native Library Calls Yeqi Fu
` (3 preceding siblings ...)
2023-08-08 14:17 ` [RFC v4 04/11] linux-user: Implement native-bypass option support Yeqi Fu
@ 2023-08-08 14:17 ` Yeqi Fu
2023-08-09 16:14 ` Richard Henderson
2023-08-08 14:17 ` [RFC v4 06/11] tcg: Add tcg opcodes and helpers for native library calls Yeqi Fu
` (5 subsequent siblings)
10 siblings, 1 reply; 31+ messages in thread
From: Yeqi Fu @ 2023-08-08 14:17 UTC (permalink / raw)
To: alex.bennee; +Cc: richard.henderson, qemu-devel, Yeqi Fu, Laurent Vivier
This commit addresses the need to parse symbols of native libraries.
The base address of a shared library is determined by the dynamic
linker. To simplify the process, we focus on the last three digits,
which reside within the same page and remain unaffected by the base
address.
Signed-off-by: Yeqi Fu <fufuyqqqqqq@gmail.com>
---
linux-user/elfload.c | 85 +++++++++++++++++++++++++++++++++++++++++---
1 file changed, 80 insertions(+), 5 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 9a2ec568b0..9448f91005 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -22,6 +22,9 @@
#include "qemu/error-report.h"
#include "target_signal.h"
#include "accel/tcg/debuginfo.h"
+#if defined(CONFIG_NATIVE_CALL)
+#include "native/native.h"
+#endif
#ifdef _ARCH_PPC64
#undef ARCH_DLINFO
@@ -2038,8 +2041,10 @@ static inline void bswap_mips_abiflags(Mips_elf_abiflags_v0 *abiflags) { }
#ifdef USE_ELF_CORE_DUMP
static int elf_core_dump(int, const CPUArchState *);
#endif /* USE_ELF_CORE_DUMP */
-static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias);
-
+static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias,
+ uint load_type);
+#define ELF_SYM 1
+#define NATIVE_LIB_SYM 2
/* Verify the portions of EHDR within E_IDENT for the target.
This can be performed before bswapping the entire header. */
static bool elf_check_ident(struct elfhdr *ehdr)
@@ -3302,7 +3307,7 @@ static void load_elf_image(const char *image_name, int image_fd,
}
if (qemu_log_enabled()) {
- load_symbols(ehdr, image_fd, load_bias);
+ load_symbols(ehdr, image_fd, load_bias, ELF_SYM);
}
debuginfo_report_elf(image_name, image_fd, load_bias);
@@ -3398,7 +3403,8 @@ static int symcmp(const void *s0, const void *s1)
}
/* Best attempt to load symbols from this ELF object. */
-static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
+static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias,
+ uint load_type)
{
int i, shnum, nsyms, sym_idx = 0, str_idx = 0;
uint64_t segsz;
@@ -3456,7 +3462,21 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
for (i = 0; i < nsyms; ) {
bswap_sym(syms + i);
/* Throw away entries which we do not need. */
- if (syms[i].st_shndx == SHN_UNDEF
+ if (load_type == NATIVE_LIB_SYM) {
+ /*
+ * Load the native library.
+ * Since the base address of a shared library is determined
+ * by the dynamic linker, we only consider the last three
+ * digits here, which are within the same page and are not
+ * affected by the base address.
+ */
+#if defined(TARGET_ARM) || defined(TARGET_MIPS)
+ /* The bottom address bit marks a Thumb or MIPS16 symbol. */
+ syms[i].st_value &= ~(target_ulong)1;
+#endif
+ syms[i].st_value &= 0xfff;
+ i++;
+ } else if (syms[i].st_shndx == SHN_UNDEF
|| syms[i].st_shndx >= SHN_LORESERVE
|| ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
if (i < --nsyms) {
@@ -3542,14 +3562,63 @@ uint32_t get_elf_eflags(int fd)
return ehdr.e_flags;
}
+#if defined(CONFIG_NATIVE_CALL)
+static void load_native_library(const char *filename, struct image_info *info,
+ char bprm_buf[BPRM_BUF_SIZE])
+{
+ int fd, retval;
+ Error *err = NULL;
+
+ fd = open(path(filename), O_RDONLY);
+ if (fd < 0) {
+ error_setg_file_open(&err, errno, filename);
+ error_report_err(err);
+ exit(-1);
+ }
+
+ retval = read(fd, bprm_buf, BPRM_BUF_SIZE);
+ if (retval < 0) {
+ error_setg_errno(&err, errno, "Error reading file header");
+ error_reportf_err(err, "%s: ", filename);
+ exit(-1);
+ }
+
+ if (retval < BPRM_BUF_SIZE) {
+ memset(bprm_buf + retval, 0, BPRM_BUF_SIZE - retval);
+ }
+
+ struct elfhdr *ehdr = (struct elfhdr *)bprm_buf;
+
+ if (!elf_check_ident(ehdr)) {
+ error_setg(&err, "Invalid ELF image for this architecture");
+ goto exit_errmsg;
+ }
+ bswap_ehdr(ehdr);
+ if (!elf_check_ehdr(ehdr)) {
+ error_setg(&err, "Invalid ELF image for this architecture");
+ goto exit_errmsg;
+ }
+
+ /* We are only concerned with the symbols of native library. */
+ load_symbols(ehdr, fd, 0, NATIVE_LIB_SYM);
+ return;
+
+exit_errmsg:
+ error_reportf_err(err, "%s: ", filename);
+ exit(-1);
+}
+#endif
+
int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
{
struct image_info interp_info;
+ struct image_info nativelib_info;
struct elfhdr elf_ex;
char *elf_interpreter = NULL;
char *scratch;
memset(&interp_info, 0, sizeof(interp_info));
+ memset(&nativelib_info, 0, sizeof(nativelib_info));
#ifdef TARGET_MIPS
interp_info.fp_abi = MIPS_ABI_FP_UNKNOWN;
#endif
@@ -3665,6 +3734,12 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
target_munmap(start_brk, end_brk - start_brk);
}
+#if defined(CONFIG_NATIVE_CALL)
+ if (native_bypass_enabled()) {
+ load_native_library(native_lib_path, &nativelib_info, bprm->buf);
+ }
+#endif
+
return 0;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [RFC v4 06/11] tcg: Add tcg opcodes and helpers for native library calls
2023-08-08 14:17 [RFC v4 00/11] Native Library Calls Yeqi Fu
` (4 preceding siblings ...)
2023-08-08 14:17 ` [RFC v4 05/11] linux-user/elfload: Add support for parsing symbols of native libraries Yeqi Fu
@ 2023-08-08 14:17 ` Yeqi Fu
2023-08-09 16:41 ` Alex Bennée
2023-08-08 14:17 ` [RFC v4 07/11] target/i386: Add support " Yeqi Fu
` (4 subsequent siblings)
10 siblings, 1 reply; 31+ messages in thread
From: Yeqi Fu @ 2023-08-08 14:17 UTC (permalink / raw)
To: alex.bennee; +Cc: richard.henderson, qemu-devel, Yeqi Fu, Paolo Bonzini
This commit implements tcg opcodes and helpers for extracting and
invoke native functions.
Signed-off-by: Yeqi Fu <fufuyqqqqqq@gmail.com>
---
accel/tcg/tcg-runtime.h | 22 ++++++
include/tcg/tcg-op-common.h | 11 +++
include/tcg/tcg.h | 9 +++
tcg/tcg-op.c | 140 ++++++++++++++++++++++++++++++++++++
4 files changed, 182 insertions(+)
diff --git a/accel/tcg/tcg-runtime.h b/accel/tcg/tcg-runtime.h
index 39e68007f9..bda78b4489 100644
--- a/accel/tcg/tcg-runtime.h
+++ b/accel/tcg/tcg-runtime.h
@@ -37,6 +37,28 @@ DEF_HELPER_FLAGS_1(exit_atomic, TCG_CALL_NO_WG, noreturn, env)
*/
#define helper_memset memset
DEF_HELPER_FLAGS_3(memset, TCG_CALL_NO_RWG, ptr, ptr, int, ptr)
+
+#define helper_memcpy memcpy
+DEF_HELPER_FLAGS_3(memcpy, TCG_CALL_NO_RWG, ptr, ptr, ptr, ptr)
+
+#define helper_strncpy strncpy
+DEF_HELPER_FLAGS_3(strncpy, TCG_CALL_NO_RWG, ptr, ptr, ptr, ptr)
+
+#define helper_memcmp memcmp
+DEF_HELPER_FLAGS_3(memcmp, TCG_CALL_NO_RWG, int, ptr, ptr, ptr)
+
+#define helper_strncmp strncmp
+DEF_HELPER_FLAGS_3(strncmp, TCG_CALL_NO_RWG, int, ptr, ptr, ptr)
+
+#define helper_strcpy strcpy
+DEF_HELPER_FLAGS_2(strcpy, TCG_CALL_NO_RWG, ptr, ptr, ptr)
+
+#define helper_strcat strcat
+DEF_HELPER_FLAGS_2(strcat, TCG_CALL_NO_RWG, ptr, ptr, ptr)
+
+#define helper_strcmp strcmp
+DEF_HELPER_FLAGS_2(strcmp, TCG_CALL_NO_RWG, int, ptr, ptr)
+
#endif /* IN_HELPER_PROTO */
DEF_HELPER_FLAGS_3(ld_i128, TCG_CALL_NO_WG, i128, env, i64, i32)
diff --git a/include/tcg/tcg-op-common.h b/include/tcg/tcg-op-common.h
index be382bbf77..2e712f1573 100644
--- a/include/tcg/tcg-op-common.h
+++ b/include/tcg/tcg-op-common.h
@@ -903,6 +903,12 @@ void tcg_gen_ld_vec(TCGv_vec r, TCGv_ptr base, TCGArg offset);
void tcg_gen_st_vec(TCGv_vec r, TCGv_ptr base, TCGArg offset);
void tcg_gen_stl_vec(TCGv_vec r, TCGv_ptr base, TCGArg offset, TCGType t);
+/* Host <-> guest conversions */
+void tcg_gen_g2h_i32(TCGv_ptr ret, TCGv_i32 arg);
+void tcg_gen_g2h_i64(TCGv_ptr ret, TCGv_i64 arg);
+void tcg_gen_h2g_i32(TCGv_i32 ret, TCGv_ptr arg);
+void tcg_gen_h2g_i64(TCGv_i64 ret, TCGv_ptr arg);
+
/* Host pointer ops */
#if UINTPTR_MAX == UINT32_MAX
@@ -938,6 +944,11 @@ static inline void tcg_gen_addi_ptr(TCGv_ptr r, TCGv_ptr a, intptr_t b)
glue(tcg_gen_addi_,PTR)((NAT)r, (NAT)a, b);
}
+static inline void tcg_gen_subi_ptr(TCGv_ptr r, TCGv_ptr a, intptr_t b)
+{
+ glue(tcg_gen_subi_, PTR)((NAT)r, (NAT)a, b);
+}
+
static inline void tcg_gen_mov_ptr(TCGv_ptr d, TCGv_ptr s)
{
glue(tcg_gen_mov_,PTR)((NAT)d, (NAT)s);
diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
index 0875971719..7c7fafb1cd 100644
--- a/include/tcg/tcg.h
+++ b/include/tcg/tcg.h
@@ -35,6 +35,9 @@
#include "tcg-target.h"
#include "tcg/tcg-cond.h"
#include "tcg/debug-assert.h"
+#ifdef CONFIG_USER_ONLY
+#include "exec/user/guest-base.h"
+#endif
/* XXX: make safe guess about sizes */
#define MAX_OP_PER_INSTR 266
@@ -1148,4 +1151,10 @@ static inline const TCGOpcode *tcg_swap_vecop_list(const TCGOpcode *n)
bool tcg_can_emit_vecop_list(const TCGOpcode *, TCGType, unsigned);
+/* native call */
+void gen_native_call_i32(const char *fun_name, TCGv_i32 ret,
+ TCGv_i32 arg1, TCGv_i32 arg2, TCGv_i32 arg3);
+void gen_native_call_i64(const char *fun_name, TCGv_i64 ret,
+ TCGv_i64 arg1, TCGv_i64 arg2, TCGv_i64 arg3);
+
#endif /* TCG_H */
diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c
index 7aadb37756..83e3a5682c 100644
--- a/tcg/tcg-op.c
+++ b/tcg/tcg-op.c
@@ -2852,3 +2852,143 @@ void tcg_gen_lookup_and_goto_ptr(void)
tcg_gen_op1i(INDEX_op_goto_ptr, tcgv_ptr_arg(ptr));
tcg_temp_free_ptr(ptr);
}
+
+#ifdef CONFIG_USER_ONLY
+void tcg_gen_g2h_i32(TCGv_ptr ret, TCGv_i32 arg)
+{
+ TCGv_ptr temp = tcg_temp_new_ptr();
+ tcg_gen_ext_i32_ptr(temp, arg);
+ tcg_gen_addi_ptr(ret, temp, guest_base);
+ tcg_temp_free_ptr(temp);
+}
+
+void tcg_gen_g2h_i64(TCGv_ptr ret, TCGv_i64 arg)
+{
+ TCGv_ptr temp = tcg_temp_new_ptr();
+ tcg_gen_trunc_i64_ptr(temp, arg); /* Not sure */
+ tcg_gen_addi_ptr(ret, temp, guest_base);
+ tcg_temp_free_ptr(temp);
+}
+
+void tcg_gen_h2g_i32(TCGv_i32 ret, TCGv_ptr arg)
+{
+ TCGv_ptr temp = tcg_temp_new_ptr();
+ tcg_gen_subi_ptr(temp, arg, guest_base);
+ tcg_gen_trunc_ptr_i32(ret, temp);
+ tcg_temp_free_ptr(temp);
+}
+
+void tcg_gen_h2g_i64(TCGv_i64 ret, TCGv_ptr arg)
+{
+ TCGv_ptr temp = tcg_temp_new_ptr();
+ tcg_gen_subi_ptr(temp, arg, guest_base);
+ tcg_gen_extu_ptr_i64(ret, temp);
+ tcg_temp_free_ptr(temp);
+}
+
+#else
+void tcg_gen_g2h_i32(TCGv_ptr ret, TCGv_i32 arg)
+{
+}
+void tcg_gen_g2h_i64(TCGv_ptr ret, TCGv_i64 arg)
+{
+}
+void tcg_gen_h2g_i32(TCGv_i32 ret, TCGv_ptr arg)
+{
+}
+void tcg_gen_h2g_i64(TCGv_i64 ret, TCGv_ptr arg)
+{
+}
+#endif
+
+/* p: iptr ; i: i32 ; a: ptr(address) */
+void gen_native_call_i32(const char *fun_name, TCGv_i32 ret,
+ TCGv_i32 arg1, TCGv_i32 arg2, TCGv_i32 arg3)
+{
+ TCGv_ptr arg1_ptr = tcg_temp_new_ptr();
+ TCGv_ptr arg2_ptr = tcg_temp_new_ptr();
+ TCGv_ptr arg3_ptr = tcg_temp_new_ptr();
+ TCGv_ptr ret_ptr = tcg_temp_new_ptr();
+ tcg_gen_g2h_i32(arg1_ptr, arg1);
+ if (strcmp(fun_name, "memset") == 0) {/* a aip */
+ tcg_gen_ext_i32_ptr(arg3_ptr, arg3);
+ gen_helper_memset(ret_ptr, arg1_ptr, arg2, arg3_ptr);
+ goto ret_ptr;
+ }
+ tcg_gen_g2h_i32(arg2_ptr, arg2);
+ if (strcmp(fun_name, "strcpy") == 0) { /* a aa */
+ gen_helper_strcpy(ret_ptr, arg1_ptr, arg2_ptr);
+ goto ret_ptr;
+ } else if (strcmp(fun_name, "strcat") == 0) { /* a aa */
+ gen_helper_strcat(ret_ptr, arg1_ptr, arg2_ptr);
+ goto ret_ptr;
+ } else if (strcmp(fun_name, "strcmp") == 0) { /* i aa */
+ gen_helper_strcmp(ret, arg1_ptr, arg2_ptr);
+ }
+ tcg_gen_ext_i32_ptr(arg3_ptr, arg3);
+ if (strcmp(fun_name, "memcpy") == 0) { /* a aap */
+ gen_helper_memcpy(ret_ptr, arg1_ptr, arg2_ptr, arg3_ptr);
+ goto ret_ptr;
+ } else if (strcmp(fun_name, "strncpy") == 0) { /* a aap */
+ gen_helper_strncpy(ret_ptr, arg1_ptr, arg2_ptr, arg3_ptr);
+ goto ret_ptr;
+ } else if (strcmp(fun_name, "memcmp") == 0) { /* i aap */
+ gen_helper_memcmp(ret, arg1_ptr, arg2_ptr, arg3_ptr);
+ } else if (strcmp(fun_name, "strncmp") == 0) { /* i aap */
+ gen_helper_strncmp(ret, arg1_ptr, arg2_ptr, arg3_ptr);
+ }
+ return;
+ret_ptr:
+ tcg_gen_h2g_i32(ret, ret_ptr);
+ return;
+}
+
+void gen_native_call_i64(const char *fun_name, TCGv_i64 ret,
+ TCGv_i64 arg1, TCGv_i64 arg2, TCGv_i64 arg3)
+{
+ TCGv_ptr arg1_ptr = tcg_temp_new_ptr();
+ TCGv_ptr arg2_ptr = tcg_temp_new_ptr();
+ TCGv_ptr arg3_ptr = tcg_temp_new_ptr();
+ TCGv_ptr ret_ptr = tcg_temp_new_ptr();
+ TCGv_i32 arg2_i32, ret_i32 = tcg_temp_new_i32();
+ tcg_gen_g2h_i64(arg1_ptr, arg1);
+ if (strcmp(fun_name, "memset") == 0) { /* a aip */
+ arg2_i32 = tcg_temp_new_i32();
+ tcg_gen_extrl_i64_i32(arg2_i32, arg2);
+ tcg_gen_trunc_i64_ptr(arg3_ptr, arg3);
+ gen_helper_memset(ret_ptr, arg1_ptr, arg2_i32, arg3_ptr);
+ goto ret_ptr;
+ }
+ tcg_gen_g2h_i64(arg2_ptr, arg2);
+ if (strcmp(fun_name, "strcpy") == 0) { /* a aa */
+ gen_helper_strcpy(ret_ptr, arg1_ptr, arg2_ptr);
+ goto ret_ptr;
+ } else if (strcmp(fun_name, "strcat") == 0) { /* a aa */
+ gen_helper_strcat(ret_ptr, arg1_ptr, arg2_ptr);
+ goto ret_ptr;
+ } else if (strcmp(fun_name, "strcmp") == 0) { /* i aa */
+ gen_helper_strcmp(ret_i32, arg1_ptr, arg2_ptr);
+ goto ret_i32;
+ }
+ tcg_gen_trunc_i64_ptr(arg3_ptr, arg3);
+ if (strcmp(fun_name, "memcpy") == 0) { /* a aap */
+ gen_helper_memcpy(ret_ptr, arg1_ptr, arg2_ptr, arg3_ptr);
+ goto ret_ptr;
+ } else if (strcmp(fun_name, "strncpy") == 0) { /* a aap */
+ gen_helper_strncpy(ret_ptr, arg1_ptr, arg2_ptr, arg3_ptr);
+ goto ret_ptr;
+ } else if (strcmp(fun_name, "memcmp") == 0) { /* i aap */
+ gen_helper_memcmp(ret_i32, arg1_ptr, arg2_ptr, arg3_ptr);
+ goto ret_i32;
+ } else if (strcmp(fun_name, "strncmp") == 0) { /* i aap */
+ gen_helper_strncmp(ret_i32, arg1_ptr, arg2_ptr, arg3_ptr);
+ goto ret_i32;
+ }
+ return;
+ret_ptr:
+ tcg_gen_h2g_i64(ret, ret_ptr);
+ return;
+ret_i32:
+ tcg_gen_extu_i32_i64(ret, ret_i32);
+ return;
+}
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [RFC v4 07/11] target/i386: Add support for native library calls
2023-08-08 14:17 [RFC v4 00/11] Native Library Calls Yeqi Fu
` (5 preceding siblings ...)
2023-08-08 14:17 ` [RFC v4 06/11] tcg: Add tcg opcodes and helpers for native library calls Yeqi Fu
@ 2023-08-08 14:17 ` Yeqi Fu
2023-08-09 16:44 ` Richard Henderson
2023-08-08 14:17 ` [RFC v4 08/11] target/mips: " Yeqi Fu
` (3 subsequent siblings)
10 siblings, 1 reply; 31+ messages in thread
From: Yeqi Fu @ 2023-08-08 14:17 UTC (permalink / raw)
To: alex.bennee
Cc: richard.henderson, qemu-devel, Yeqi Fu, Laurent Vivier,
Paolo Bonzini, Eduardo Habkost
This commit introduces support for native library calls on the
i386 target. When special instructions reserved for native calls
are encountered, the code now performs address translation and
generates the corresponding native call.
Signed-off-by: Yeqi Fu <fufuyqqqqqq@gmail.com>
---
configs/targets/i386-linux-user.mak | 1 +
configs/targets/x86_64-linux-user.mak | 1 +
target/i386/tcg/translate.c | 27 +++++++++++++++++++++++++++
3 files changed, 29 insertions(+)
diff --git a/configs/targets/i386-linux-user.mak b/configs/targets/i386-linux-user.mak
index 5b2546a430..2d8bca8f93 100644
--- a/configs/targets/i386-linux-user.mak
+++ b/configs/targets/i386-linux-user.mak
@@ -2,3 +2,4 @@ TARGET_ARCH=i386
TARGET_SYSTBL_ABI=i386
TARGET_SYSTBL=syscall_32.tbl
TARGET_XML_FILES= gdb-xml/i386-32bit.xml
+CONFIG_NATIVE_CALL=y
diff --git a/configs/targets/x86_64-linux-user.mak b/configs/targets/x86_64-linux-user.mak
index 9ceefbb615..a53b017454 100644
--- a/configs/targets/x86_64-linux-user.mak
+++ b/configs/targets/x86_64-linux-user.mak
@@ -3,3 +3,4 @@ TARGET_BASE_ARCH=i386
TARGET_SYSTBL_ABI=common,64
TARGET_SYSTBL=syscall_64.tbl
TARGET_XML_FILES= gdb-xml/i386-64bit.xml
+CONFIG_NATIVE_CALL=y
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 90c7b32f36..28bf4477fb 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -33,6 +33,7 @@
#include "helper-tcg.h"
#include "exec/log.h"
+#include "native/native.h"
#define HELPER_H "helper.h"
#include "exec/helper-info.c.inc"
@@ -6810,6 +6811,32 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
case 0x1d0 ... 0x1fe:
disas_insn_new(s, cpu, b);
break;
+ case 0x1ff:
+ if (native_bypass_enabled()) {
+ TCGv ret = tcg_temp_new();
+ TCGv arg1 = tcg_temp_new();
+ TCGv arg2 = tcg_temp_new();
+ TCGv arg3 = tcg_temp_new();
+ const char *fun_name = lookup_symbol((s->base.pc_next) & 0xfff);
+#ifdef TARGET_X86_64
+ tcg_gen_mov_tl(arg1, cpu_regs[R_EDI]);
+ tcg_gen_mov_tl(arg2, cpu_regs[R_ESI]);
+ tcg_gen_mov_tl(arg3, cpu_regs[R_EDX]);
+ gen_native_call_i64(fun_name, ret, arg1, arg2, arg3);
+#else
+ uintptr_t ra = GETPC();
+ uint32_t a1 = cpu_ldl_data_ra(env, env->regs[R_ESP] + 4, ra);
+ uint32_t a2 = cpu_ldl_data_ra(env, env->regs[R_ESP] + 8, ra);
+ uint32_t a3 = cpu_ldl_data_ra(env, env->regs[R_ESP] + 12, ra);
+ tcg_gen_movi_tl(arg1, a1);
+ tcg_gen_movi_tl(arg2, a2);
+ tcg_gen_movi_tl(arg3, a3);
+ gen_native_call_i32(fun_name, ret, arg1, arg2, arg3);
+#endif
+ tcg_gen_mov_tl(cpu_regs[R_EAX], ret);
+ break;
+ }
+ break;
default:
goto unknown_op;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [RFC v4 08/11] target/mips: Add support for native library calls
2023-08-08 14:17 [RFC v4 00/11] Native Library Calls Yeqi Fu
` (6 preceding siblings ...)
2023-08-08 14:17 ` [RFC v4 07/11] target/i386: Add support " Yeqi Fu
@ 2023-08-08 14:17 ` Yeqi Fu
2023-08-08 14:17 ` [RFC v4 09/11] target/arm: " Yeqi Fu
` (2 subsequent siblings)
10 siblings, 0 replies; 31+ messages in thread
From: Yeqi Fu @ 2023-08-08 14:17 UTC (permalink / raw)
To: alex.bennee
Cc: richard.henderson, qemu-devel, Yeqi Fu, Laurent Vivier,
Philippe Mathieu-Daudé, Jiaxun Yang, Aurelien Jarno,
Aleksandar Rikalo
This commit introduces support for native library calls on the
mips target. When special instructions reserved for native calls
are encountered, the code now performs address translation and
generates the corresponding native call.
Signed-off-by: Yeqi Fu <fufuyqqqqqq@gmail.com>
---
configs/targets/mips-linux-user.mak | 1 +
configs/targets/mips64-linux-user.mak | 1 +
target/mips/tcg/translate.c | 21 ++++++++++++++++++++-
3 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/configs/targets/mips-linux-user.mak b/configs/targets/mips-linux-user.mak
index b4569a9893..fa005d487a 100644
--- a/configs/targets/mips-linux-user.mak
+++ b/configs/targets/mips-linux-user.mak
@@ -3,3 +3,4 @@ TARGET_ABI_MIPSO32=y
TARGET_SYSTBL_ABI=o32
TARGET_SYSTBL=syscall_o32.tbl
TARGET_BIG_ENDIAN=y
+CONFIG_NATIVE_CALL=y
diff --git a/configs/targets/mips64-linux-user.mak b/configs/targets/mips64-linux-user.mak
index d2ff509a11..ecfe6bcf73 100644
--- a/configs/targets/mips64-linux-user.mak
+++ b/configs/targets/mips64-linux-user.mak
@@ -4,3 +4,4 @@ TARGET_BASE_ARCH=mips
TARGET_SYSTBL_ABI=n64
TARGET_SYSTBL=syscall_n64.tbl
TARGET_BIG_ENDIAN=y
+CONFIG_NATIVE_CALL=y
diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c
index 74af91e4f5..51a5c1d49b 100644
--- a/target/mips/tcg/translate.c
+++ b/target/mips/tcg/translate.c
@@ -36,6 +36,7 @@
#include "exec/helper-info.c.inc"
#undef HELPER_H
+#include "native/native.h"
/*
* Many sysemu-only helpers are not reachable for user-only.
@@ -13487,7 +13488,7 @@ static void decode_opc_special_legacy(CPUMIPSState *env, DisasContext *ctx)
static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx)
{
int rs, rt, rd, sa;
- uint32_t op1;
+ uint32_t op1, sig;
rs = (ctx->opcode >> 21) & 0x1f;
rt = (ctx->opcode >> 16) & 0x1f;
@@ -13583,6 +13584,24 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx)
#endif
break;
case OPC_SYSCALL:
+ sig = (ctx->opcode) >> 6;
+ if ((sig == 0xffff) && native_bypass_enabled()) {
+ TCGv arg1 = tcg_temp_new();
+ TCGv arg2 = tcg_temp_new();
+ TCGv arg3 = tcg_temp_new();
+ TCGv ret = tcg_temp_new();
+ const char *fun_name = lookup_symbol((ctx->base.pc_next) & 0xfff);
+ tcg_gen_mov_tl(arg1, cpu_gpr[4]);
+ tcg_gen_mov_tl(arg2, cpu_gpr[5]);
+ tcg_gen_mov_tl(arg3, cpu_gpr[6]);
+#if defined(TARGET_MIPS64)
+ gen_native_call_i64(fun_name, ret, arg1, arg2, arg3);
+#else
+ gen_native_call_i32(fun_name, ret, arg1, arg2, arg3);
+#endif
+ tcg_gen_mov_tl(cpu_gpr[2], ret);
+ break;
+ }
generate_exception_end(ctx, EXCP_SYSCALL);
break;
case OPC_BREAK:
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [RFC v4 09/11] target/arm: Add support for native library calls
2023-08-08 14:17 [RFC v4 00/11] Native Library Calls Yeqi Fu
` (7 preceding siblings ...)
2023-08-08 14:17 ` [RFC v4 08/11] target/mips: " Yeqi Fu
@ 2023-08-08 14:17 ` Yeqi Fu
2023-08-08 14:17 ` [RFC v4 10/11] tests/tcg/multiarch: Add nativecall.c test Yeqi Fu
2023-08-08 14:17 ` [RFC v4 11/11] docs/user: Add doc for native library calls Yeqi Fu
10 siblings, 0 replies; 31+ messages in thread
From: Yeqi Fu @ 2023-08-08 14:17 UTC (permalink / raw)
To: alex.bennee
Cc: richard.henderson, qemu-devel, Yeqi Fu, Laurent Vivier,
Peter Maydell, open list:ARM TCG CPUs
This commit introduces support for native library calls on the
arm target. When special instructions reserved for native calls
are encountered, the code now performs address translation and
generates the corresponding native call.
Signed-off-by: Yeqi Fu <fufuyqqqqqq@gmail.com>
---
configs/targets/aarch64-linux-user.mak | 1 +
configs/targets/arm-linux-user.mak | 1 +
target/arm/tcg/translate-a64.c | 14 ++++++++++++++
target/arm/tcg/translate.c | 11 +++++++++++
4 files changed, 27 insertions(+)
diff --git a/configs/targets/aarch64-linux-user.mak b/configs/targets/aarch64-linux-user.mak
index ba8bc5fe3f..5a8fd98cd9 100644
--- a/configs/targets/aarch64-linux-user.mak
+++ b/configs/targets/aarch64-linux-user.mak
@@ -4,3 +4,4 @@ TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml gdb-xml/aarch
TARGET_HAS_BFLT=y
CONFIG_SEMIHOSTING=y
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
+CONFIG_NATIVE_CALL=y
diff --git a/configs/targets/arm-linux-user.mak b/configs/targets/arm-linux-user.mak
index 7f5d65794c..f934fb82da 100644
--- a/configs/targets/arm-linux-user.mak
+++ b/configs/targets/arm-linux-user.mak
@@ -5,3 +5,4 @@ TARGET_XML_FILES= gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml
TARGET_HAS_BFLT=y
CONFIG_SEMIHOSTING=y
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
+CONFIG_NATIVE_CALL=y
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index 3baab6aa60..422d943f92 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -25,6 +25,7 @@
#include "arm_ldst.h"
#include "semihosting/semihost.h"
#include "cpregs.h"
+#include "native/native.h"
static TCGv_i64 cpu_X[32];
static TCGv_i64 cpu_pc;
@@ -2400,6 +2401,19 @@ static bool trans_HLT(DisasContext *s, arg_i *a)
* it is required for halting debug disabled: it will UNDEF.
* Secondly, "HLT 0xf000" is the A64 semihosting syscall instruction.
*/
+ if (native_bypass_enabled() && (a->imm == 0xffff)) {
+ TCGv_i64 arg1 = tcg_temp_new_i64();
+ TCGv_i64 arg2 = tcg_temp_new_i64();
+ TCGv_i64 arg3 = tcg_temp_new_i64();
+ TCGv_i64 ret = tcg_temp_new_i64();
+ const char *fun_name = lookup_symbol((s->base.pc_next) & 0xfff);
+ tcg_gen_mov_i64(arg1, cpu_reg(s, 0));
+ tcg_gen_mov_i64(arg2, cpu_reg(s, 1));
+ tcg_gen_mov_i64(arg3, cpu_reg(s, 2));
+ gen_native_call_i64(fun_name, ret, arg1, arg2, arg3);
+ tcg_gen_mov_i64(cpu_reg(s, 0), ret);
+ return true;
+ }
if (semihosting_enabled(s->current_el == 0) && a->imm == 0xf000) {
gen_exception_internal_insn(s, EXCP_SEMIHOST);
} else {
diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c
index 13c88ba1b9..a095ebcea6 100644
--- a/target/arm/tcg/translate.c
+++ b/target/arm/tcg/translate.c
@@ -27,6 +27,7 @@
#include "arm_ldst.h"
#include "semihosting/semihost.h"
#include "cpregs.h"
+#include "native/native.h"
#include "exec/helper-proto.h"
#define HELPER_H "helper.h"
@@ -1139,6 +1140,16 @@ static inline void gen_hlt(DisasContext *s, int imm)
* semihosting, to provide some semblance of security
* (and for consistency with our 32-bit semihosting).
*/
+ if (native_bypass_enabled() && (imm == 0xffff)) {
+ TCGv_i32 arg1 = load_reg(s, 0);
+ TCGv_i32 arg2 = load_reg(s, 1);
+ TCGv_i32 arg3 = load_reg(s, 2);
+ TCGv_i32 ret = tcg_temp_new_i32();
+ const char *fun_name = lookup_symbol((s->base.pc_next) & 0xfff);
+ gen_native_call_i32(fun_name, ret, arg1, arg2, arg3);
+ store_reg(s, 0, ret);
+ return;
+ }
if (semihosting_enabled(s->current_el == 0) &&
(imm == (s->thumb ? 0x3c : 0xf000))) {
gen_exception_internal_insn(s, EXCP_SEMIHOST);
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [RFC v4 10/11] tests/tcg/multiarch: Add nativecall.c test
2023-08-08 14:17 [RFC v4 00/11] Native Library Calls Yeqi Fu
` (8 preceding siblings ...)
2023-08-08 14:17 ` [RFC v4 09/11] target/arm: " Yeqi Fu
@ 2023-08-08 14:17 ` Yeqi Fu
2023-08-09 8:42 ` Alex Bennée
` (2 more replies)
2023-08-08 14:17 ` [RFC v4 11/11] docs/user: Add doc for native library calls Yeqi Fu
10 siblings, 3 replies; 31+ messages in thread
From: Yeqi Fu @ 2023-08-08 14:17 UTC (permalink / raw)
To: alex.bennee; +Cc: richard.henderson, qemu-devel, Yeqi Fu
Introduce a new test for native calls to ensure their functionality.
The process involves cross-compiling the test cases, building them
as dynamically linked binaries, and running these binaries which
necessitates the addition of the appropriate interpreter prefix.
Signed-off-by: Yeqi Fu <fufuyqqqqqq@gmail.com>
---
tests/tcg/multiarch/Makefile.target | 17 +++++
tests/tcg/multiarch/native/nativecall.c | 98 +++++++++++++++++++++++++
2 files changed, 115 insertions(+)
create mode 100644 tests/tcg/multiarch/native/nativecall.c
diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target
index 43bddeaf21..5231df34ba 100644
--- a/tests/tcg/multiarch/Makefile.target
+++ b/tests/tcg/multiarch/Makefile.target
@@ -138,5 +138,22 @@ run-plugin-semiconsole-with-%:
TESTS += semihosting semiconsole
endif
+nativecall: native/nativecall.c
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(filter-out -static,$(LDFLAGS))
+
+ifneq ($(LD_PREFIX),)
+ifneq ($(wildcard $(LIBNATIVE)),)
+run-nativecall: nativecall
+ $(call run-test,$<, $(QEMU) -L $(LD_PREFIX) --native-bypass $(LIBNATIVE) $<, "nativecall")
+else
+run-nativecall: nativecall
+ $(call skip-test, $<, "no native library found")
+endif
+else
+run-nativecall: nativecall
+ $(call skip-test, $<, "no elf interpreter prefix found")
+endif
+EXTRA_RUNS += run-nativecall
+
# Update TESTS
TESTS += $(MULTIARCH_TESTS)
diff --git a/tests/tcg/multiarch/native/nativecall.c b/tests/tcg/multiarch/native/nativecall.c
new file mode 100644
index 0000000000..d3f6f49ed0
--- /dev/null
+++ b/tests/tcg/multiarch/native/nativecall.c
@@ -0,0 +1,98 @@
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+
+void compare_memory(const void *a, const void *b, size_t n)
+{
+ const unsigned char *p1 = a;
+ const unsigned char *p2 = b;
+ for (size_t i = 0; i < n; i++) {
+ assert(p1[i] == p2[i]);
+ }
+}
+
+void test_memcpy()
+{
+ char src[] = "Hello, world!";
+ char dest[20];
+ memcpy(dest, src, 13);
+ compare_memory(dest, src, 13);
+}
+
+void test_strncpy()
+{
+ char src[] = "Hello, world!";
+ char dest[20];
+ strncpy(dest, src, 13);
+ compare_memory(dest, src, 13);
+}
+
+void test_strcpy()
+{
+ char src[] = "Hello, world!";
+ char dest[20];
+ strcpy(dest, src);
+ compare_memory(dest, src, 13);
+}
+
+void test_strcat()
+{
+ char src[20] = "Hello, ";
+ char dst[] = "world!";
+ char str[] = "Hello, world!";
+ strcat(src, dest);
+ compare_memory(src, str, 13);
+}
+
+void test_memcmp()
+{
+ char str1[] = "abc";
+ char str2[] = "abc";
+ char str3[] = "def";
+ assert(memcmp(str1, str2, 3) == 0);
+ assert(memcmp(str1, str3, 3) != 0);
+}
+
+void test_strncmp()
+{
+ char str1[] = "abc";
+ char str2[] = "abc";
+ char str3[] = "def";
+ assert(strncmp(str1, str2, 2) == 0);
+ assert(strncmp(str1, str3, 2) != 0);
+}
+
+void test_strcmp()
+{
+ char str1[] = "abc";
+ char str2[] = "abc";
+ char str3[] = "def";
+ assert(strcmp(str1, str2) == 0);
+ assert(strcmp(str1, str3) != 0);
+}
+
+void test_memset()
+{
+ char buffer[10];
+ memset(buffer, 'A', 10);
+ int i;
+ for (i = 0; i < 10; i++) {
+ assert(buffer[i] == 'A');
+ }
+}
+
+int main()
+{
+ test_memset();
+ test_memcpy();
+ test_strncpy();
+ test_memcmp();
+ test_strncmp();
+ test_strcpy();
+ test_strcmp();
+ test_strcat();
+
+ return EXIT_SUCCESS;
+}
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [RFC v4 11/11] docs/user: Add doc for native library calls
2023-08-08 14:17 [RFC v4 00/11] Native Library Calls Yeqi Fu
` (9 preceding siblings ...)
2023-08-08 14:17 ` [RFC v4 10/11] tests/tcg/multiarch: Add nativecall.c test Yeqi Fu
@ 2023-08-08 14:17 ` Yeqi Fu
2023-08-09 12:51 ` Manos Pitsidianakis
10 siblings, 1 reply; 31+ messages in thread
From: Yeqi Fu @ 2023-08-08 14:17 UTC (permalink / raw)
To: alex.bennee; +Cc: richard.henderson, qemu-devel, Yeqi Fu
Signed-off-by: Yeqi Fu <fufuyqqqqqq@gmail.com>
---
docs/user/index.rst | 1 +
docs/user/native_calls.rst | 90 ++++++++++++++++++++++++++++++++++++++
2 files changed, 91 insertions(+)
create mode 100644 docs/user/native_calls.rst
diff --git a/docs/user/index.rst b/docs/user/index.rst
index 782d27cda2..d3fc9b7af1 100644
--- a/docs/user/index.rst
+++ b/docs/user/index.rst
@@ -12,3 +12,4 @@ processes compiled for one CPU on another CPU.
:maxdepth: 2
main
+ native_calls
diff --git a/docs/user/native_calls.rst b/docs/user/native_calls.rst
new file mode 100644
index 0000000000..c4b854096a
--- /dev/null
+++ b/docs/user/native_calls.rst
@@ -0,0 +1,90 @@
+Native Library Calls Optimization
+=================================
+
+Description
+-----------
+
+Executing a program under QEMU's user mode subjects the entire
+program, including all library calls, to translation. It's important
+to understand that many of these library functions are optimized
+specifically for the guest architecture. Therefore, their
+translation might not yield the most efficient execution.
+
+When the semantics of a library function are well defined, we can
+capitalize on this by substituting the translated version with a call
+to the native equivalent function.
+
+To achieve tangible results, focus should be given to functions such
+as memory-related ('mem*') and string-related ('str*') functions.
+These subsets of functions often have the most significant effect
+on overall performance, making them optimal candidates for
+optimization.
+
+Implementation
+--------------
+
+Upon setting the LD_PRELOAD environment variable, the dynamic linker
+will load the library specified in LD_PRELOAD preferentially. If there
+exist functions in the LD_PRELOAD library that share names with those
+in other libraries, they will override the corresponding functions in
+those other libraries.
+
+To implement native library bypass, we created a shared library and
+re-implemented the native functions within it as a special
+instruction sequence. By means of the LD_PRELOAD environment
+variable, we load this shared library into the user program.
+Therefore, when the user program calls a native function, it actually
+executes this special instruction sequence. During execution, QEMU's
+translator captures these special instructions and executes the
+corresponding native functions.
+
+These special instructions are implemented using
+architecture-specific unused or invalid opcodes, ensuring that they
+do not conflict with existing instructions.
+
+
+i386 and x86_64
+---------------
+An unused instruction is utilized to mark a native call.
+
+arm and aarch64
+---------------
+HLT is an invalid instruction for userspace and usefully has 16
+bits of spare immeadiate data which we can stuff data in.
+
+mips and mips64
+---------------
+The syscall instruction contains 20 unused bits, which are typically
+set to 0. These bits can be used to store non-zero data,
+distinguishing them from a regular syscall instruction.
+
+Usage
+-----
+
+1. Install cross-compilation tools
+
+Cross-compilation tools are required to build the shared libraries
+that can hook the necessary library functions. For example, a viable
+command on Ubuntu is:
+
+::
+
+ apt install gcc-arm-linux-gnueabihf gcc-aarch64-linux-gnu \
+ gcc-mips-linux-gnu gcc-mips64-linux-gnuabi64
+
+
+2. Locate the compiled libnative.so
+
+After compilation, the libnative.so file can be found in the
+``./build/common-user/native/<target>-linux-user`` directory.
+
+3. Run the program with the ``--native-bypass`` option
+
+To run your program with native library bypass, use the
+``--native-bypass`` option to import libnative.so:
+
+::
+
+ qemu-<target> --native-bypass \
+ ./build/common-user/native/<target>-linux-user/libnative.so ./program
+
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* Re: [RFC v4 10/11] tests/tcg/multiarch: Add nativecall.c test
2023-08-08 14:17 ` [RFC v4 10/11] tests/tcg/multiarch: Add nativecall.c test Yeqi Fu
@ 2023-08-09 8:42 ` Alex Bennée
2023-08-09 17:01 ` Alex Bennée
2023-08-09 17:12 ` Alex Bennée
2 siblings, 0 replies; 31+ messages in thread
From: Alex Bennée @ 2023-08-09 8:42 UTC (permalink / raw)
To: Yeqi Fu; +Cc: richard.henderson, qemu-devel
Yeqi Fu <fufuyqqqqqq@gmail.com> writes:
> Introduce a new test for native calls to ensure their functionality.
> The process involves cross-compiling the test cases, building them
> as dynamically linked binaries, and running these binaries which
> necessitates the addition of the appropriate interpreter prefix.
>
> Signed-off-by: Yeqi Fu <fufuyqqqqqq@gmail.com>
> ---
> tests/tcg/multiarch/Makefile.target | 17 +++++
> tests/tcg/multiarch/native/nativecall.c | 98 +++++++++++++++++++++++++
> 2 files changed, 115 insertions(+)
> create mode 100644 tests/tcg/multiarch/native/nativecall.c
>
> diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target
> index 43bddeaf21..5231df34ba 100644
> --- a/tests/tcg/multiarch/Makefile.target
> +++ b/tests/tcg/multiarch/Makefile.target
> @@ -138,5 +138,22 @@ run-plugin-semiconsole-with-%:
> TESTS += semihosting semiconsole
> endif
>
> +nativecall: native/nativecall.c
> + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(filter-out -static,$(LDFLAGS))
> +
> +ifneq ($(LD_PREFIX),)
> +ifneq ($(wildcard $(LIBNATIVE)),)
> +run-nativecall: nativecall
> + $(call run-test,$<, $(QEMU) -L $(LD_PREFIX) --native-bypass $(LIBNATIVE) $<, "nativecall")
> +else
> +run-nativecall: nativecall
> + $(call skip-test, $<, "no native library found")
> +endif
> +else
> +run-nativecall: nativecall
> + $(call skip-test, $<, "no elf interpreter prefix found")
> +endif
> +EXTRA_RUNS += run-nativecall
> +
> # Update TESTS
> TESTS += $(MULTIARCH_TESTS)
> diff --git a/tests/tcg/multiarch/native/nativecall.c b/tests/tcg/multiarch/native/nativecall.c
> new file mode 100644
> index 0000000000..d3f6f49ed0
> --- /dev/null
> +++ b/tests/tcg/multiarch/native/nativecall.c
> @@ -0,0 +1,98 @@
> +#include <assert.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <sys/mman.h>
> +
> +void compare_memory(const void *a, const void *b, size_t n)
> +{
> + const unsigned char *p1 = a;
> + const unsigned char *p2 = b;
> + for (size_t i = 0; i < n; i++) {
> + assert(p1[i] == p2[i]);
> + }
> +}
> +
> +void test_memcpy()
> +{
> + char src[] = "Hello, world!";
> + char dest[20];
> + memcpy(dest, src, 13);
> + compare_memory(dest, src, 13);
> +}
As discussed earlier expanding the range of sizes involved will help get
more coverage especially as routines are usually optimised to handle
various alignments and block sizes.
You can also use a --enable-gcov build and check how much coverage of
your new code is hit by the test cases.
> +
> +void test_strncpy()
> +{
> + char src[] = "Hello, world!";
> + char dest[20];
> + strncpy(dest, src, 13);
> + compare_memory(dest, src, 13);
> +}
> +
> +void test_strcpy()
> +{
> + char src[] = "Hello, world!";
> + char dest[20];
> + strcpy(dest, src);
> + compare_memory(dest, src, 13);
> +}
> +
> +void test_strcat()
> +{
> + char src[20] = "Hello, ";
> + char dst[] = "world!";
> + char str[] = "Hello, world!";
> + strcat(src, dest);
copy and paste fail here (dst/dest) means it doesn't compile.
It's always good practice to make sure your tree passes a make check (or
at least check-tcg in the user-mode case) to ensure no silly bugs are
present.
You can also create a gitlab account and take advantage of the CI. See
this run for example:
https://gitlab.com/stsquad/qemu/-/pipelines/959899240/failures
> + compare_memory(src, str, 13);
> +}
> +
> +void test_memcmp()
> +{
> + char str1[] = "abc";
> + char str2[] = "abc";
> + char str3[] = "def";
> + assert(memcmp(str1, str2, 3) == 0);
> + assert(memcmp(str1, str3, 3) != 0);
> +}
> +
> +void test_strncmp()
> +{
> + char str1[] = "abc";
> + char str2[] = "abc";
> + char str3[] = "def";
> + assert(strncmp(str1, str2, 2) == 0);
> + assert(strncmp(str1, str3, 2) != 0);
> +}
> +
> +void test_strcmp()
> +{
> + char str1[] = "abc";
> + char str2[] = "abc";
> + char str3[] = "def";
> + assert(strcmp(str1, str2) == 0);
> + assert(strcmp(str1, str3) != 0);
> +}
> +
> +void test_memset()
> +{
> + char buffer[10];
> + memset(buffer, 'A', 10);
> + int i;
> + for (i = 0; i < 10; i++) {
> + assert(buffer[i] == 'A');
> + }
> +}
> +
> +int main()
> +{
> + test_memset();
> + test_memcpy();
> + test_strncpy();
> + test_memcmp();
> + test_strncmp();
> + test_strcpy();
> + test_strcmp();
> + test_strcat();
> +
> + return EXIT_SUCCESS;
> +}
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [RFC v4 01/11] build: Implement logic for sharing cross-building config files
2023-08-08 14:17 ` [RFC v4 01/11] build: Implement logic for sharing cross-building config files Yeqi Fu
@ 2023-08-09 12:24 ` Manos Pitsidianakis
2023-08-09 14:42 ` Alex Bennée
2023-08-10 8:41 ` Alex Bennée
2 siblings, 0 replies; 31+ messages in thread
From: Manos Pitsidianakis @ 2023-08-09 12:24 UTC (permalink / raw)
To: qemu-devel, Yeqi Fu, alex.bennee
Cc: richard.henderson, qemu-devel, Yeqi Fu, Paolo Bonzini,
Thomas Huth
This patch needs a detailed commit message, since it's not obvious why
these changes are made at all. It'd also be helpful for reviewing.
General style comment for shell scripts: Always put curly braces around
variables even if they are unnecessary. a $source_path could become
$source_pathPREFIX in the future and instead of ${source_path} it would
expand to ${source_pathPREFIX}.
On Tue, 08 Aug 2023 16:17, Yeqi Fu <fufuyqqqqqq@gmail.com> wrote:
>+tcg_tests_targets=
>+for target in $target_list; do
>+ case $target in
>+ *-softmmu)
>+ test -f "$source_path/tests/tcg/$arch/Makefile.softmmu-target" || continue
>+ ;;
>+ esac
>
>+ if test -f cross-build/$target/config-target.mak; then
targets will never have spaces but I'd still double quote ${target} for
consistency and style
>+ mkdir -p "tests/tcg/$target"
>+ ln -srf cross-build/$target/config-target.mak tests/tcg/$target/config-target.mak
>+ ln -sf $source_path/tests/tcg/Makefile.target tests/tcg/$target/Makefile
This ln definitely needs double quoting.
> echo "run-tcg-tests-$target: $qemu\$(EXESUF)" >> Makefile.prereqs
> tcg_tests_targets="$tcg_tests_targets $target"
> fi
>--
>2.34.1
>
>
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [RFC v4 11/11] docs/user: Add doc for native library calls
2023-08-08 14:17 ` [RFC v4 11/11] docs/user: Add doc for native library calls Yeqi Fu
@ 2023-08-09 12:51 ` Manos Pitsidianakis
0 siblings, 0 replies; 31+ messages in thread
From: Manos Pitsidianakis @ 2023-08-09 12:51 UTC (permalink / raw)
To: qemu-devel, Yeqi Fu, alex.bennee; +Cc: richard.henderson, qemu-devel, Yeqi Fu
On Tue, 08 Aug 2023 16:17, Yeqi Fu <fufuyqqqqqq@gmail.com> wrote:
>+arm and aarch64
>+---------------
>+HLT is an invalid instruction for userspace and usefully has 16
>+bits of spare immeadiate data which we can stuff data in.
s/immeadiate/immediate
With that fix, you can add
Reviewed-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [RFC v4 01/11] build: Implement logic for sharing cross-building config files
2023-08-08 14:17 ` [RFC v4 01/11] build: Implement logic for sharing cross-building config files Yeqi Fu
2023-08-09 12:24 ` Manos Pitsidianakis
@ 2023-08-09 14:42 ` Alex Bennée
2023-08-09 15:23 ` Alex Bennée
2023-08-10 8:41 ` Alex Bennée
2 siblings, 1 reply; 31+ messages in thread
From: Alex Bennée @ 2023-08-09 14:42 UTC (permalink / raw)
To: Yeqi Fu; +Cc: richard.henderson, qemu-devel, Paolo Bonzini, Thomas Huth
Yeqi Fu <fufuyqqqqqq@gmail.com> writes:
> Signed-off-by: Yeqi Fu <fufuyqqqqqq@gmail.com>
> ---
> configure | 57 +++++++++++++++++++++++++++++++++----------------------
> 1 file changed, 34 insertions(+), 23 deletions(-)
>
> diff --git a/configure b/configure
> index 2b41c49c0d..a076583141 100755
> --- a/configure
> +++ b/configure
> @@ -1751,56 +1751,67 @@ if test "$ccache_cpp2" = "yes"; then
> echo "export CCACHE_CPP2=y" >> $config_host_mak
> fi
>
> -# tests/tcg configuration
> -(config_host_mak=tests/tcg/config-host.mak
> -mkdir -p tests/tcg
> -echo "# Automatically generated by configure - do not modify" > $config_host_mak
> -echo "SRC_PATH=$source_path" >> $config_host_mak
> -echo "HOST_CC=$host_cc" >> $config_host_mak
> +# Prepare the config files for cross building.
> +# This process generates 'cross-build/<target>/config-target.mak' files.
> +# These files are then symlinked to the directories that need them which
> +# including the TCG tests (tests/tcg/<target>) and the libnative library
> +# for linux-user (common/native/<target>/).
> +mkdir -p cross-build
>
> -# versioned checked in the main config_host.mak above
> -if test -n "$gdb_bin"; then
> - echo "HAVE_GDB_BIN=$gdb_bin" >> $config_host_mak
> -fi
> -if test "$plugins" = "yes" ; then
> - echo "CONFIG_PLUGIN=y" >> $config_host_mak
> -fi
I think there is a merge conflict here because a bunch of the
config-host.mak output has been squashed. This disabled plugins and gdb
testing.
> -
> -tcg_tests_targets=
> for target in $target_list; do
> arch=${target%%-*}
> -
> case $target in
> xtensa*-linux-user)
> - # the toolchain is not complete with headers, only build softmmu tests
> + # the toolchain for tests/tcg is not complete with headers
> continue
> ;;
> *-softmmu)
> - test -f "$source_path/tests/tcg/$arch/Makefile.softmmu-target" || continue
We still want to skip linking tests/tcg/foo-softmmu/config-target.mak
when there are no softmmu tests to build (only a few targets currently
have softmmu tests). I think this is triggering failures like:
➜ make run-tcg-tests-m68k-softmmu V=1
make -C tests/tcg/m68k-softmmu
make[1]: Entering directory '/home/alex/lsrc/qemu.git/builds/all/tests/tcg/m68k-softmmu'
make[1]: Nothing to be done for 'all'.
make[1]: Leaving directory '/home/alex/lsrc/qemu.git/builds/all/tests/tcg/m68k-softmmu'
make -C tests/tcg/m68k-softmmu SPEED=quick run
make[1]: Entering directory '/home/alex/lsrc/qemu.git/builds/all/tests/tcg/m68k-softmmu'
make[1]: *** No rule to make target 'hello', needed by 'run-plugin-hello-with-libbb.so'. Stop.
make[1]: Leaving directory '/home/alex/lsrc/qemu.git/builds/all/tests/tcg/m68k-softmmu'
make: *** [/home/alex/lsrc/qemu.git/tests/Makefile.include:56: run-tcg-tests-m68k-softmmu] Erro
> qemu="qemu-system-$arch"
> ;;
> *-linux-user|*-bsd-user)
> qemu="qemu-$arch"
> ;;
> esac
> -
> if probe_target_compiler $target || test -n "$container_image"; then
> test -n "$container_image" && build_static=y
> - mkdir -p "tests/tcg/$target"
> - config_target_mak=tests/tcg/$target/config-target.mak
> - ln -sf "$source_path/tests/tcg/Makefile.target" "tests/tcg/$target/Makefile"
> + mkdir -p "cross-build/$target"
> + config_target_mak=cross-build/$target/config-target.mak
> echo "# Automatically generated by configure - do not modify" > "$config_target_mak"
> echo "TARGET_NAME=$arch" >> "$config_target_mak"
> echo "TARGET=$target" >> "$config_target_mak"
> - write_target_makefile "build-tcg-tests-$target" >> "$config_target_mak"
> + write_target_makefile "$target" >> "$config_target_mak"
> echo "BUILD_STATIC=$build_static" >> "$config_target_mak"
> echo "QEMU=$PWD/$qemu" >> "$config_target_mak"
>
> + # get the interpreter prefix and the path of libnative required for native call tests
> + if [ -d "/usr/$(echo "$target_cc" | sed 's/-gcc//')" ]; then
> + echo "LD_PREFIX=/usr/$(echo "$target_cc" | sed 's/-gcc//')" >> "$config_target_mak"
> + fi
> +
We should only emit LD_PREFIX for -user targets.
> # will GDB work with these binaries?
> if test "${gdb_arches#*$arch}" != "$gdb_arches"; then
> echo "HOST_GDB_SUPPORTS_ARCH=y" >> "$config_target_mak"
> fi
> + fi
> +done
> +
> +# tests/tcg configuration
> +(mkdir -p tests/tcg
> +# create a symlink to the config-host.mak file in the tests/tcg
> +ln -srf $config_host_mak tests/tcg/config-host.mak
> +
> +tcg_tests_targets=
> +for target in $target_list; do
> + case $target in
> + *-softmmu)
> + test -f "$source_path/tests/tcg/$arch/Makefile.softmmu-target" || continue
> + ;;
> + esac
>
> + if test -f cross-build/$target/config-target.mak; then
> + mkdir -p "tests/tcg/$target"
> + ln -srf cross-build/$target/config-target.mak tests/tcg/$target/config-target.mak
> + ln -sf $source_path/tests/tcg/Makefile.target tests/tcg/$target/Makefile
> echo "run-tcg-tests-$target: $qemu\$(EXESUF)" >> Makefile.prereqs
> tcg_tests_targets="$tcg_tests_targets $target"
> fi
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [RFC v4 02/11] build: Implement libnative library and the build machinery for libnative
2023-08-08 14:17 ` [RFC v4 02/11] build: Implement libnative library and the build machinery for libnative Yeqi Fu
@ 2023-08-09 15:18 ` Alex Bennée
2023-08-09 16:10 ` Richard Henderson
1 sibling, 0 replies; 31+ messages in thread
From: Alex Bennée @ 2023-08-09 15:18 UTC (permalink / raw)
To: Yeqi Fu
Cc: richard.henderson, qemu-devel, Paolo Bonzini, Thomas Huth,
Riku Voipio
Yeqi Fu <fufuyqqqqqq@gmail.com> writes:
> This commit implements a shared library, where native functions are
> rewritten as special instructions. At runtime, user programs load
> the shared library, and special instructions are executed when
> native functions are called.
>
> Signed-off-by: Yeqi Fu <fufuyqqqqqq@gmail.com>
> ---
> Makefile | 2 +
> common-user/native/Makefile.include | 9 ++++
> common-user/native/Makefile.target | 22 ++++++++++
> common-user/native/libnative.c | 67 +++++++++++++++++++++++++++++
> configure | 39 +++++++++++++++++
> include/native/libnative.h | 8 ++++
> 6 files changed, 147 insertions(+)
> create mode 100644 common-user/native/Makefile.include
> create mode 100644 common-user/native/Makefile.target
> create mode 100644 common-user/native/libnative.c
> create mode 100644 include/native/libnative.h
>
> diff --git a/Makefile b/Makefile
> index 5d48dfac18..6f6147b40f 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -182,6 +182,8 @@ SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory --quiet)
>
> include $(SRC_PATH)/tests/Makefile.include
>
> +include $(SRC_PATH)/common-user/native/Makefile.include
> +
> all: recurse-all
>
> ROMS_RULES=$(foreach t, all clean distclean, $(addsuffix /$(t), $(ROMS)))
> diff --git a/common-user/native/Makefile.include b/common-user/native/Makefile.include
> new file mode 100644
> index 0000000000..40d20bcd4c
> --- /dev/null
> +++ b/common-user/native/Makefile.include
> @@ -0,0 +1,9 @@
> +.PHONY: build-native
> +build-native: $(NATIVE_TARGETS:%=build-native-library-%)
> +$(NATIVE_TARGETS:%=build-native-library-%): build-native-library-%:
> + $(call quiet-command, \
> + $(MAKE) -C common-user/native/$* $(SUBDIR_MAKEFLAGS), \
> + "BUILD","$* native library")
> +# endif
> +
> +all: build-native
> diff --git a/common-user/native/Makefile.target b/common-user/native/Makefile.target
> new file mode 100644
> index 0000000000..0c1241b368
> --- /dev/null
> +++ b/common-user/native/Makefile.target
> @@ -0,0 +1,22 @@
> +# -*- Mode: makefile -*-
> +#
> +# Library for native calls
> +#
> +
> +all:
> +-include ../../config-host.mak
This is sensitive to the out of tree build structure the user chooses. For
example:
➜ pwd
/home/alex/lsrc/qemu.git/builds/user/common-user/native/aarch64-linux-user
🕙16:20:08 alex@zen:common-user/native/aarch64-linux-user on review/native-lib-calls-v4 [$!?]
➜ make libnative.so
make: *** No rule to make target '/common-user/native/libnative.c', needed by 'libnative.so'. Stop.
🕙16:20:13 alex@zen:common-user/native/aarch64-linux-user on review/native-lib-calls-v4 [$!?] [🔴 USAGE]
✗
I think this can be solved the same way as we do for tests/tcg by
symlinking the config-host.mak into place and referring to it directly
or adjusting the include to ../../../config-host.mak because the top of
the build tree has a symlinked copy as well.
> +-include config-target.mak
> +
> +CFLAGS+=-O1 -fPIC -shared -fno-stack-protector -I$(SRC_PATH)/include -D$(TARGET_NAME)
> +LDFLAGS+=
> +
> +SRC = $(SRC_PATH)/common-user/native/libnative.c
> +LIBNATIVE = libnative.so
> +
> +all: $(LIBNATIVE)
> +
> +$(LIBNATIVE): $(SRC)
> + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(EXTRA_NATIVE_CALL_FLAGS) $< -o $@ $(LDFLAGS)
> +
> +clean:
> + rm -f $(LIBNATIVE)
> diff --git a/common-user/native/libnative.c b/common-user/native/libnative.c
> new file mode 100644
> index 0000000000..662ae6fbfe
> --- /dev/null
> +++ b/common-user/native/libnative.c
> @@ -0,0 +1,67 @@
> +#include <stdint.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +
> +#include "native/libnative.h"
> +
> +#define WRAP_NATIVE() \
> + do { \
> + __asm__ volatile(__CALL_EXPR : : : "memory"); \
> + } while (0)
> +
> +#if defined(i386) || defined(x86_64)
> +/*
> + * An unused instruction is utilized to mark a native call.
> + */
> +#define __CALL_EXPR ".byte 0x0f, 0xff;"
> +#endif
> +
> +#if defined(arm) || defined(aarch64)
> +/*
> + * HLT is an invalid instruction for userspace and usefully has 16
> + * bits of spare immeadiate data which we can stuff data in.
> + */
> +#define __CALL_EXPR "hlt 0xffff;"
> +#endif
> +
> +#if defined(mips) || defined(mips64)
> +/*
> + * The syscall instruction contains 20 unused bits, which are typically
> + * set to 0. These bits can be used to store non-zero data,
> + * distinguishing them from a regular syscall instruction.
> + */
> +#define __CALL_EXPR "syscall 0xffff;"
> +#endif
> +
> +void *memcpy(void *dest, const void *src, size_t n)
> +{
> + WRAP_NATIVE();
> +}
> +int memcmp(const void *s1, const void *s2, size_t n)
> +{
> + WRAP_NATIVE();
> +}
> +void *memset(void *s, int c, size_t n)
> +{
> + WRAP_NATIVE();
> +}
> +char *strncpy(char *dest, const char *src, size_t n)
> +{
> + WRAP_NATIVE();
> +}
> +int strncmp(const char *s1, const char *s2, size_t n)
> +{
> + WRAP_NATIVE();
> +}
> +char *strcpy(char *dest, const char *src)
> +{
> + WRAP_NATIVE();
> +}
> +char *strcat(char *dest, const char *src)
> +{
> + WRAP_NATIVE();
> +}
> +int strcmp(const char *s1, const char *s2)
> +{
> + WRAP_NATIVE();
> +}
> diff --git a/configure b/configure
> index a076583141..e02fc2c5c0 100755
> --- a/configure
> +++ b/configure
> @@ -1822,6 +1822,45 @@ if test "$tcg" = "enabled"; then
> fi
> )
>
> +# common-user/native configuration
> +(mkdir -p common-user/native
> +
> +native_targets=
> +for target in $target_list; do
> + case $target in
> + *-softmmu)
> + continue
> + ;;
> + esac
> +
> + # native call is only supported on these architectures
> + arch=${target%%-*}
> + config_target_mak=common-user/native/$target/config-target.mak
> + case $arch in
> + i386|x86_64|arm|aarch64|mips|mips64)
> + if test -f cross-build/$target/config-target.mak; then
> + mkdir -p "common-user/native/$target"
> + ln -srf cross-build/$target/config-target.mak "$config_target_mak"
> + if test $arch = arm; then
> + echo "EXTRA_NATIVE_CALL_FLAGS=-marm" >> "$config_target_mak"
> + fi
> + if test $arch = $cpu || \
> + { test $arch = i386 && test $cpu = x86_64; } || \
> + { test $arch = arm && test $cpu = aarch64; } || \
> + { test $arch = mips && test $cpu = mips64; }; then
> + echo "LD_PREFIX=/" >> "$config_target_mak"
> + fi
> + echo "LIBNATIVE=$PWD/common-user/native/$target/libnative.so" >> "$config_target_mak"
> + ln -sf $source_path/common-user/native/Makefile.target common-user/native/$target/Makefile
> + native_targets="$native_targets $target"
> + fi
> + ;;
> + esac
> +done
> +
> +echo "NATIVE_TARGETS=$native_targets" >> config-host.mak
> +)
> +
> if test "$skip_meson" = no; then
> cross="config-meson.cross.new"
> meson_quote() {
> diff --git a/include/native/libnative.h b/include/native/libnative.h
> new file mode 100644
> index 0000000000..ec990d8e5f
> --- /dev/null
> +++ b/include/native/libnative.h
> @@ -0,0 +1,8 @@
> +void *memset(void *s, int c, size_t n);
> +void *memcpy(void *dest, const void *src, size_t n);
> +char *strncpy(char *dest, const char *src, size_t n);
> +int memcmp(const void *s1, const void *s2, size_t n);
> +int strncmp(const char *s1, const char *s2, size_t n);
> +char *strcpy(char *dest, const char *src);
> +char *strcat(char *dest, const char *src);
> +int strcmp(const char *s1, const char *s2);
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [RFC v4 01/11] build: Implement logic for sharing cross-building config files
2023-08-09 14:42 ` Alex Bennée
@ 2023-08-09 15:23 ` Alex Bennée
0 siblings, 0 replies; 31+ messages in thread
From: Alex Bennée @ 2023-08-09 15:23 UTC (permalink / raw)
To: Alex Bennée
Cc: Yeqi Fu, richard.henderson, qemu-devel, Paolo Bonzini,
Thomas Huth
Alex Bennée <alex.bennee@linaro.org> writes:
> Yeqi Fu <fufuyqqqqqq@gmail.com> writes:
>
>> Signed-off-by: Yeqi Fu <fufuyqqqqqq@gmail.com>
>> ---
>> configure | 57 +++++++++++++++++++++++++++++++++----------------------
>> 1 file changed, 34 insertions(+), 23 deletions(-)
>>
>> diff --git a/configure b/configure
>> index 2b41c49c0d..a076583141 100755
>> --- a/configure
>> +++ b/configure
>> @@ -1751,56 +1751,67 @@ if test "$ccache_cpp2" = "yes"; then
>> echo "export CCACHE_CPP2=y" >> $config_host_mak
>> fi
>>
>> -# tests/tcg configuration
>> -(config_host_mak=tests/tcg/config-host.mak
>> -mkdir -p tests/tcg
>> -echo "# Automatically generated by configure - do not modify" > $config_host_mak
>> -echo "SRC_PATH=$source_path" >> $config_host_mak
>> -echo "HOST_CC=$host_cc" >> $config_host_mak
>> +# Prepare the config files for cross building.
>> +# This process generates 'cross-build/<target>/config-target.mak' files.
>> +# These files are then symlinked to the directories that need them which
>> +# including the TCG tests (tests/tcg/<target>) and the libnative library
>> +# for linux-user (common/native/<target>/).
>> +mkdir -p cross-build
>>
>> -# versioned checked in the main config_host.mak above
>> -if test -n "$gdb_bin"; then
>> - echo "HAVE_GDB_BIN=$gdb_bin" >> $config_host_mak
>> -fi
>> -if test "$plugins" = "yes" ; then
>> - echo "CONFIG_PLUGIN=y" >> $config_host_mak
>> -fi
>
> I think there is a merge conflict here because a bunch of the
> config-host.mak output has been squashed. This disabled plugins and gdb
> testing.
Ahh I see now this was intentional because we symlink however it was
lost in the noise of the diff. As Manos pointed out detailing the
movement in the commit message aids reviewers in tracing what has
changed.
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [RFC v4 03/11] linux-user: Implement envlist_appendenv and add tests for envlist
2023-08-08 14:17 ` [RFC v4 03/11] linux-user: Implement envlist_appendenv and add tests for envlist Yeqi Fu
@ 2023-08-09 15:27 ` Alex Bennée
2023-08-09 15:44 ` Richard Henderson
2023-08-09 16:06 ` Richard Henderson
2 siblings, 0 replies; 31+ messages in thread
From: Alex Bennée @ 2023-08-09 15:27 UTC (permalink / raw)
To: Yeqi Fu; +Cc: richard.henderson, qemu-devel
Yeqi Fu <fufuyqqqqqq@gmail.com> writes:
> Signed-off-by: Yeqi Fu <fufuyqqqqqq@gmail.com>
> ---
> include/qemu/envlist.h | 13 ++++++
> tests/unit/meson.build | 1 +
> tests/unit/test-envlist.c | 94 +++++++++++++++++++++++++++++++++++++++
> util/envlist.c | 71 ++++++++++++++++++++++++-----
> 4 files changed, 169 insertions(+), 10 deletions(-)
> create mode 100644 tests/unit/test-envlist.c
Thanks for adding the unit test.
>
> +/*
> + * Appends environment value to envlist. If the environment
> + * variable already exists, the new value is appended to the
> + * existing one.
> + *
> + * Returns 0 in success, errno otherwise.
> + */
> +int
> +envlist_appendenv(envlist_t *envlist, const char *env, const char *separator)
> +{
> + struct envlist_entry *entry = NULL;
> + const char *eq_sign;
> + size_t envname_len;
> +
> + if ((envlist == NULL) || (env == NULL) || (separator == NULL)) {
> + return -EINVAL;
> + }
> +
> + /* find out first equals sign in given env */
> + eq_sign = strchr(env, '=');
> + if (eq_sign == NULL) {
> + return -EINVAL;
> + }
> +
> + if (strchr(eq_sign + 1, '=') != NULL) {
> + return -EINVAL;
> + }
> +
> + envname_len = eq_sign - env + 1;
> +
> + /*
> + * If there already exists variable with given name,
> + * we append the new value to the existing one.
> + */
> + for (entry = envlist->el_entries.lh_first; entry != NULL;
> + entry = entry->ev_link.le_next) {
> + if (strncmp(entry->ev_var, env, envname_len) == 0) {
> + break;
> + }
> + }
> +
> + if (entry != NULL) {
> + char *new_env_value = NULL;
> + size_t new_env_len = strlen(entry->ev_var) + strlen(eq_sign)
> + + strlen(separator) + 1;
> + new_env_value = g_malloc(new_env_len);
> + strcpy(new_env_value, entry->ev_var);
> + strcat(new_env_value, separator);
> + strcat(new_env_value, eq_sign + 1);
> + g_free((char *)entry->ev_var);
> + entry->ev_var = new_env_value;
You could probably avoid messing about with strlens if you used the
handy glib functions:
if (entry != NULL) {
GString *new_val = g_string_new(entry->ev_var);
g_string_append(new_val, separator);
g_string_append(new_val, eq_sign + 1);
g_free(entry->ev_var);
entry->ev_var = g_string_free(new_val, false);
} else {
Also the fact you needed to cast entry->ev_var to g_free() should have
pointed out that now we can change env entries we need to drop the const
from the char *ev_var; definition in envlist_entry.
Otherwise with those fixes:
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [RFC v4 04/11] linux-user: Implement native-bypass option support
2023-08-08 14:17 ` [RFC v4 04/11] linux-user: Implement native-bypass option support Yeqi Fu
@ 2023-08-09 15:42 ` Richard Henderson
2023-08-09 15:47 ` Alex Bennée
1 sibling, 0 replies; 31+ messages in thread
From: Richard Henderson @ 2023-08-09 15:42 UTC (permalink / raw)
To: Yeqi Fu, alex.bennee; +Cc: qemu-devel, Laurent Vivier
On 8/8/23 07:17, Yeqi Fu wrote:
> +#define native_bypass_enabled() native_lib_path ? true : false
Need parenthesis for the expression, and possibly better as
(native_lib_path != NULL)
rather than ternary expression.
> +#if defined(CONFIG_NATIVE_CALL)
> + /* Set the library for native bypass */
> + if (native_lib_path) {
> + if (g_file_test(native_lib_path, G_FILE_TEST_EXISTS)) {
G_FILE_TEST_EXISTS may be a directory.
Better with G_FILE_TEST_IS_REGULAR, I guess?
r~
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [RFC v4 03/11] linux-user: Implement envlist_appendenv and add tests for envlist
2023-08-08 14:17 ` [RFC v4 03/11] linux-user: Implement envlist_appendenv and add tests for envlist Yeqi Fu
2023-08-09 15:27 ` Alex Bennée
@ 2023-08-09 15:44 ` Richard Henderson
2023-08-09 16:06 ` Richard Henderson
2 siblings, 0 replies; 31+ messages in thread
From: Richard Henderson @ 2023-08-09 15:44 UTC (permalink / raw)
To: Yeqi Fu, alex.bennee; +Cc: qemu-devel
On 8/8/23 07:17, Yeqi Fu wrote:
> Signed-off-by: Yeqi Fu <fufuyqqqqqq@gmail.com>
> ---
> include/qemu/envlist.h | 13 ++++++
> tests/unit/meson.build | 1 +
> tests/unit/test-envlist.c | 94 +++++++++++++++++++++++++++++++++++++++
> util/envlist.c | 71 ++++++++++++++++++++++++-----
> 4 files changed, 169 insertions(+), 10 deletions(-)
> create mode 100644 tests/unit/test-envlist.c
>
> diff --git a/include/qemu/envlist.h b/include/qemu/envlist.h
> index 6006dfae44..9eb1459e79 100644
> --- a/include/qemu/envlist.h
> +++ b/include/qemu/envlist.h
> @@ -1,12 +1,25 @@
> #ifndef ENVLIST_H
> #define ENVLIST_H
>
> +#include "qemu/queue.h"
> +
> +struct envlist_entry {
> + const char *ev_var; /* actual env value */
> + QLIST_ENTRY(envlist_entry) ev_link;
> +};
> +
> +struct envlist {
> + QLIST_HEAD(, envlist_entry) el_entries; /* actual entries */
> + size_t el_count; /* number of entries */
> +};
> +
Why are you exposing the structures?
> +static void envlist_parse_set_unset_test(void)
> +{
> + envlist_t *testenvlist;
> + const char *env = "TEST1=123,TEST2=456";
> +
> + testenvlist = envlist_create();
> + g_assert(envlist_parse_set(testenvlist, env) == 0);
> + g_assert(testenvlist->el_count == 2);
> + g_assert(envlist_parse_unset(testenvlist, "TEST1,TEST2") == 0);
> + g_assert(testenvlist->el_count == 0);
If it's just for the count, then add an envlist_length() function.
r~
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [RFC v4 04/11] linux-user: Implement native-bypass option support
2023-08-08 14:17 ` [RFC v4 04/11] linux-user: Implement native-bypass option support Yeqi Fu
2023-08-09 15:42 ` Richard Henderson
@ 2023-08-09 15:47 ` Alex Bennée
1 sibling, 0 replies; 31+ messages in thread
From: Alex Bennée @ 2023-08-09 15:47 UTC (permalink / raw)
To: Yeqi Fu; +Cc: richard.henderson, qemu-devel, Laurent Vivier
Yeqi Fu <fufuyqqqqqq@gmail.com> writes:
> This commit implements the -native-bypass support in linux-user. The
> native_calls_enabled() function can be true only when the
> '-native-bypass' option is given.
>
> Signed-off-by: Yeqi Fu <fufuyqqqqqq@gmail.com>
> ---
> include/native/native.h | 9 +++++++++
> linux-user/main.c | 38 ++++++++++++++++++++++++++++++++++++++
> 2 files changed, 47 insertions(+)
> create mode 100644 include/native/native.h
>
> diff --git a/include/native/native.h b/include/native/native.h
> new file mode 100644
> index 0000000000..62951fafb1
> --- /dev/null
> +++ b/include/native/native.h
> @@ -0,0 +1,9 @@
> +/*
> + * Check if the native bypass feature is enabled.
> + */
> +#if defined(CONFIG_USER_ONLY) && defined(CONFIG_NATIVE_CALL)
> +extern char *native_lib_path;
> +#define native_bypass_enabled() native_lib_path ? true : false
> +#else
> +#define native_bypass_enabled() false
> +#endif
> diff --git a/linux-user/main.c b/linux-user/main.c
> index dba67ffa36..86ea0191f7 100644
> --- a/linux-user/main.c
> +++ b/linux-user/main.c
> @@ -60,6 +60,11 @@
> #include "semihosting/semihost.h"
> #endif
>
> +#if defined(CONFIG_NATIVE_CALL)
> +#include "native/native.h"
> +char *native_lib_path;
> +#endif
> +
> #ifndef AT_FLAGS_PRESERVE_ARGV0
> #define AT_FLAGS_PRESERVE_ARGV0_BIT 0
> #define AT_FLAGS_PRESERVE_ARGV0 (1 << AT_FLAGS_PRESERVE_ARGV0_BIT)
> @@ -293,6 +298,17 @@ static void handle_arg_set_env(const char *arg)
> free(r);
> }
>
> +#if defined(CONFIG_NATIVE_CALL)
> +static void handle_arg_native_bypass(const char *arg)
> +{
> + if (access(arg, F_OK) != 0) {
> + fprintf(stderr, "native library %s does not exist\n", arg);
> + exit(EXIT_FAILURE);
> + }
> + native_lib_path = strdup(arg);
Although we never free this the coding style states:
Because of the memory management rules, you must use g_strdup/g_strndup
instead of plain strdup/strndup.
We do still have a few legacy strdup's to eliminate from the code base
though.
> +}
> +#endif
> +
> static void handle_arg_unset_env(const char *arg)
> {
> char *r, *p, *token;
> @@ -522,6 +538,10 @@ static const struct qemu_argument arg_table[] = {
> "", "Generate a /tmp/perf-${pid}.map file for perf"},
> {"jitdump", "QEMU_JITDUMP", false, handle_arg_jitdump,
> "", "Generate a jit-${pid}.dump file for perf"},
> +#if defined(CONFIG_NATIVE_CALL)
> + {"native-bypass", "QEMU_NATIVE_BYPASS", true, handle_arg_native_bypass,
> + "", "native bypass for library calls in user mode only."},
> +#endif
You can drop " in user mode only" because this help text will only show
up on linux-user binaries with support for native bypass.
Otherwise:
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [RFC v4 03/11] linux-user: Implement envlist_appendenv and add tests for envlist
2023-08-08 14:17 ` [RFC v4 03/11] linux-user: Implement envlist_appendenv and add tests for envlist Yeqi Fu
2023-08-09 15:27 ` Alex Bennée
2023-08-09 15:44 ` Richard Henderson
@ 2023-08-09 16:06 ` Richard Henderson
2 siblings, 0 replies; 31+ messages in thread
From: Richard Henderson @ 2023-08-09 16:06 UTC (permalink / raw)
To: Yeqi Fu, alex.bennee; +Cc: qemu-devel
On 8/8/23 07:17, Yeqi Fu wrote:
> + char *new_env_value = NULL;
> + size_t new_env_len = strlen(entry->ev_var) + strlen(eq_sign)
> + + strlen(separator) + 1;
> + new_env_value = g_malloc(new_env_len);
> + strcpy(new_env_value, entry->ev_var);
> + strcat(new_env_value, separator);
> + strcat(new_env_value, eq_sign + 1);
This is
new_env_value = g_strconcat(entry->ev_var, separator, eq_sign + 1, NULL);
r~
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [RFC v4 02/11] build: Implement libnative library and the build machinery for libnative
2023-08-08 14:17 ` [RFC v4 02/11] build: Implement libnative library and the build machinery for libnative Yeqi Fu
2023-08-09 15:18 ` Alex Bennée
@ 2023-08-09 16:10 ` Richard Henderson
1 sibling, 0 replies; 31+ messages in thread
From: Richard Henderson @ 2023-08-09 16:10 UTC (permalink / raw)
To: Yeqi Fu, alex.bennee; +Cc: qemu-devel, Paolo Bonzini, Thomas Huth, Riku Voipio
On 8/8/23 07:17, Yeqi Fu wrote:
> +#if defined(i386) || defined(x86_64)
> +/*
> + * An unused instruction is utilized to mark a native call.
> + */
> +#define __CALL_EXPR ".byte 0x0f, 0xff;"
> +#endif
This is 2 of the 3 (or more) bytes of the UD0 instruction.
At minimum you should include a third byte for the modrm.
For example,
0F FF C0 ud0 %eax, %eax
If you want to encode more data, or simply magic numbers, you can use
0F FF 80
78 56 34 12 ud0 0x12345678(%eax), %eax
or with modrm + sib bytes,
0F FF 84 00
78 56 34 12 ud0 0x12345678(%eax, %eax, 0), %eax
So you have up to 32 (displacement) + 3 * 3 (registers) + 2 (shift) = 43 bits that you can
vary while staying within the encoding of UD0.
You can even have the assembler help encode a displacement to associated data:
.text
0: ud0 label-0b(%eax), %eax
.rodata
label: .byte some stuff
r~
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [RFC v4 05/11] linux-user/elfload: Add support for parsing symbols of native libraries.
2023-08-08 14:17 ` [RFC v4 05/11] linux-user/elfload: Add support for parsing symbols of native libraries Yeqi Fu
@ 2023-08-09 16:14 ` Richard Henderson
2023-08-09 17:04 ` Alex Bennée
0 siblings, 1 reply; 31+ messages in thread
From: Richard Henderson @ 2023-08-09 16:14 UTC (permalink / raw)
To: Yeqi Fu, alex.bennee; +Cc: qemu-devel, Laurent Vivier
On 8/8/23 07:17, Yeqi Fu wrote:
> This commit addresses the need to parse symbols of native libraries.
> The base address of a shared library is determined by the dynamic
> linker. To simplify the process, we focus on the last three digits,
> which reside within the same page and remain unaffected by the base
> address.
>
> Signed-off-by: Yeqi Fu<fufuyqqqqqq@gmail.com>
> ---
> linux-user/elfload.c | 85 +++++++++++++++++++++++++++++++++++++++++---
> 1 file changed, 80 insertions(+), 5 deletions(-)
I'm not keen on this. I would much prefer the native library to be self-contained and not
rely on symbols in this fashion.
r~
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [RFC v4 06/11] tcg: Add tcg opcodes and helpers for native library calls
2023-08-08 14:17 ` [RFC v4 06/11] tcg: Add tcg opcodes and helpers for native library calls Yeqi Fu
@ 2023-08-09 16:41 ` Alex Bennée
0 siblings, 0 replies; 31+ messages in thread
From: Alex Bennée @ 2023-08-09 16:41 UTC (permalink / raw)
To: Yeqi Fu; +Cc: richard.henderson, qemu-devel, Paolo Bonzini
Yeqi Fu <fufuyqqqqqq@gmail.com> writes:
> This commit implements tcg opcodes and helpers for extracting and
> invoke native functions.
>
> Signed-off-by: Yeqi Fu <fufuyqqqqqq@gmail.com>
> ---
> accel/tcg/tcg-runtime.h | 22 ++++++
> include/tcg/tcg-op-common.h | 11 +++
> include/tcg/tcg.h | 9 +++
> tcg/tcg-op.c | 140 ++++++++++++++++++++++++++++++++++++
> 4 files changed, 182 insertions(+)
>
> diff --git a/accel/tcg/tcg-runtime.h b/accel/tcg/tcg-runtime.h
> index 39e68007f9..bda78b4489 100644
> --- a/accel/tcg/tcg-runtime.h
> +++ b/accel/tcg/tcg-runtime.h
> @@ -37,6 +37,28 @@ DEF_HELPER_FLAGS_1(exit_atomic, TCG_CALL_NO_WG, noreturn, env)
> */
> #define helper_memset memset
> DEF_HELPER_FLAGS_3(memset, TCG_CALL_NO_RWG, ptr, ptr, int, ptr)
> +
> +#define helper_memcpy memcpy
> +DEF_HELPER_FLAGS_3(memcpy, TCG_CALL_NO_RWG, ptr, ptr, ptr, ptr)
> +
> +#define helper_strncpy strncpy
> +DEF_HELPER_FLAGS_3(strncpy, TCG_CALL_NO_RWG, ptr, ptr, ptr, ptr)
> +
> +#define helper_memcmp memcmp
> +DEF_HELPER_FLAGS_3(memcmp, TCG_CALL_NO_RWG, int, ptr, ptr, ptr)
> +
> +#define helper_strncmp strncmp
> +DEF_HELPER_FLAGS_3(strncmp, TCG_CALL_NO_RWG, int, ptr, ptr, ptr)
> +
> +#define helper_strcpy strcpy
> +DEF_HELPER_FLAGS_2(strcpy, TCG_CALL_NO_RWG, ptr, ptr, ptr)
> +
> +#define helper_strcat strcat
> +DEF_HELPER_FLAGS_2(strcat, TCG_CALL_NO_RWG, ptr, ptr, ptr)
> +
> +#define helper_strcmp strcmp
> +DEF_HELPER_FLAGS_2(strcmp, TCG_CALL_NO_RWG, int, ptr, ptr)
> +
> #endif /* IN_HELPER_PROTO */
>
> DEF_HELPER_FLAGS_3(ld_i128, TCG_CALL_NO_WG, i128, env, i64, i32)
> diff --git a/include/tcg/tcg-op-common.h b/include/tcg/tcg-op-common.h
> index be382bbf77..2e712f1573 100644
> --- a/include/tcg/tcg-op-common.h
> +++ b/include/tcg/tcg-op-common.h
> @@ -903,6 +903,12 @@ void tcg_gen_ld_vec(TCGv_vec r, TCGv_ptr base, TCGArg offset);
> void tcg_gen_st_vec(TCGv_vec r, TCGv_ptr base, TCGArg offset);
> void tcg_gen_stl_vec(TCGv_vec r, TCGv_ptr base, TCGArg offset, TCGType t);
>
> +/* Host <-> guest conversions */
> +void tcg_gen_g2h_i32(TCGv_ptr ret, TCGv_i32 arg);
> +void tcg_gen_g2h_i64(TCGv_ptr ret, TCGv_i64 arg);
> +void tcg_gen_h2g_i32(TCGv_i32 ret, TCGv_ptr arg);
> +void tcg_gen_h2g_i64(TCGv_i64 ret, TCGv_ptr arg);
> +
> /* Host pointer ops */
>
> #if UINTPTR_MAX == UINT32_MAX
> @@ -938,6 +944,11 @@ static inline void tcg_gen_addi_ptr(TCGv_ptr r, TCGv_ptr a, intptr_t b)
> glue(tcg_gen_addi_,PTR)((NAT)r, (NAT)a, b);
> }
>
> +static inline void tcg_gen_subi_ptr(TCGv_ptr r, TCGv_ptr a, intptr_t b)
> +{
> + glue(tcg_gen_subi_, PTR)((NAT)r, (NAT)a, b);
> +}
> +
> static inline void tcg_gen_mov_ptr(TCGv_ptr d, TCGv_ptr s)
> {
> glue(tcg_gen_mov_,PTR)((NAT)d, (NAT)s);
> diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
> index 0875971719..7c7fafb1cd 100644
> --- a/include/tcg/tcg.h
> +++ b/include/tcg/tcg.h
> @@ -35,6 +35,9 @@
> #include "tcg-target.h"
> #include "tcg/tcg-cond.h"
> #include "tcg/debug-assert.h"
> +#ifdef CONFIG_USER_ONLY
> +#include "exec/user/guest-base.h"
> +#endif
>
> /* XXX: make safe guess about sizes */
> #define MAX_OP_PER_INSTR 266
> @@ -1148,4 +1151,10 @@ static inline const TCGOpcode *tcg_swap_vecop_list(const TCGOpcode *n)
>
> bool tcg_can_emit_vecop_list(const TCGOpcode *, TCGType, unsigned);
>
> +/* native call */
> +void gen_native_call_i32(const char *fun_name, TCGv_i32 ret,
> + TCGv_i32 arg1, TCGv_i32 arg2, TCGv_i32 arg3);
> +void gen_native_call_i64(const char *fun_name, TCGv_i64 ret,
> + TCGv_i64 arg1, TCGv_i64 arg2, TCGv_i64 arg3);
> +
> #endif /* TCG_H */
> diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c
> index 7aadb37756..83e3a5682c 100644
> --- a/tcg/tcg-op.c
> +++ b/tcg/tcg-op.c
> @@ -2852,3 +2852,143 @@ void tcg_gen_lookup_and_goto_ptr(void)
> tcg_gen_op1i(INDEX_op_goto_ptr, tcgv_ptr_arg(ptr));
> tcg_temp_free_ptr(ptr);
> }
> +
> +#ifdef CONFIG_USER_ONLY
> +void tcg_gen_g2h_i32(TCGv_ptr ret, TCGv_i32 arg)
> +{
> + TCGv_ptr temp = tcg_temp_new_ptr();
> + tcg_gen_ext_i32_ptr(temp, arg);
> + tcg_gen_addi_ptr(ret, temp, guest_base);
> + tcg_temp_free_ptr(temp);
> +}
> +
> +void tcg_gen_g2h_i64(TCGv_ptr ret, TCGv_i64 arg)
> +{
> + TCGv_ptr temp = tcg_temp_new_ptr();
> + tcg_gen_trunc_i64_ptr(temp, arg); /* Not sure */
> + tcg_gen_addi_ptr(ret, temp, guest_base);
> + tcg_temp_free_ptr(temp);
> +}
> +
> +void tcg_gen_h2g_i32(TCGv_i32 ret, TCGv_ptr arg)
> +{
> + TCGv_ptr temp = tcg_temp_new_ptr();
> + tcg_gen_subi_ptr(temp, arg, guest_base);
> + tcg_gen_trunc_ptr_i32(ret, temp);
> + tcg_temp_free_ptr(temp);
> +}
> +
> +void tcg_gen_h2g_i64(TCGv_i64 ret, TCGv_ptr arg)
> +{
> + TCGv_ptr temp = tcg_temp_new_ptr();
> + tcg_gen_subi_ptr(temp, arg, guest_base);
> + tcg_gen_extu_ptr_i64(ret, temp);
> + tcg_temp_free_ptr(temp);
> +}
> +
> +#else
> +void tcg_gen_g2h_i32(TCGv_ptr ret, TCGv_i32 arg)
> +{
It would be worth adding g_assert_not_reached() to these stubs so any
accidental call gets flagged straight away.
> +}
> +void tcg_gen_g2h_i64(TCGv_ptr ret, TCGv_i64 arg)
> +{
> +}
> +void tcg_gen_h2g_i32(TCGv_i32 ret, TCGv_ptr arg)
> +{
> +}
> +void tcg_gen_h2g_i64(TCGv_i64 ret, TCGv_ptr arg)
> +{
> +}
> +#endif
> +
> +/* p: iptr ; i: i32 ; a: ptr(address) */
> +void gen_native_call_i32(const char *fun_name, TCGv_i32 ret,
> + TCGv_i32 arg1, TCGv_i32 arg2, TCGv_i32 arg3)
> +{
> + TCGv_ptr arg1_ptr = tcg_temp_new_ptr();
> + TCGv_ptr arg2_ptr = tcg_temp_new_ptr();
> + TCGv_ptr arg3_ptr = tcg_temp_new_ptr();
> + TCGv_ptr ret_ptr = tcg_temp_new_ptr();
> + tcg_gen_g2h_i32(arg1_ptr, arg1);
> + if (strcmp(fun_name, "memset") == 0) {/* a aip */
> + tcg_gen_ext_i32_ptr(arg3_ptr, arg3);
> + gen_helper_memset(ret_ptr, arg1_ptr, arg2, arg3_ptr);
> + goto ret_ptr;
> + }
> + tcg_gen_g2h_i32(arg2_ptr, arg2);
> + if (strcmp(fun_name, "strcpy") == 0) { /* a aa */
> + gen_helper_strcpy(ret_ptr, arg1_ptr, arg2_ptr);
> + goto ret_ptr;
> + } else if (strcmp(fun_name, "strcat") == 0) { /* a aa */
> + gen_helper_strcat(ret_ptr, arg1_ptr, arg2_ptr);
> + goto ret_ptr;
> + } else if (strcmp(fun_name, "strcmp") == 0) { /* i aa */
> + gen_helper_strcmp(ret, arg1_ptr, arg2_ptr);
> + }
> + tcg_gen_ext_i32_ptr(arg3_ptr, arg3);
> + if (strcmp(fun_name, "memcpy") == 0) { /* a aap */
> + gen_helper_memcpy(ret_ptr, arg1_ptr, arg2_ptr, arg3_ptr);
> + goto ret_ptr;
> + } else if (strcmp(fun_name, "strncpy") == 0) { /* a aap */
> + gen_helper_strncpy(ret_ptr, arg1_ptr, arg2_ptr, arg3_ptr);
> + goto ret_ptr;
> + } else if (strcmp(fun_name, "memcmp") == 0) { /* i aap */
> + gen_helper_memcmp(ret, arg1_ptr, arg2_ptr, arg3_ptr);
> + } else if (strcmp(fun_name, "strncmp") == 0) { /* i aap */
> + gen_helper_strncmp(ret, arg1_ptr, arg2_ptr, arg3_ptr);
> + }
> + return;
> +ret_ptr:
> + tcg_gen_h2g_i32(ret, ret_ptr);
> + return;
This is a bit of a messy function considering that most of it is data
driven. I think we could have a table with something like:
{
{ .func = "memset", .helper = gen_helper_memset,
.g2h_arg1 = true },
...
}
and then remove the duplication between the two gen_native_calls as
simply having different signatures for their g2h and h2h conversions. If
we ever get to embedding the signatures in the library that would make
things simpler to replace as well I think.
> +}
> +
> +void gen_native_call_i64(const char *fun_name, TCGv_i64 ret,
> + TCGv_i64 arg1, TCGv_i64 arg2, TCGv_i64 arg3)
> +{
> + TCGv_ptr arg1_ptr = tcg_temp_new_ptr();
> + TCGv_ptr arg2_ptr = tcg_temp_new_ptr();
> + TCGv_ptr arg3_ptr = tcg_temp_new_ptr();
> + TCGv_ptr ret_ptr = tcg_temp_new_ptr();
> + TCGv_i32 arg2_i32, ret_i32 = tcg_temp_new_i32();
> + tcg_gen_g2h_i64(arg1_ptr, arg1);
> + if (strcmp(fun_name, "memset") == 0) { /* a aip */
> + arg2_i32 = tcg_temp_new_i32();
> + tcg_gen_extrl_i64_i32(arg2_i32, arg2);
> + tcg_gen_trunc_i64_ptr(arg3_ptr, arg3);
> + gen_helper_memset(ret_ptr, arg1_ptr, arg2_i32, arg3_ptr);
> + goto ret_ptr;
> + }
> + tcg_gen_g2h_i64(arg2_ptr, arg2);
> + if (strcmp(fun_name, "strcpy") == 0) { /* a aa */
> + gen_helper_strcpy(ret_ptr, arg1_ptr, arg2_ptr);
> + goto ret_ptr;
> + } else if (strcmp(fun_name, "strcat") == 0) { /* a aa */
> + gen_helper_strcat(ret_ptr, arg1_ptr, arg2_ptr);
> + goto ret_ptr;
> + } else if (strcmp(fun_name, "strcmp") == 0) { /* i aa */
> + gen_helper_strcmp(ret_i32, arg1_ptr, arg2_ptr);
> + goto ret_i32;
> + }
> + tcg_gen_trunc_i64_ptr(arg3_ptr, arg3);
> + if (strcmp(fun_name, "memcpy") == 0) { /* a aap */
> + gen_helper_memcpy(ret_ptr, arg1_ptr, arg2_ptr, arg3_ptr);
> + goto ret_ptr;
> + } else if (strcmp(fun_name, "strncpy") == 0) { /* a aap */
> + gen_helper_strncpy(ret_ptr, arg1_ptr, arg2_ptr, arg3_ptr);
> + goto ret_ptr;
> + } else if (strcmp(fun_name, "memcmp") == 0) { /* i aap */
> + gen_helper_memcmp(ret_i32, arg1_ptr, arg2_ptr, arg3_ptr);
> + goto ret_i32;
> + } else if (strcmp(fun_name, "strncmp") == 0) { /* i aap */
> + gen_helper_strncmp(ret_i32, arg1_ptr, arg2_ptr, arg3_ptr);
> + goto ret_i32;
> + }
> + return;
> +ret_ptr:
> + tcg_gen_h2g_i64(ret, ret_ptr);
> + return;
> +ret_i32:
> + tcg_gen_extu_i32_i64(ret, ret_i32);
> + return;
> +}
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [RFC v4 07/11] target/i386: Add support for native library calls
2023-08-08 14:17 ` [RFC v4 07/11] target/i386: Add support " Yeqi Fu
@ 2023-08-09 16:44 ` Richard Henderson
0 siblings, 0 replies; 31+ messages in thread
From: Richard Henderson @ 2023-08-09 16:44 UTC (permalink / raw)
To: Yeqi Fu, alex.bennee
Cc: qemu-devel, Laurent Vivier, Paolo Bonzini, Eduardo Habkost
On 8/8/23 07:17, Yeqi Fu wrote:
> This commit introduces support for native library calls on the
> i386 target. When special instructions reserved for native calls
> are encountered, the code now performs address translation and
> generates the corresponding native call.
>
> Signed-off-by: Yeqi Fu <fufuyqqqqqq@gmail.com>
> ---
> configs/targets/i386-linux-user.mak | 1 +
> configs/targets/x86_64-linux-user.mak | 1 +
> target/i386/tcg/translate.c | 27 +++++++++++++++++++++++++++
> 3 files changed, 29 insertions(+)
>
> diff --git a/configs/targets/i386-linux-user.mak b/configs/targets/i386-linux-user.mak
> index 5b2546a430..2d8bca8f93 100644
> --- a/configs/targets/i386-linux-user.mak
> +++ b/configs/targets/i386-linux-user.mak
> @@ -2,3 +2,4 @@ TARGET_ARCH=i386
> TARGET_SYSTBL_ABI=i386
> TARGET_SYSTBL=syscall_32.tbl
> TARGET_XML_FILES= gdb-xml/i386-32bit.xml
> +CONFIG_NATIVE_CALL=y
> diff --git a/configs/targets/x86_64-linux-user.mak b/configs/targets/x86_64-linux-user.mak
> index 9ceefbb615..a53b017454 100644
> --- a/configs/targets/x86_64-linux-user.mak
> +++ b/configs/targets/x86_64-linux-user.mak
> @@ -3,3 +3,4 @@ TARGET_BASE_ARCH=i386
> TARGET_SYSTBL_ABI=common,64
> TARGET_SYSTBL=syscall_64.tbl
> TARGET_XML_FILES= gdb-xml/i386-64bit.xml
> +CONFIG_NATIVE_CALL=y
> diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
> index 90c7b32f36..28bf4477fb 100644
> --- a/target/i386/tcg/translate.c
> +++ b/target/i386/tcg/translate.c
> @@ -33,6 +33,7 @@
> #include "helper-tcg.h"
>
> #include "exec/log.h"
> +#include "native/native.h"
>
> #define HELPER_H "helper.h"
> #include "exec/helper-info.c.inc"
> @@ -6810,6 +6811,32 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
> case 0x1d0 ... 0x1fe:
> disas_insn_new(s, cpu, b);
> break;
> + case 0x1ff:
> + if (native_bypass_enabled()) {
> + TCGv ret = tcg_temp_new();
> + TCGv arg1 = tcg_temp_new();
> + TCGv arg2 = tcg_temp_new();
> + TCGv arg3 = tcg_temp_new();
> + const char *fun_name = lookup_symbol((s->base.pc_next) & 0xfff);
I'm not keen on this lookup_symbol interface.
I would much rather there be some data encoded in the native.so.
> + uintptr_t ra = GETPC();
> + uint32_t a1 = cpu_ldl_data_ra(env, env->regs[R_ESP] + 4, ra);
> + uint32_t a2 = cpu_ldl_data_ra(env, env->regs[R_ESP] + 8, ra);
> + uint32_t a3 = cpu_ldl_data_ra(env, env->regs[R_ESP] + 12, ra);
> + tcg_gen_movi_tl(arg1, a1);
> + tcg_gen_movi_tl(arg2, a2);
> + tcg_gen_movi_tl(arg3, a3);
This is wrong. You are performing the stack load at translation time, but it must be done
at execution time. You need
tcg_gen_addi_tl(arg1, cpu_regs[R_ESP], 4); /* arg1 = esp + 4 */
gen_op_ld_v(s, MO_UL, arg1, arg1); /* arg1 = *arg1 */
etc.
r~
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [RFC v4 10/11] tests/tcg/multiarch: Add nativecall.c test
2023-08-08 14:17 ` [RFC v4 10/11] tests/tcg/multiarch: Add nativecall.c test Yeqi Fu
2023-08-09 8:42 ` Alex Bennée
@ 2023-08-09 17:01 ` Alex Bennée
2023-08-09 17:12 ` Alex Bennée
2 siblings, 0 replies; 31+ messages in thread
From: Alex Bennée @ 2023-08-09 17:01 UTC (permalink / raw)
To: Yeqi Fu; +Cc: richard.henderson, qemu-devel
Yeqi Fu <fufuyqqqqqq@gmail.com> writes:
> Introduce a new test for native calls to ensure their functionality.
> The process involves cross-compiling the test cases, building them
> as dynamically linked binaries, and running these binaries which
> necessitates the addition of the appropriate interpreter prefix.
>
> Signed-off-by: Yeqi Fu <fufuyqqqqqq@gmail.com>
> ---
> tests/tcg/multiarch/Makefile.target | 17 +++++
> tests/tcg/multiarch/native/nativecall.c | 98
> +++++++++++++++++++++++++
Another thing I missed is putting the test in a subdir misses out the
common logic:
# Set search path for all sources
VPATH += $(MULTIARCH_SRC)
MULTIARCH_SRCS = $(notdir $(wildcard $(MULTIARCH_SRC)/*.c))
ifeq ($(filter %-linux-user, $(TARGET)),$(TARGET))
VPATH += $(MULTIARCH_SRC)/linux
MULTIARCH_SRCS += $(notdir $(wildcard $(MULTIARCH_SRC)/linux/*.c))
endif
MULTIARCH_TESTS = $(MULTIARCH_SRCS:.c=)
which as a result means things like:
make build-tcg
don't automatically build the tests (although it does get picked up at
runtime).
You can either move it out of the subdir or do something similar that
the arm-compat-semi does, expand VPATH and use TESTS:
modified tests/tcg/multiarch/Makefile.target
@@ -138,13 +138,18 @@ run-plugin-semiconsole-with-%:
TESTS += semihosting semiconsole
endif
-nativecall: native/nativecall.c
- $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(filter-out -static,$(LDFLAGS))
-
ifneq ($(LD_PREFIX),)
ifneq ($(wildcard $(LIBNATIVE)),)
+VPATH += $(MULTIARCH_SRC)/native
+
+nativecall: nativecall.c
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(filter-out -static,$(LDFLAGS))
+
run-nativecall: nativecall
- $(call run-test,$<, $(QEMU) -L $(LD_PREFIX) --native-bypass $(LIBNATIVE) $<, "nativecall")
+ $(call run-test,$<, $(QEMU) -L $(LD_PREFIX) --native-bypass
+ $(LIBNATIVE) $<, "nativecall")
+
+TESTS += nativecall
else
run-nativecall: nativecall
$(call skip-test, $<, "no native library found")
@@ -153,7 +158,6 @@ else
run-nativecall: nativecall
$(call skip-test, $<, "no elf interpreter prefix found")
endif
-EXTRA_RUNS += run-nativecall
> 2 files changed, 115 insertions(+)
> create mode 100644 tests/tcg/multiarch/native/nativecall.c
>
> diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target
> index 43bddeaf21..5231df34ba 100644
> --- a/tests/tcg/multiarch/Makefile.target
> +++ b/tests/tcg/multiarch/Makefile.target
> @@ -138,5 +138,22 @@ run-plugin-semiconsole-with-%:
> TESTS += semihosting semiconsole
> endif
>
> +nativecall: native/nativecall.c
> + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(filter-out -static,$(LDFLAGS))
> +
> +ifneq ($(LD_PREFIX),)
> +ifneq ($(wildcard $(LIBNATIVE)),)
> +run-nativecall: nativecall
> + $(call run-test,$<, $(QEMU) -L $(LD_PREFIX) --native-bypass $(LIBNATIVE) $<, "nativecall")
> +else
> +run-nativecall: nativecall
> + $(call skip-test, $<, "no native library found")
> +endif
> +else
> +run-nativecall: nativecall
> + $(call skip-test, $<, "no elf interpreter prefix found")
> +endif
> +EXTRA_RUNS += run-nativecall
> +
> # Update TESTS
> TESTS += $(MULTIARCH_TESTS)
> diff --git a/tests/tcg/multiarch/native/nativecall.c b/tests/tcg/multiarch/native/nativecall.c
> new file mode 100644
> index 0000000000..d3f6f49ed0
> --- /dev/null
> +++ b/tests/tcg/multiarch/native/nativecall.c
> @@ -0,0 +1,98 @@
> +#include <assert.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <sys/mman.h>
> +
> +void compare_memory(const void *a, const void *b, size_t n)
> +{
> + const unsigned char *p1 = a;
> + const unsigned char *p2 = b;
> + for (size_t i = 0; i < n; i++) {
> + assert(p1[i] == p2[i]);
> + }
> +}
> +
> +void test_memcpy()
> +{
> + char src[] = "Hello, world!";
> + char dest[20];
> + memcpy(dest, src, 13);
> + compare_memory(dest, src, 13);
> +}
> +
> +void test_strncpy()
> +{
> + char src[] = "Hello, world!";
> + char dest[20];
> + strncpy(dest, src, 13);
> + compare_memory(dest, src, 13);
> +}
> +
> +void test_strcpy()
> +{
> + char src[] = "Hello, world!";
> + char dest[20];
> + strcpy(dest, src);
> + compare_memory(dest, src, 13);
> +}
> +
> +void test_strcat()
> +{
> + char src[20] = "Hello, ";
> + char dst[] = "world!";
> + char str[] = "Hello, world!";
> + strcat(src, dest);
> + compare_memory(src, str, 13);
> +}
> +
> +void test_memcmp()
> +{
> + char str1[] = "abc";
> + char str2[] = "abc";
> + char str3[] = "def";
> + assert(memcmp(str1, str2, 3) == 0);
> + assert(memcmp(str1, str3, 3) != 0);
> +}
> +
> +void test_strncmp()
> +{
> + char str1[] = "abc";
> + char str2[] = "abc";
> + char str3[] = "def";
> + assert(strncmp(str1, str2, 2) == 0);
> + assert(strncmp(str1, str3, 2) != 0);
> +}
> +
> +void test_strcmp()
> +{
> + char str1[] = "abc";
> + char str2[] = "abc";
> + char str3[] = "def";
> + assert(strcmp(str1, str2) == 0);
> + assert(strcmp(str1, str3) != 0);
> +}
> +
> +void test_memset()
> +{
> + char buffer[10];
> + memset(buffer, 'A', 10);
> + int i;
> + for (i = 0; i < 10; i++) {
> + assert(buffer[i] == 'A');
> + }
> +}
> +
> +int main()
> +{
> + test_memset();
> + test_memcpy();
> + test_strncpy();
> + test_memcmp();
> + test_strncmp();
> + test_strcpy();
> + test_strcmp();
> + test_strcat();
> +
> + return EXIT_SUCCESS;
> +}
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [RFC v4 05/11] linux-user/elfload: Add support for parsing symbols of native libraries.
2023-08-09 16:14 ` Richard Henderson
@ 2023-08-09 17:04 ` Alex Bennée
0 siblings, 0 replies; 31+ messages in thread
From: Alex Bennée @ 2023-08-09 17:04 UTC (permalink / raw)
To: Richard Henderson; +Cc: Yeqi Fu, qemu-devel, Laurent Vivier
Richard Henderson <richard.henderson@linaro.org> writes:
> On 8/8/23 07:17, Yeqi Fu wrote:
>> This commit addresses the need to parse symbols of native libraries.
>> The base address of a shared library is determined by the dynamic
>> linker. To simplify the process, we focus on the last three digits,
>> which reside within the same page and remain unaffected by the base
>> address.
>> Signed-off-by: Yeqi Fu<fufuyqqqqqq@gmail.com>
>> ---
>> linux-user/elfload.c | 85 +++++++++++++++++++++++++++++++++++++++++---
>> 1 file changed, 80 insertions(+), 5 deletions(-)
>
> I'm not keen on this. I would much prefer the native library to be
> self-contained and not rely on symbols in this fashion.
Didn't we have an example build that allowed us to extend the metadata
and insert string pointers into the instruction stream? Did that prove
unworkable? I know there was some hoop jumping required in the inline
assembler but I thought that had been solved.
>
>
> r~
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [RFC v4 10/11] tests/tcg/multiarch: Add nativecall.c test
2023-08-08 14:17 ` [RFC v4 10/11] tests/tcg/multiarch: Add nativecall.c test Yeqi Fu
2023-08-09 8:42 ` Alex Bennée
2023-08-09 17:01 ` Alex Bennée
@ 2023-08-09 17:12 ` Alex Bennée
2 siblings, 0 replies; 31+ messages in thread
From: Alex Bennée @ 2023-08-09 17:12 UTC (permalink / raw)
To: Yeqi Fu; +Cc: richard.henderson, qemu-devel
Yeqi Fu <fufuyqqqqqq@gmail.com> writes:
> Introduce a new test for native calls to ensure their functionality.
> The process involves cross-compiling the test cases, building them
> as dynamically linked binaries, and running these binaries which
> necessitates the addition of the appropriate interpreter prefix.
>
> Signed-off-by: Yeqi Fu <fufuyqqqqqq@gmail.com>
> ---
> tests/tcg/multiarch/Makefile.target | 17 +++++
> tests/tcg/multiarch/native/nativecall.c | 98 +++++++++++++++++++++++++
> 2 files changed, 115 insertions(+)
> create mode 100644 tests/tcg/multiarch/native/nativecall.c
>
> diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target
> index 43bddeaf21..5231df34ba 100644
> --- a/tests/tcg/multiarch/Makefile.target
> +++ b/tests/tcg/multiarch/Makefile.target
> @@ -138,5 +138,22 @@ run-plugin-semiconsole-with-%:
> TESTS += semihosting semiconsole
> endif
>
> +nativecall: native/nativecall.c
> + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(filter-out -static,$(LDFLAGS))
> +
> +ifneq ($(LD_PREFIX),)
> +ifneq ($(wildcard $(LIBNATIVE)),)
> +run-nativecall: nativecall
> + $(call run-test,$<, $(QEMU) -L $(LD_PREFIX) --native-bypass $(LIBNATIVE) $<, "nativecall")
> +else
> +run-nativecall: nativecall
> + $(call skip-test, $<, "no native library found")
> +endif
> +else
> +run-nativecall: nativecall
> + $(call skip-test, $<, "no elf interpreter prefix found")
> +endif
> +EXTRA_RUNS += run-nativecall
> +
Or indeed just expand VPATH and use TESTS instead of EXTRA_RUNS (which
is for additional configurations of tests):
modified tests/tcg/multiarch/Makefile.target
@@ -138,13 +138,18 @@ run-plugin-semiconsole-with-%:
TESTS += semihosting semiconsole
endif
-nativecall: native/nativecall.c
- $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(filter-out -static,$(LDFLAGS))
-
ifneq ($(LD_PREFIX),)
ifneq ($(wildcard $(LIBNATIVE)),)
+VPATH += $(MULTIARCH_SRC)/native
+
+nativecall: nativecall.c
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(filter-out -static,$(LDFLAGS))
+
run-nativecall: nativecall
- $(call run-test,$<, $(QEMU) -L $(LD_PREFIX) --native-bypass $(LIBNATIVE) $<, "nativecall")
+ $(call run-test,$<, $(QEMU) -L $(LD_PREFIX) --native-bypass
+ $(LIBNATIVE) $<, "nativecall")
+
+TESTS += nativecall
else
run-nativecall: nativecall
$(call skip-test, $<, "no native library found")
@@ -153,7 +158,6 @@ else
run-nativecall: nativecall
$(call skip-test, $<, "no elf interpreter prefix found")
endif
-EXTRA_RUNS += run-nativecall
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [RFC v4 01/11] build: Implement logic for sharing cross-building config files
2023-08-08 14:17 ` [RFC v4 01/11] build: Implement logic for sharing cross-building config files Yeqi Fu
2023-08-09 12:24 ` Manos Pitsidianakis
2023-08-09 14:42 ` Alex Bennée
@ 2023-08-10 8:41 ` Alex Bennée
2 siblings, 0 replies; 31+ messages in thread
From: Alex Bennée @ 2023-08-10 8:41 UTC (permalink / raw)
To: Yeqi Fu; +Cc: richard.henderson, qemu-devel, Paolo Bonzini, Thomas Huth
Yeqi Fu <fufuyqqqqqq@gmail.com> writes:
> Signed-off-by: Yeqi Fu <fufuyqqqqqq@gmail.com>
> ---
> configure | 57 +++++++++++++++++++++++++++++++++----------------------
> 1 file changed, 34 insertions(+), 23 deletions(-)
>
> diff --git a/configure b/configure
> index 2b41c49c0d..a076583141 100755
> --- a/configure
> +++ b/configure
<snip>
>
> + # get the interpreter prefix and the path of libnative required for native call tests
> + if [ -d "/usr/$(echo "$target_cc" | sed 's/-gcc//')" ]; then
> + echo "LD_PREFIX=/usr/$(echo "$target_cc" | sed 's/-gcc//')" >> "$config_target_mak"
> + fi
> +
We need some gating and testing here because for mips on my system we
fallback to docker:
cat tests/tcg/mips-linux-user/config-target.mak
# Automatically generated by configure - do not modify
TARGET_NAME=mips
TARGET=mips-linux-user
EXTRA_CFLAGS=
CC=/home/alex/lsrc/qemu.git/builds/debug/pyvenv/bin/python3 -B /home/alex/lsrc/qemu.git/tests/docker/docker.py --engine docker cc --cc mips-linux-gnu-gcc -i qemu/debian-mips-cross -s /home/alex/lsrc/qemu.git --
CCAS=/home/alex/lsrc/qemu.git/builds/debug/pyvenv/bin/python3 -B /home/alex/lsrc/qemu.git/tests/docker/docker.py --engine docker cc --cc mips-linux-gnu-gcc -i qemu/debian-mips-cross -s /home/alex/lsrc/qemu.git --
AR=/home/alex/lsrc/qemu.git/builds/debug/pyvenv/bin/python3 -B /home/alex/lsrc/qemu.git/tests/docker/docker.py --engine docker cc --cc mips-linux-gnu-ar -i qemu/debian-mips-cross -s /home/alex/lsrc/qemu.git --
AS=/home/alex/lsrc/qemu.git/builds/debug/pyvenv/bin/python3 -B /home/alex/lsrc/qemu.git/tests/docker/docker.py --engine docker cc --cc mips-linux-gnu-as -i qemu/debian-mips-cross -s /home/alex/lsrc/qemu.git --
LD=/home/alex/lsrc/qemu.git/builds/debug/pyvenv/bin/python3 -B /home/alex/lsrc/qemu.git/tests/docker/docker.py --engine docker cc --cc mips-linux-gnu-ld -i qemu/debian-mips-cross -s /home/alex/lsrc/qemu.git --
NM=/home/alex/lsrc/qemu.git/builds/debug/pyvenv/bin/python3 -B /home/alex/lsrc/qemu.git/tests/docker/docker.py --engine docker cc --cc mips-linux-gnu-nm -i qemu/debian-mips-cross -s /home/alex/lsrc/qemu.git --
OBJCOPY=/home/alex/lsrc/qemu.git/builds/debug/pyvenv/bin/python3 -B /home/alex/lsrc/qemu.git/tests/docker/docker.py --engine docker cc --cc mips-linux-gnu-objcopy -i qemu/debian-mips-cross -s /home/alex/lsrc/qemu.git --
RANLIB=/home/alex/lsrc/qemu.git/builds/debug/pyvenv/bin/python3 -B /home/alex/lsrc/qemu.git/tests/docker/docker.py --engine docker cc --cc mips-linux-gnu-ranlib -i qemu/debian-mips-cross -s /home/alex/lsrc/qemu.git --
STRIP=/home/alex/lsrc/qemu.git/builds/debug/pyvenv/bin/python3 -B /home/alex/lsrc/qemu.git/tests/docker/docker.py --engine docker cc --cc mips-linux-gnu-strip -i qemu/debian-mips-cross -s /home/alex/lsrc/qemu.git --
BUILD_STATIC=y
QEMU=/home/alex/lsrc/qemu.git/builds/debug/qemu-mips
LD_PREFIX=/usr/
HOST_GDB_SUPPORTS_ARCH=y
LIBNATIVE=/home/alex/lsrc/qemu.git/builds/debug/common-user/native/mips-linux-user/libnative.so
but still set LD_PREFIX. We should at least check there is some sort of
ld.so in the LD_PREFIX path to indicate the loader is available.
> # will GDB work with these binaries?
> if test "${gdb_arches#*$arch}" != "$gdb_arches"; then
> echo "HOST_GDB_SUPPORTS_ARCH=y" >> "$config_target_mak"
> fi
> + fi
> +done
> +
> +# tests/tcg configuration
> +(mkdir -p tests/tcg
> +# create a symlink to the config-host.mak file in the tests/tcg
> +ln -srf $config_host_mak tests/tcg/config-host.mak
> +
> +tcg_tests_targets=
> +for target in $target_list; do
> + case $target in
> + *-softmmu)
> + test -f "$source_path/tests/tcg/$arch/Makefile.softmmu-target" || continue
> + ;;
> + esac
>
> + if test -f cross-build/$target/config-target.mak; then
> + mkdir -p "tests/tcg/$target"
> + ln -srf cross-build/$target/config-target.mak tests/tcg/$target/config-target.mak
> + ln -sf $source_path/tests/tcg/Makefile.target tests/tcg/$target/Makefile
> echo "run-tcg-tests-$target: $qemu\$(EXESUF)" >> Makefile.prereqs
> tcg_tests_targets="$tcg_tests_targets $target"
> fi
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 31+ messages in thread
end of thread, other threads:[~2023-08-10 8:44 UTC | newest]
Thread overview: 31+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-08-08 14:17 [RFC v4 00/11] Native Library Calls Yeqi Fu
2023-08-08 14:17 ` [RFC v4 01/11] build: Implement logic for sharing cross-building config files Yeqi Fu
2023-08-09 12:24 ` Manos Pitsidianakis
2023-08-09 14:42 ` Alex Bennée
2023-08-09 15:23 ` Alex Bennée
2023-08-10 8:41 ` Alex Bennée
2023-08-08 14:17 ` [RFC v4 02/11] build: Implement libnative library and the build machinery for libnative Yeqi Fu
2023-08-09 15:18 ` Alex Bennée
2023-08-09 16:10 ` Richard Henderson
2023-08-08 14:17 ` [RFC v4 03/11] linux-user: Implement envlist_appendenv and add tests for envlist Yeqi Fu
2023-08-09 15:27 ` Alex Bennée
2023-08-09 15:44 ` Richard Henderson
2023-08-09 16:06 ` Richard Henderson
2023-08-08 14:17 ` [RFC v4 04/11] linux-user: Implement native-bypass option support Yeqi Fu
2023-08-09 15:42 ` Richard Henderson
2023-08-09 15:47 ` Alex Bennée
2023-08-08 14:17 ` [RFC v4 05/11] linux-user/elfload: Add support for parsing symbols of native libraries Yeqi Fu
2023-08-09 16:14 ` Richard Henderson
2023-08-09 17:04 ` Alex Bennée
2023-08-08 14:17 ` [RFC v4 06/11] tcg: Add tcg opcodes and helpers for native library calls Yeqi Fu
2023-08-09 16:41 ` Alex Bennée
2023-08-08 14:17 ` [RFC v4 07/11] target/i386: Add support " Yeqi Fu
2023-08-09 16:44 ` Richard Henderson
2023-08-08 14:17 ` [RFC v4 08/11] target/mips: " Yeqi Fu
2023-08-08 14:17 ` [RFC v4 09/11] target/arm: " Yeqi Fu
2023-08-08 14:17 ` [RFC v4 10/11] tests/tcg/multiarch: Add nativecall.c test Yeqi Fu
2023-08-09 8:42 ` Alex Bennée
2023-08-09 17:01 ` Alex Bennée
2023-08-09 17:12 ` Alex Bennée
2023-08-08 14:17 ` [RFC v4 11/11] docs/user: Add doc for native library calls Yeqi Fu
2023-08-09 12:51 ` Manos Pitsidianakis
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).