On 7/8/2026 8:20 AM, Ziyang Zhang wrote:
> 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 prebuilt thunks and a
> runnable example.
> 
> Signed-off-by: Ziyang Zhang <[email protected]>
> ---
>  docs/about/emulation.rst | 122 +++++++++++++++++++++++++++++++++++++++
>  1 file changed, 122 insertions(+)
> 
> diff --git a/docs/about/emulation.rst b/docs/about/emulation.rst
> index 3b4c365933..07fbd24072 100644
> --- a/docs/about/emulation.rst
> +++ b/docs/about/emulation.rst
> @@ -1046,6 +1046,128 @@ 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. Its prebuilt thunks are 
> for an
> +x86_64 guest, running on an x86_64, aarch64 or riscv64 host.
> +
> +A minimal end-to-end example wraps a one-function library, ``libhello.so``,
> +declared by ``hello.h``:
> +
> +.. code-block:: c
> +
> +   void hello(const char *name, int lucky);
> +

Please include full files for example:
hello.h, hello.c and main.c calling hello function.

Also, please include compiler commands for libhello.so and main.
You can give a full example assuming it run on a x86_64 host.

> +The guest program ``main`` is an ordinary x86_64 executable, linked against a
> +guest ``libhello.so`` and calling its ``hello()``. The host has its own
> +``libhello.so``, the same library built for the host. The goal is to run
> +``main``, but have each ``hello()`` call run on the host's ``libhello.so``.
> +
> +Lorelei ships a prebuilt toolchain (a "devkit") in its releases. Download one
> +for your host and unpack it:
> +
> +.. code-block:: shell
> +
> +   # <arch> is your host architecture: x86_64, aarch64 or riscv64
> +   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>
> +
> +A single command reads the host ``libhello.so`` and ``hello.h`` and generates
> +the thunk: a guest-side ``libhello.so`` that stands in for an ordinary guest
> +build, and a host-side thunk library that dispatches to the real one:
> +
> +.. code-block:: shell
> +
> +   $DEVKIT/bin/LoreMakeThunk.py --name hello --lib libhello.so --header 
> hello.h \
> +       -o thunks -- -I.
> +

Sounds good.

> +Running ``main`` under the plugin forwards each ``hello()`` call to the 
> host's
> +real ``libhello.so``:
> +
> +.. code-block:: shell
> +
> +   LORELEI_THUNK_PATH=thunks \
> +   LD_LIBRARY_PATH=$DEVKIT/lib:. \
> +       qemu-x86_64 -plugin contrib/plugins/libdlcall.so \
> +       -L $DEVKIT/x86_64/sysroot \
> +       -E 
> LD_LIBRARY_PATH=$DEVKIT/x86_64/lib:thunks/x86_64/lib/x86_64-LoreGTL \
> +       ./main
> +

I could not get it to work.
Following all the steps, the error message is:

[GRT] failed to load host runtime
qemu: uncaught target signal 6 (Aborted) - core dumped
Aborted

We talked about not overriding sysroot, so please remove -L part.
Also, Why do current dir is passed in LD_LIBRARY_PATH?

> +The guest ``LD_LIBRARY_PATH``, passed with ``-E``, controls what the emulated
> +program loads:
> +
> +* ``$DEVKIT/x86_64/lib`` contains the guest runtime support shipped with the
> +  devkit.
> +* ``thunks/x86_64/lib/x86_64-LoreGTL`` contains the generated guest
> +  ``libhello.so`` thunk, used in place of an ordinary guest library.
> +
> +The host ``LD_LIBRARY_PATH`` controls what the plugin and host thunk load:
> +
> +* ``$DEVKIT/lib`` contains the host runtime support shipped with the devkit.
> +* ``.`` is the current directory, where the host's own ``libhello.so`` is
> +  located.
> +
> +See the runnable
> +`hello <https://github.com/rover2024/lorelei/tree/main/examples/hello>`_
> +(minimal) and
> +`demo <https://github.com/rover2024/lorelei/tree/main/examples/demo>`_
> +(variadic functions and a callback that reenters the guest) examples, and
> +`Lorelei <https://github.com/rover2024/lorelei>`_ for prebuilt thunk trees 
> and
> +the runtime environment they expect.
> +
> +.. 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
>  ------------------------
>  

Regards,
Pierrick

Reply via email to