All of lore.kernel.org
 help / color / mirror / Atom feed
* [PULL 0/3] Plugins update for 2026-07-13
@ 2026-07-13 18:06 Pierrick Bouvier
  2026-07-13 18:06 ` [PULL 1/3] uftrace: riscv privilege level Pierrick Bouvier
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Pierrick Bouvier @ 2026-07-13 18:06 UTC (permalink / raw)
  To: qemu-devel, peter.maydell, richard.henderson, pbonzini, stefanha
  Cc: pierrick.bouvier

The following changes since commit 499039798cdad7d86b787fec0eaf1da4151c0f05:

  Merge tag 'pull-request-2026-07-12' of https://gitlab.com/huth/qemu into staging (2026-07-12 21:49:04 +0200)

are available in the Git repository at:

  https://gitlab.com/p-b-o/qemu tags/pbouvier/pr/plugins-20260713

for you to fetch changes up to eee8e58eed452fb8a7be4fd9c7868d0512abbd6a:

  docs/about/emulation: document the dlcall plugin (2026-07-13 11:04:51 -0700)

----------------------------------------------------------------
Changes:
- [PATCH v1] uftrace: riscv privilege level (Yanfeng Liu <yfliu2008@qq.com>)
  Link: https://lore.kernel.org/qemu-devel/tencent_E17E8F6494EE130F71527C6BCE481AF33E08@qq.com
- [PATCH v12 0/2] contrib/plugins: add dlcall to call host functions (Ziyang Zhang <functioner@sjtu.edu.cn>)
  Link: https://lore.kernel.org/qemu-devel/20260711094523.622997-1-functioner@sjtu.edu.cn

----------------------------------------------------------------
Yanfeng Liu (1):
      uftrace: riscv privilege level

Ziyang Zhang (2):
      contrib/plugins: add a minimal dlcall plugin
      docs/about/emulation: document the dlcall plugin

 contrib/plugins/dlcall.c    | 248 ++++++++++++++++++++++++++++++++++++++++++++
 contrib/plugins/meson.build |   5 +
 contrib/plugins/uftrace.c   |  13 ++-
 docs/about/emulation.rst    | 158 ++++++++++++++++++++++++++++
 4 files changed, 421 insertions(+), 3 deletions(-)
 create mode 100644 contrib/plugins/dlcall.c


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PULL 1/3] uftrace: riscv privilege level
  2026-07-13 18:06 [PULL 0/3] Plugins update for 2026-07-13 Pierrick Bouvier
@ 2026-07-13 18:06 ` Pierrick Bouvier
  2026-07-13 18:06 ` [PULL 2/3] contrib/plugins: add a minimal dlcall plugin Pierrick Bouvier
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Pierrick Bouvier @ 2026-07-13 18:06 UTC (permalink / raw)
  To: qemu-devel, peter.maydell, richard.henderson, pbonzini, stefanha
  Cc: pierrick.bouvier

From: Yanfeng Liu <yfliu2008@qq.com>

This adds RiscV virtual user and supervisor privilege levels to
uftrace plugin to avoid crashing with H extension guests.

Signed-off-by: Yanfeng Liu <yfliu2008@qq.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Link: https://lore.kernel.org/qemu-devel/tencent_E17E8F6494EE130F71527C6BCE481AF33E08@qq.com
Signed-off-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
---
 contrib/plugins/uftrace.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/contrib/plugins/uftrace.c b/contrib/plugins/uftrace.c
index 9b0a4963aee..063e32220b1 100644
--- a/contrib/plugins/uftrace.c
+++ b/contrib/plugins/uftrace.c
@@ -109,6 +109,8 @@ typedef enum {
     RISCV64_SUPERVISOR,
     RISCV64_RESERVED,
     RISCV64_MACHINE,
+    RISCV64_VUSER,
+    RISCV64_VSUPERVISOR,
     RISCV64_PRIVILEGE_LEVEL_MAX,
 } Riscv64PrivilegeLevel;
 
@@ -153,8 +155,10 @@ static void uftrace_write_map(bool system_emulation)
     const char *path = "./uftrace.data/sid-0.map";
 
     if (system_emulation && access(path, F_OK) == 0) {
-        /* do not erase existing map in system emulation, as a custom one might
-         * already have been generated by uftrace_symbols.py */
+        /*
+         * do not erase existing map in system emulation, as a custom one might
+         * already have been generated by uftrace_symbols.py
+         */
         return;
     }
 
@@ -706,6 +710,8 @@ static const char *riscv64_get_privilege_level_name(uint8_t pl)
     case RISCV64_SUPERVISOR: return "Supervisor";
     case RISCV64_RESERVED: return "Unknown";
     case RISCV64_MACHINE: return "Machine";
+    case RISCV64_VUSER: return "VUser";
+    case RISCV64_VSUPERVISOR: return "VSupervisor";
     default:
         g_assert_not_reached();
     }
@@ -986,7 +992,8 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
 
     score = qemu_plugin_scoreboard_new(sizeof(Cpu));
     qemu_plugin_register_vcpu_init_cb(id, vcpu_init, NULL);
-    qemu_plugin_register_atexit_cb(id, at_exit, (void *) info->system_emulation);
+    qemu_plugin_register_atexit_cb(id, at_exit,
+                                   (void *) info->system_emulation);
     qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans, NULL);
 
     return 0;
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PULL 2/3] contrib/plugins: add a minimal dlcall plugin
  2026-07-13 18:06 [PULL 0/3] Plugins update for 2026-07-13 Pierrick Bouvier
  2026-07-13 18:06 ` [PULL 1/3] uftrace: riscv privilege level Pierrick Bouvier
