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);
+
+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.
+
+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
+
+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
 ------------------------
 
-- 
2.34.1


Reply via email to