@ 2026-07-13 18:06 ` Pierrick Bouvier
  2026-07-13 18:06 ` [PULL 3/3] docs/about/emulation: document the " Pierrick Bouvier
  2026-07-14 19:23 ` [PULL 0/3] Plugins update for 2026-07-13 Stefan Hajnoczi
  3 siblings, 0 replies; 5+ messages in thread
From: Pierrick Bouvier @ 2026-07-13 18:06 UTC (permalink / raw)
  To: qemu-devel, peter.maydell, richard.henderson, pbonzini, stefanha
  Cc: pierrick.bouvier

From: Ziyang Zhang <functioner@sjtu.edu.cn>

Add a minimal dlcall plugin that lets the guest invoke host functions
through magic system calls. The plugin registers a vCPU syscall filter
callback that intercepts a reserved syscall number and dispatches a set
of pass-through operations: querying host attributes, loading and freeing
shared libraries, resolving symbols, retrieving the last library error,
and invoking a host function through a common interface.

The magic syscall number defaults to 4096 and can be overridden at load
time with the "syscall_num=N" argument; values low enough to clash with a
real syscall are rejected.

Co-authored-by: Kailiang Xu <xukl2019@sjtu.edu.cn>
Co-authored-by: Mingyuan Xia <xiamy@ultrarisc.com>
Signed-off-by: Ziyang Zhang <functioner@sjtu.edu.cn>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Link: https://lore.kernel.org/qemu-devel/20260711094523.622997-2-functioner@sjtu.edu.cn
Signed-off-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
---
 contrib/plugins/dlcall.c    | 248 ++++++++++++++++++++++++++++++++++++
 contrib/plugins/meson.build |   5 +
 2 files changed, 253 insertions(+)
 create mode 100644 contrib/plugins/dlcall.c

diff --git a/contrib/plugins/dlcall.c b/contrib/plugins/dlcall.c
new file mode 100644
index 00000000000..9d2230b2d1a
--- /dev/null
+++ b/contrib/plugins/dlcall.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2026, Ziyang Zhang <functioner@sjtu.edu.cn>
+ *
+ * dlcall (Dynamic Linking Call) plugin: lets a linux-user guest invoke host
+ * functions by issuing a magic system call. The guest can ask QEMU to dlopen()
+ * a host shared library, dlsym() a symbol, and call it with guest-supplied
+ * arguments.
+ *
+ * The plugin intentionally keeps the QEMU side lightweight and prescribes
+ * nothing about how a library is thunked. Any toolchain can implement the
+ * userspace side. Lorelei is one end-to-end implementation (guest/host
+ * runtimes plus a thunk compiler that generates thunks from a library's
+ * headers):
+ * https://github.com/rover2024/lorelei
+ *
+ * See docs/about/emulation.rst|Dynamic Linking Call for details and examples.
+ *
+ * WARNING: trusted guests only. The guest can load arbitrary host libraries
+ * and execute arbitrary host code with arbitrary arguments, i.e. full code
+ * execution in the QEMU host process. It is NOT a sandbox and provides no
+ * isolation; only load it for guests you fully trust.
+ *
+ * WARNING: requires guest_base == 0, which is qemu-user's default. Pointer
+ * operands are dereferenced as host addresses directly, and the invoked host
+ * functions dereference guest pointers with no address translation, so guest
+ * and host must share a single address space. A non-zero guest_base (e.g. set
+ * via -B/-R) would make every pointer off by guest_base and hit unrelated
+ * host memory.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <glib.h>
+#include <dlfcn.h>
+
+#include <qemu-plugin.h>
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
+
+/*
+ * The magic system call number for dlcall.
+ *
+ * It defaults to DLCALL_SYSCALL_DEFAULT and can be overridden at load time
+ * with the "syscall_num=N" argument. To avoid hijacking a real syscall the
+ * guest might issue, N must be at least DLCALL_SYSCALL_MIN: every Linux ABI
+ * keeps its syscall numbers well below this; numbers from here up are free.
+ */
+enum {
+    DLCALL_SYSCALL_DEFAULT = 4096,
+    DLCALL_SYSCALL_MIN = 4096,
+};
+
+static int64_t dlcall_syscall_num = DLCALL_SYSCALL_DEFAULT;
+
+/*
+ * dlcall calling convention.
+ *
+ * The guest issues the magic system call (dlcall_syscall_num). The first
+ * argument (a1) is one of the call IDs below; the remaining arguments (a2, a3,
+ * a4, ...) are that ID's operands. All pointer operands are guest virtual
+ * addresses that the plugin dereferences as host addresses directly (see the
+ * guest_base requirement above). Results are written back through
+ * caller-provided "out" pointers rather than returned in the syscall value.
+ *
+ * The syscall return value (*sysret) only reports dispatch status: 0 on a
+ * recognised ID, -EINVAL for an unknown one. The actual success/failure of an
+ * operation (e.g. a NULL handle from dlopen) is delivered through its out
+ * pointer, exactly like the underlying libdl call.
+ *
+ * Operands per ID:
+ *
+ *   DLCALL_ID_GET_HOST_ATTRIBUTE
+ *     a2  const char *key        in:  attribute name to query
+ *     a3  const char **attr_ptr  out: matching value, or NULL if unknown
+ *
+ *   DLCALL_ID_LOAD_LIBRARY                            (wraps dlopen)
+ *     a2  const char *path       in:  library path
+ *     a3  int flags              in:  dlopen() flags (e.g. RTLD_NOW)
+ *     a4  void **handle_ptr      out: library handle, or NULL on failure
+ *
+ *   DLCALL_ID_GET_PROC_ADDRESS                        (wraps dlsym)
+ *     a2  void *handle           in:  library handle
+ *     a3  const char *name       in:  symbol name
+ *     a4  void **entry_ptr       out: symbol address, or NULL if not found
+ *
+ *   DLCALL_ID_FREE_LIBRARY                            (wraps dlclose)
+ *     a2  void *handle           in:  library handle
+ *     a3  int *ret_ptr           out: dlclose() return value (0 on success)
+ *
+ *   DLCALL_ID_GET_LIBRARY_ERROR                       (wraps dlerror)
+ *     a2  const char **error_ptr out: last libdl error string, or NULL
+ *
+ *   DLCALL_ID_INVOKE_PROC                             (calls the symbol)
+ *     a2  void *proc             in:  function pointer, signature
+ *                                     void (*)(void *arg1, void *arg2)
+ *     a3  void *arg1             in:  first argument forwarded to proc
+ *     a4  void *arg2             in:  second argument forwarded to proc
+ */
+enum DlcallID {
+    DLCALL_ID_GET_HOST_ATTRIBUTE,
+    DLCALL_ID_LOAD_LIBRARY,
+    DLCALL_ID_GET_PROC_ADDRESS,
+    DLCALL_ID_FREE_LIBRARY,
+    DLCALL_ID_GET_LIBRARY_ERROR,
+    DLCALL_ID_INVOKE_PROC,
+};
+
+static inline const char *query_host_attribute(const char *key)
+{
+    if (strcmp(key, "emu") == 0) {
+        return "qemu";
+    }
+    return NULL;
+}
+
+static inline void invoke_proc(void *proc, void *arg1, void *arg2)
+{
+    typedef void (*Func)(void * /*arg1*/, void * /*arg2*/);
+    Func func = (Func) proc;
+    func(arg1, arg2);
+}
+
+static bool vcpu_syscall_filter(unsigned int vcpu_index,
+                                int64_t num, uint64_t a1, uint64_t a2,
+                                uint64_t a3, uint64_t a4, uint64_t a5,
+                                uint64_t a6, uint64_t a7, uint64_t a8,
+                                int64_t *sysret, void *userdata)
+{
+    if (num == dlcall_syscall_num) {
+        switch (a1) {
+        /* Query host attribute by a reserved key. */
+        case DLCALL_ID_GET_HOST_ATTRIBUTE: {
+            const char *key = (const char *) a2;
+            const char **attr_ptr = (const char **) a3;
+            assert(attr_ptr);
+            *attr_ptr = query_host_attribute(key);
+            *sysret = 0;
+            break;
+        }
+
+        /* Load a shared library. */
+        case DLCALL_ID_LOAD_LIBRARY: {
+            const char *path = (const char *) a2;
+            int flags = (int) a3;
+            void **handle_ptr = (void **) a4;
+            assert(handle_ptr);
+            *handle_ptr = dlopen(path, flags);
+            *sysret = 0;
+            break;
+        }
+
+        /* Get the address of a function in a shared library. */
+        case DLCALL_ID_GET_PROC_ADDRESS: {
+            void *handle = (void *) a2;
+            const char *name = (const char *) a3;
+            void **entry_ptr = (void **) a4;
+            assert(entry_ptr);
+            *entry_ptr = dlsym(handle, name);
+            *sysret = 0;
+            break;
+        }
+
+        /* Free a shared library. */
+        case DLCALL_ID_FREE_LIBRARY: {
+            void *handle = (void *) a2;
+            int *ret_ptr = (int *) a3;
+            *ret_ptr = dlclose(handle);
+            *sysret = 0;
+            break;
+        }
+
+        /* Get the last error message for a library event. */
+        case DLCALL_ID_GET_LIBRARY_ERROR: {
+            const char **error_ptr = (const char **) a2;
+            *error_ptr = dlerror();
+            *sysret = 0;
+            break;
+        }
+
+        /* Invoke a function of a common interface. */
+        case DLCALL_ID_INVOKE_PROC: {
+            void *proc = (void *) a2;
+            void *arg1 = (void *) a3;
+            void *arg2 = (void *) a4;
+            assert(proc);
+            invoke_proc(proc, arg1, arg2);
+            *sysret = 0;
+            break;
+        }
+
+        default:
+            *sysret = -EINVAL;
+            break;
+        }
+        return true;
+    }
+    return false;
+}
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
+                                           const qemu_info_t *info,
+                                           int argc, char **argv)
+{
+    if (info->system_emulation) {
+        fprintf(stderr, "plugin dlcall: only useful for user emulation\n");
+        return -1;
+    }
+
+    for (int i = 0; i < argc; i++) {
+        char *opt = argv[i];
+        g_auto(GStrv) tokens = g_strsplit(opt, "=", 2);
+        if (g_strcmp0(tokens[0], "syscall_num") == 0) {
+            const char *val = tokens[1];
+            char *endptr = NULL;
+            guint64 num;
+            if (!val || *val == '\0') {
+                fprintf(stderr,
+                        "plugin dlcall: missing value for syscall_num\n");
+                return -1;
+            }
+            num = g_ascii_strtoull(val, &endptr, 0);
+            if (*endptr != '\0' || g_strrstr(val, "-") != NULL) {
+                fprintf(stderr,
+                        "plugin dlcall: invalid syscall_num '%s'\n", val);
+                return -1;
+            }
+            if (num < DLCALL_SYSCALL_MIN || num > G_MAXINT64) {
+                fprintf(stderr,
+                        "plugin dlcall: syscall_num %s is out of range; "
+                        "it must be >= %d to avoid clashing with a real "
+                        "syscall\n", val, DLCALL_SYSCALL_MIN);
+                return -1;
+            }
+            dlcall_syscall_num = (int64_t) num;
+        } else {
+            fprintf(stderr, "plugin dlcall: unknown option '%s'\n", opt);
+            return -1;
+        }
+    }
+
+    qemu_plugin_register_vcpu_syscall_filter_cb(id, vcpu_syscall_filter, NULL);
+
+    return 0;
+}
diff --git a/contrib/plugins/meson.build b/contrib/plugins/meson.build
index 099319e7a17..e7fc4d6d8f5 100644
--- a/contrib/plugins/meson.build
+++ b/contrib/plugins/meson.build
@@ -19,6 +19,11 @@ if host_os != 'windows'
   contrib_plugins += 'lockstep.c'
 endif
 
+if host_os == 'linux'
+  # dlcall passes guest calls through to host libraries; linux-user only
+  contrib_plugins += 'dlcall.c'
+endif
+
 if 'cpp' in all_languages
   contrib_plugins += 'cpp.cpp'
 endif
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PULL 3/3] docs/about/emulation: document the dlcall plugin
  2026-07-13 18:06 [PULL 0/3] Plugins update for 2026-07-13 Pierrick Bouvier
  2026-07-13 18:06 ` [PULL 1/3] uftrace: riscv privilege level Pierrick Bouvier
  2026-07-13 18:06 ` [PULL 2/3] contrib/plugins: add a minimal dlcall plugin Pierrick Bouvier
@ 2026-07-13 18:06 ` Pierrick Bouvier
  2026-07-14 19:23 ` [PULL 0/3] Plugins update for 2026-07-13 Stefan Hajnoczi
  3 siblings, 0 replies; 5+ messages in thread
From: Pierrick Bouvier @ 2026-07-13 18:06 UTC (permalink / raw)
  To: qemu-devel, peter.maydell, richard.henderson, pbonzini, stefanha
  Cc: pierrick.bouvier

From: Ziyang Zhang <functioner@sjtu.edu.cn>

Document the dlcall plugin under Example Plugins: what it does, the trusted-
guests and guest_base == 0 constraints, how to load it, and a pointer to
Lorelei, one end-to-end userspace implementation, for the toolchain and a
runnable example.

Co-authored-by: Kailiang Xu <xukl2019@sjtu.edu.cn>
Co-authored-by: Mingyuan Xia <xiamy@ultrarisc.com>
Signed-off-by: Ziyang Zhang <functioner@sjtu.edu.cn>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Link: https://lore.kernel.org/qemu-devel/20260711094523.622997-3-functioner@sjtu.edu.cn
Signed-off-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
---
 docs/about/emulation.rst | 158 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 158 insertions(+)

diff --git a/docs/about/emulation.rst b/docs/about/emulation.rst
index 3b4c365933d..b861501e85e 100644
--- a/docs/about/emulation.rst
+++ b/docs/about/emulation.rst
@@ -1046,6 +1046,164 @@ Count traps
 This plugin counts the number of interrupts (asynchronous events), exceptions
 (synchronous events) and host calls (e.g. semihosting) per cpu.
 
+Dynamic Linking Call
+....................
+
+``contrib/plugins/dlcall.c``
+
+This plugin provides a dynamic linking function call interception mechanism
+for linux-user guests: the guest hands a call off to the host, where the plugin
+runs native code in its place instead of the guest emulating it. Interception
+alone enables several uses, for instance tracing or auditing guest calls.
+One use is acceleration by leveraging the host's native shared libraries. For
+example, a thunk layer can run the stock zlib ``minizip`` utility under
+emulation while forwarding its ``deflate`` calls to the host's native zlib
+library (libz). This avoids emulating those selected library calls instruction
+by instruction.
+
+The guest issues a reserved "magic" system call (4096 by default, configurable
+with ``syscall_num=N``) whose first argument selects a pass-through operation:
+dlopen/dlclose a host library, dlsym a symbol, and invoke a resolved host
+function. The plugin performs the operation on the host and consumes the
+syscall, so the real kernel never sees it.
+
+.. warning::
+
+   Trusted guests only. The guest can load arbitrary host libraries and run
+   arbitrary code in the QEMU host process. The plugin is not a sandbox and
+   provides no isolation. It also requires ``guest_base == 0`` (qemu-user's
+   default), as guest pointers are dereferenced as host addresses with no
+   translation.
+
+The plugin intentionally keeps the QEMU side lightweight and knows nothing
+about any particular library or its calling convention. Turning a real library
+into working thunks, including argument marshalling, callbacks and variadic
+functions, is done entirely in userspace, and any toolchain can implement the
+interface.
+
+Loading the plugin is all that is required from QEMU's side:
+
+.. code-block:: shell
+
+   qemu-x86_64 -plugin contrib/plugins/libdlcall.so <guest-program> ...
+
+`Lorelei <https://github.com/rover2024/lorelei>`_ is one end-to-end userspace
+implementation of this: it provides the guest and host runtimes and an
+automated toolchain that generates the thunks from a library's headers, so guest
+library calls run on the host's native libraries. It supports an x86_64 guest
+running on an x86_64, aarch64 or riscv64 host.
+
+A minimal end-to-end example uses a one-function library, ``libhello.so``, built
+two ways: the guest build tags its output ``(from the guest)`` and the host
+build ``(from the host)``. An unmodified guest program ``main`` calls
+``hello("World", 7)``, and the thunk makes that same binary reach the host build
+in place of its own. The sources live under ``src/``:
+
+.. code-block:: c
+
+   /* src/hello.h */
+   void hello(const char *name, int lucky);
+
+.. code-block:: c
+
+   /* src/hello_guest.c */
+   #include "hello.h"
+   #include <stdio.h>
+
+   void hello(const char *name, int lucky)
+   {
+       printf("Hello, %s! Your lucky number is %d. (from the guest)\n", name, lucky);
+   }
+
+.. code-block:: c
+
+   /* src/hello_host.c */
+   #include "hello.h"
+   #include <stdio.h>
+
+   void hello(const char *name, int lucky)
+   {
+       printf("Hello, %s! Your lucky number is %d. (from the host)\n", name, lucky);
+   }
+
+.. code-block:: c
+
+   /* src/main.c */
+   #include "hello.h"
+
+   int main(void)
+   {
+       hello("World", 7);
+       return 0;
+   }
+
+Lorelei ships a prebuilt toolchain (a "devkit") in its releases. Download the
+one for your host and unpack it:
+
+.. code-block:: shell
+
+   # ARCH is your host's architecture: x86_64, aarch64 or riscv64. This example uses aarch64.
+   # See https://github.com/rover2024/lorelei/releases
+   ARCH=aarch64
+   VERSION=$(curl -fsSL -o /dev/null -w '%{url_effective}' \
+         https://github.com/rover2024/lorelei/releases/latest | sed 's|.*/tag/v||')
+   wget "https://github.com/rover2024/lorelei/releases/download/v$VERSION/lorelei-devkit-$ARCH-$VERSION.tar.xz"
+   tar -xf lorelei-devkit-$ARCH-$VERSION.tar.xz
+   DEVKIT=lorelei-devkit-$ARCH
+
+Build the guest ``libhello.so`` (x86_64) and the host ``libhello.so`` (this
+host's architecture), then the guest program:
+
+.. code-block:: shell
+
+   mkdir -p build/guest build/host
+   $DEVKIT/bin/x86_64-linux-gnu-clang -shared -fPIC src/hello_guest.c -o build/guest/libhello.so
+   cc -shared -fPIC src/hello_host.c -o build/host/libhello.so
+   $DEVKIT/bin/x86_64-linux-gnu-clang src/main.c -Isrc -Lbuild/guest -lhello -o build/guest/main
+
+Run it under qemu:
+
+.. code-block:: shell
+
+   qemu-x86_64 -L /usr/x86_64-linux-gnu/ -E LD_LIBRARY_PATH=build/guest build/guest/main
+
+which prints::
+
+   Hello, World! Your lucky number is 7. (from the guest)
+
+Now generate the thunk from the host ``libhello.so``. This produces a guest-side
+``libhello.so`` that stands in for the guest build, and a host-side thunk library
+that dispatches to the host build:
+
+.. code-block:: shell
+
+   $DEVKIT/bin/LoreMakeThunk.py --name hello --lib build/host/libhello.so \
+       --header hello.h -o thunks -- -Isrc
+
+Run the same ``main`` under the plugin. The call reaches the host build now:
+
+.. code-block:: shell
+
+   LD_LIBRARY_PATH=$DEVKIT/lib:build/host \
+       qemu-x86_64 -plugin contrib/plugins/libdlcall.so \
+       -E LD_LIBRARY_PATH=$DEVKIT/x86_64/lib:thunks/x86_64 \
+       -L /usr/x86_64-linux-gnu/ \
+       build/guest/main
+
+which prints::
+
+   Hello, World! Your lucky number is 7. (from the host)
+
+.. list-table:: Dynamic Linking Call arguments
+  :widths: 20 80
+  :header-rows: 1
+
+  * - Option
+    - Description
+  * - syscall_num=N
+    - The magic syscall number the guest issues (default 4096). Must be high
+      enough not to clash with a real syscall.
+
 Other emulation features
 ------------------------
 
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PULL 0/3] Plugins update for 2026-07-13
  2026-07-13 18:06 [PULL 0/3] Plugins update for 2026-07-13 Pierrick Bouvier
                   ` (2 preceding siblings ...)
  2026-07-13 18:06 ` [PULL 3/3] docs/about/emulation: document the " Pierrick Bouvier
@ 2026-07-14 19:23 ` Stefan Hajnoczi
  3 siblings, 0 replies; 5+ messages in thread
From: Stefan Hajnoczi @ 2026-07-14 19:23 UTC (permalink / raw)
  To: Pierrick Bouvier
  Cc: qemu-devel, peter.maydell, richard.henderson, pbonzini, stefanha,
	pierrick.bouvier

[-- Attachment #1: Type: text/plain, Size: 116 bytes --]

Applied, thanks.

Please update the changelog at https://wiki.qemu.org/ChangeLog/11.1 for any user-visible changes.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-07-15  6:52 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-13 18:06 [PULL 0/3] Plugins update for 2026-07-13 Pierrick Bouvier
2026-07-13 18:06 ` [PULL 1/3] uftrace: riscv privilege level Pierrick Bouvier
2026-07-13 18:06 ` [PULL 2/3] contrib/plugins: add a minimal dlcall plugin Pierrick Bouvier
2026-07-13 18:06 ` [PULL 3/3] docs/about/emulation: document the " Pierrick Bouvier
2026-07-14 19:23 ` [PULL 0/3] Plugins update for 2026-07-13 Stefan Hajnoczi

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.