From 1872bfa2dfa938908f764225f1d996430fc9c31e Mon Sep 17 00:00:00 2001 From: Hanlu Li Date: Thu, 13 Aug 2026 16:11:58 +0800 Subject: [PATCH 1/4] LATX, refactor: Annotate wrappers with KZT groups Add one declarative registry for KZT group names, bit positions, stability, and dependencies, then annotate each existing wrapper with its group. This prepares the registry for dependency-aware controls without changing wrapper selection behavior. Signed-off-by: Hanlu Li --- target/i386/latx/context/elfloader.c | 4 +- target/i386/latx/context/library.c | 8 +- target/i386/latx/include/kzt-group-list.h | 28 +++ target/i386/latx/include/library_list.h | 224 +++++++++++----------- 4 files changed, 146 insertions(+), 118 deletions(-) create mode 100644 target/i386/latx/include/kzt-group-list.h diff --git a/target/i386/latx/context/elfloader.c b/target/i386/latx/context/elfloader.c index 6b08dc2234e..5a14832fe5f 100755 --- a/target/i386/latx/context/elfloader.c +++ b/target/i386/latx/context/elfloader.c @@ -402,8 +402,8 @@ void FreeElfHeader(elfheader_t** head) *head = NULL; } #include "fileutils.h" -#define GO(P, N) P, -#define GOALIAS(P, N) P, +#define GO(P, N, G) P, +#define GOALIAS(P, N, G) P, const char * wrappedlibs_name[] = { #include "library_list.h" }; diff --git a/target/i386/latx/context/library.c b/target/i386/latx/context/library.c index 90b8264ea61..df0a7e6b7cc 100755 --- a/target/i386/latx/context/library.c +++ b/target/i386/latx/context/library.c @@ -30,17 +30,17 @@ #include "librarian_private.h" #include "pathcoll.h" -#define GO(P, N) int wrapped##N##_init(library_t* lib, box64context_t *box64); \ +#define GO(P, N, G) int wrapped##N##_init(library_t* lib, box64context_t *box64); \ void wrapped##N##_fini(library_t* lib); \ int wrapped##N##_get(library_t* lib, const char* name, khint_t pre_k, uintptr_t *offs, uintptr_t *sz, int version, const char* vername, int local); \ int wrapped##N##_getnoweak(library_t* lib, const char* name, khint_t pre_k, uintptr_t *offs, uintptr_t *sz, int version, const char* vername, int local); -#define GOALIAS(P, N) +#define GOALIAS(P, N, G) #include "library_list.h" #undef GO #undef GOALIAS -#define GO(P, N) {P, wrapped##N##_init, wrapped##N##_fini, wrapped##N##_get, wrapped##N##_getnoweak}, -#define GOALIAS(P, N) {P, wrapped##N##_init, wrapped##N##_fini, wrapped##N##_get, wrapped##N##_getnoweak}, +#define GO(P, N, G) {P, wrapped##N##_init, wrapped##N##_fini, wrapped##N##_get, wrapped##N##_getnoweak}, +#define GOALIAS(P, N, G) {P, wrapped##N##_init, wrapped##N##_fini, wrapped##N##_get, wrapped##N##_getnoweak}, wrappedlib_t wrappedlibs[] = { #include "library_list.h" }; diff --git a/target/i386/latx/include/kzt-group-list.h b/target/i386/latx/include/kzt-group-list.h new file mode 100644 index 00000000000..6c7caab659b --- /dev/null +++ b/target/i386/latx/include/kzt-group-list.h @@ -0,0 +1,28 @@ +/* + * SPDX-FileCopyrightText: 2026 LAT Project Authors + * + * SPDX-License-Identifier: GPL-2.0-only + */ + +#ifndef LATX_KZT_GROUP_LIST_H +#define LATX_KZT_GROUP_LIST_H + +/* + * KZT library-group registry. + * + * This is the single source of truth for group names, bit positions, + * stability, and dependencies. Keep concrete shared-library assignments in + * library_list.h. + * + * KZT_GROUP_LIST(X) entries are: + * + * X(identifier, name, bit, STABLE|EXPERIMENTAL, dependencies) + */ +#define KZT_GROUP_LIST(X) \ + X(CORE, "core", 0, STABLE, KZT_GROUP_NONE) \ + X(X11, "x11", 1, STABLE, KZT_GROUP_CORE) \ + X(GL, "gl", 2, STABLE, KZT_GROUP_CORE | KZT_GROUP_X11) \ + X(VULKAN, "vulkan", 3, STABLE, KZT_GROUP_CORE | KZT_GROUP_X11) \ + X(VAAPI, "vaapi", 4, STABLE, KZT_GROUP_CORE | KZT_GROUP_X11) + +#endif /* LATX_KZT_GROUP_LIST_H */ diff --git a/target/i386/latx/include/library_list.h b/target/i386/latx/include/library_list.h index 01638dd688b..35a1ed3e784 100755 --- a/target/i386/latx/include/library_list.h +++ b/target/i386/latx/include/library_list.h @@ -4,121 +4,121 @@ #include "config-host.h" -GO("libEGL.so.1", libegl) +GO("libEGL.so.1", libegl, KZT_GROUP_GL) #ifndef CONFIG_LOONGARCH_NEW_WORLD -GO("libdl.so.2", libdl) +GO("libdl.so.2", libdl, KZT_GROUP_CORE) #endif -//GO("libgtk-3.so", gtk3) -//GO("libgio-2.0.so", gio2) -GO("libc.so.6", libc) -GO("libGL.so.1", libgl) -GO("libX11.so.6", libx11) -GO("libGLU.so.1", libglu) -GO("libGLX.so.0", libglx) -GO("libXxf86vm.so.1", libxxf86vm) -GO("libXext.so.6", libxext) -GO("libXau.so.6", libxau) -GO("libXi.so.6", libxi) -GO("libXdmcp.so.6", libxdmcp) -GO("libxshmfence.so.1", xshmfence) -GO("libXfixes.so.3", libxfixes) -GO("libXcursor.so.1", libxcursor) -GO("libXinerama.so.1", xinerama) -GO("libXrandr.so.2", libxrandr) -GO("libXss.so.1", libxss) -GO("libXft.so.2", libxft) -GO("libXtst.so.6", libxtst) -GO("libXt.so.6", libxt) -GO("libXrender.so.1", libxrender) -GO("libXpm.so.4", libxpm) -GO("libXdamage.so.1", libxdamage) -GO("libXmu.so.6", libxmu) -GO("libXcomposite.so.1", libxcomposite) -GO("libva-x11.so.2", libvax11) -GO("libva-drm.so.2", libvadrm) -GO("libva.so.2", libva) -GO("libxcb.so.1", libxcb) -GO("libxcb-xkb.so.1", libxcbxkb) -//GO("libxkbcommon-x11.so.0", xkbcommonx11) -//GO("libxkbcommon.so.0", xkbcommon) -GO("libX11-xcb.so.1", libx11xcb) -GO("libxcb-randr.so.0", libxcbrandr) -GO("libxcb-shm.so.0", libxcbshm) -GO("libxcb-xfixes.so.0", libxcbxfixes) -GO("libxcb-shape.so.0", libxcbshape) -GO("libxcb-image.so.0", libxcbimage) -GO("libxcb-keysyms.so.1", libxcbkeysyms) -GO("libxcb-xtest.so.0", libxcbxtest) -GO("libxcb-glx.so.0", libxcbglx) -GO("libxcb-dri2.so.0", libxcbdri2) -GO("libxcb-dri3.so.0", libxcbdri3) -GO("libvulkan.so.1", vulkan) -GO("libxcb-cursor.so.0", libxcbcursor) -GO("libxcb-icccm.so.4", libxcbicccm) -GO("libxcb-util.so.1", libxcbutil) -GO("libxcb-render-util.so.0", libxcbrenderutil) -GO("libxcb-render.so.0", libxcbrender) -GO("libxcb-sync.so.1", libxcbsync) -GO("libxcb-xinerama.so.0", libxcbxinerama) -GO("libxcb-xinput.so.0", libxcbxinput) -GO("libxcb-present.so.0", libxcbpresent) +//GO("libgtk-3.so", gtk3, KZT_GROUP_X11) +//GO("libgio-2.0.so", gio2, KZT_GROUP_CORE) +GO("libc.so.6", libc, KZT_GROUP_CORE) +GO("libGL.so.1", libgl, KZT_GROUP_GL) +GO("libX11.so.6", libx11, KZT_GROUP_X11) +GO("libGLU.so.1", libglu, KZT_GROUP_GL) +GO("libGLX.so.0", libglx, KZT_GROUP_GL) +GO("libXxf86vm.so.1", libxxf86vm, KZT_GROUP_X11) +GO("libXext.so.6", libxext, KZT_GROUP_X11) +GO("libXau.so.6", libxau, KZT_GROUP_X11) +GO("libXi.so.6", libxi, KZT_GROUP_X11) +GO("libXdmcp.so.6", libxdmcp, KZT_GROUP_X11) +GO("libxshmfence.so.1", xshmfence, KZT_GROUP_X11) +GO("libXfixes.so.3", libxfixes, KZT_GROUP_X11) +GO("libXcursor.so.1", libxcursor, KZT_GROUP_X11) +GO("libXinerama.so.1", xinerama, KZT_GROUP_X11) +GO("libXrandr.so.2", libxrandr, KZT_GROUP_X11) +GO("libXss.so.1", libxss, KZT_GROUP_X11) +GO("libXft.so.2", libxft, KZT_GROUP_X11) +GO("libXtst.so.6", libxtst, KZT_GROUP_X11) +GO("libXt.so.6", libxt, KZT_GROUP_X11) +GO("libXrender.so.1", libxrender, KZT_GROUP_X11) +GO("libXpm.so.4", libxpm, KZT_GROUP_X11) +GO("libXdamage.so.1", libxdamage, KZT_GROUP_X11) +GO("libXmu.so.6", libxmu, KZT_GROUP_X11) +GO("libXcomposite.so.1", libxcomposite, KZT_GROUP_X11) +GO("libva-x11.so.2", libvax11, KZT_GROUP_VAAPI) +GO("libva-drm.so.2", libvadrm, KZT_GROUP_VAAPI) +GO("libva.so.2", libva, KZT_GROUP_VAAPI) +GO("libxcb.so.1", libxcb, KZT_GROUP_X11) +GO("libxcb-xkb.so.1", libxcbxkb, KZT_GROUP_X11) +//GO("libxkbcommon-x11.so.0", xkbcommonx11, KZT_GROUP_X11) +//GO("libxkbcommon.so.0", xkbcommon, KZT_GROUP_X11) +GO("libX11-xcb.so.1", libx11xcb, KZT_GROUP_X11) +GO("libxcb-randr.so.0", libxcbrandr, KZT_GROUP_X11) +GO("libxcb-shm.so.0", libxcbshm, KZT_GROUP_X11) +GO("libxcb-xfixes.so.0", libxcbxfixes, KZT_GROUP_X11) +GO("libxcb-shape.so.0", libxcbshape, KZT_GROUP_X11) +GO("libxcb-image.so.0", libxcbimage, KZT_GROUP_X11) +GO("libxcb-keysyms.so.1", libxcbkeysyms, KZT_GROUP_X11) +GO("libxcb-xtest.so.0", libxcbxtest, KZT_GROUP_X11) +GO("libxcb-glx.so.0", libxcbglx, KZT_GROUP_X11) +GO("libxcb-dri2.so.0", libxcbdri2, KZT_GROUP_X11) +GO("libxcb-dri3.so.0", libxcbdri3, KZT_GROUP_X11) +GO("libvulkan.so.1", vulkan, KZT_GROUP_VULKAN) +GO("libxcb-cursor.so.0", libxcbcursor, KZT_GROUP_X11) +GO("libxcb-icccm.so.4", libxcbicccm, KZT_GROUP_X11) +GO("libxcb-util.so.1", libxcbutil, KZT_GROUP_X11) +GO("libxcb-render-util.so.0", libxcbrenderutil, KZT_GROUP_X11) +GO("libxcb-render.so.0", libxcbrender, KZT_GROUP_X11) +GO("libxcb-sync.so.1", libxcbsync, KZT_GROUP_X11) +GO("libxcb-xinerama.so.0", libxcbxinerama, KZT_GROUP_X11) +GO("libxcb-xinput.so.0", libxcbxinput, KZT_GROUP_X11) +GO("libxcb-present.so.0", libxcbpresent, KZT_GROUP_X11) -GOALIAS("libxcb-cursor.so", libxcbcursor) -GOALIAS("libxcb-icccm.so", libxcbicccm) -GOALIAS("libxcb-util.so", libxcbutil) -GOALIAS("libxcb-render-util.so", libxcbrenderutil) -GOALIAS("libxcb-render.so", libxcbrender) -GOALIAS("libxcb-sync.so", libxcbsync) -GOALIAS("libxcb-xinerama.so", libxcbxinerama) -GOALIAS("libxcb-xinput.so", libxcbxinput) -GOALIAS("libxcb-present.so", libxcbpresent) -GOALIAS("libvulkan.so", vulkan) -GOALIAS("libEGL.so", libegl) +GOALIAS("libxcb-cursor.so", libxcbcursor, KZT_GROUP_X11) +GOALIAS("libxcb-icccm.so", libxcbicccm, KZT_GROUP_X11) +GOALIAS("libxcb-util.so", libxcbutil, KZT_GROUP_X11) +GOALIAS("libxcb-render-util.so", libxcbrenderutil, KZT_GROUP_X11) +GOALIAS("libxcb-render.so", libxcbrender, KZT_GROUP_X11) +GOALIAS("libxcb-sync.so", libxcbsync, KZT_GROUP_X11) +GOALIAS("libxcb-xinerama.so", libxcbxinerama, KZT_GROUP_X11) +GOALIAS("libxcb-xinput.so", libxcbxinput, KZT_GROUP_X11) +GOALIAS("libxcb-present.so", libxcbpresent, KZT_GROUP_X11) +GOALIAS("libvulkan.so", vulkan, KZT_GROUP_VULKAN) +GOALIAS("libEGL.so", libegl, KZT_GROUP_GL) #ifndef CONFIG_LOONGARCH_NEW_WORLD -GOALIAS("libdl.so", libdl) +GOALIAS("libdl.so", libdl, KZT_GROUP_CORE) #endif -//GOALIAS("libgtk-3.so", gtk3) -//GOALIAS("libgio-2.0.so", gio2) -GOALIAS("libc.so", libc) -GOALIAS("libGL.so", libgl) -GOALIAS("libX11.so", libx11) -GOALIAS("libGLU.so", libglu) -GOALIAS("libGLX.so", libglx) -GOALIAS("libXxf86vm.so", libxxf86vm) -GOALIAS("libXext.so", libxext) -GOALIAS("libXau.so", libxau) -GOALIAS("libXi.so", libxi) -GOALIAS("libXdmcp.so", libxdmcp) -GOALIAS("libxshmfence.so", xshmfence) -GOALIAS("libXfixes.so", libxfixes) -GOALIAS("libXcursor.so", libxcursor) -GOALIAS("libXinerama.so", xinerama) -GOALIAS("libXrandr.so", libxrandr) -GOALIAS("libXss.so", libxss) -GOALIAS("libXft.so", libxft) -GOALIAS("libXtst.so", libxtst) -GOALIAS("libXt.so", libxt) -GOALIAS("libXrender.so", libxrender) -GOALIAS("libXpm.so", libxpm) -GOALIAS("libXdamage.so", libxdamage) -GOALIAS("libXmu.so", libxmu) -GOALIAS("libXcomposite.so", libxcomposite) -GOALIAS("libva-x11.so", libvax11) -GOALIAS("libva-drm.so", libvadrm) -GOALIAS("libva.so", libva) -GOALIAS("libxcb.so", libxcb) -GOALIAS("libxcb-xkb.so", libxcbxkb) -//GOALIAS("libxkbcommon-x11.so", xkbcommonx11) -//GOALIAS("libxkbcommon.so", xkbcommon) -GOALIAS("libX11-xcb.so", libx11xcb) -GOALIAS("libxcb-randr.so", libxcbrandr) -GOALIAS("libxcb-shm.so", libxcbshm) -GOALIAS("libxcb-xfixes.so", libxcbxfixes) -GOALIAS("libxcb-shape.so", libxcbshape) -GOALIAS("libxcb-image.so", libxcbimage) -GOALIAS("libxcb-keysyms.so", libxcbkeysyms) -GOALIAS("libxcb-xtest.so", libxcbxtest) -GOALIAS("libxcb-glx.so", libxcbglx) -GOALIAS("libxcb-dri2.so", libxcbdri2) -GOALIAS("libxcb-dri3.so", libxcbdri3) +//GOALIAS("libgtk-3.so", gtk3, KZT_GROUP_X11) +//GOALIAS("libgio-2.0.so", gio2, KZT_GROUP_CORE) +GOALIAS("libc.so", libc, KZT_GROUP_CORE) +GOALIAS("libGL.so", libgl, KZT_GROUP_GL) +GOALIAS("libX11.so", libx11, KZT_GROUP_X11) +GOALIAS("libGLU.so", libglu, KZT_GROUP_GL) +GOALIAS("libGLX.so", libglx, KZT_GROUP_GL) +GOALIAS("libXxf86vm.so", libxxf86vm, KZT_GROUP_X11) +GOALIAS("libXext.so", libxext, KZT_GROUP_X11) +GOALIAS("libXau.so", libxau, KZT_GROUP_X11) +GOALIAS("libXi.so", libxi, KZT_GROUP_X11) +GOALIAS("libXdmcp.so", libxdmcp, KZT_GROUP_X11) +GOALIAS("libxshmfence.so", xshmfence, KZT_GROUP_X11) +GOALIAS("libXfixes.so", libxfixes, KZT_GROUP_X11) +GOALIAS("libXcursor.so", libxcursor, KZT_GROUP_X11) +GOALIAS("libXinerama.so", xinerama, KZT_GROUP_X11) +GOALIAS("libXrandr.so", libxrandr, KZT_GROUP_X11) +GOALIAS("libXss.so", libxss, KZT_GROUP_X11) +GOALIAS("libXft.so", libxft, KZT_GROUP_X11) +GOALIAS("libXtst.so", libxtst, KZT_GROUP_X11) +GOALIAS("libXt.so", libxt, KZT_GROUP_X11) +GOALIAS("libXrender.so", libxrender, KZT_GROUP_X11) +GOALIAS("libXpm.so", libxpm, KZT_GROUP_X11) +GOALIAS("libXdamage.so", libxdamage, KZT_GROUP_X11) +GOALIAS("libXmu.so", libxmu, KZT_GROUP_X11) +GOALIAS("libXcomposite.so", libxcomposite, KZT_GROUP_X11) +GOALIAS("libva-x11.so", libvax11, KZT_GROUP_VAAPI) +GOALIAS("libva-drm.so", libvadrm, KZT_GROUP_VAAPI) +GOALIAS("libva.so", libva, KZT_GROUP_VAAPI) +GOALIAS("libxcb.so", libxcb, KZT_GROUP_X11) +GOALIAS("libxcb-xkb.so", libxcbxkb, KZT_GROUP_X11) +//GOALIAS("libxkbcommon-x11.so", xkbcommonx11, KZT_GROUP_X11) +//GOALIAS("libxkbcommon.so", xkbcommon, KZT_GROUP_X11) +GOALIAS("libX11-xcb.so", libx11xcb, KZT_GROUP_X11) +GOALIAS("libxcb-randr.so", libxcbrandr, KZT_GROUP_X11) +GOALIAS("libxcb-shm.so", libxcbshm, KZT_GROUP_X11) +GOALIAS("libxcb-xfixes.so", libxcbxfixes, KZT_GROUP_X11) +GOALIAS("libxcb-shape.so", libxcbshape, KZT_GROUP_X11) +GOALIAS("libxcb-image.so", libxcbimage, KZT_GROUP_X11) +GOALIAS("libxcb-keysyms.so", libxcbkeysyms, KZT_GROUP_X11) +GOALIAS("libxcb-xtest.so", libxcbxtest, KZT_GROUP_X11) +GOALIAS("libxcb-glx.so", libxcbglx, KZT_GROUP_X11) +GOALIAS("libxcb-dri2.so", libxcbdri2, KZT_GROUP_X11) +GOALIAS("libxcb-dri3.so", libxcbdri3, KZT_GROUP_X11) From 4a5200b998a5d4f6917a71ab80948fdc0faf7a02 Mon Sep 17 00:00:00 2001 From: Hanlu Li Date: Thu, 13 Aug 2026 16:14:02 +0800 Subject: [PATCH 2/4] LATX, feat: Add per-library-family KZT controls Add Wine-style KZT group selection for command-line and application-specific configuration. Derive group names, default stability, and dependency closure from the central group registry so new families have one policy definition. Signed-off-by: Hanlu Li --- configs/latx-x86_64.conf | 6 + docs/user/latx-environment.rst | 78 ++++- linux-user/elfload.c | 25 +- linux-user/main.c | 38 ++- target/i386/latx/context/elfloader.c | 4 + target/i386/latx/context/kzt-groups.c | 397 ++++++++++++++++++++++++ target/i386/latx/context/library.c | 12 +- target/i386/latx/context/meson.build | 1 + target/i386/latx/include/kzt-groups.h | 53 ++++ target/i386/latx/include/latx-options.h | 5 + target/i386/latx/latx-options.c | 41 +++ 11 files changed, 638 insertions(+), 22 deletions(-) create mode 100644 target/i386/latx/context/kzt-groups.c create mode 100644 target/i386/latx/include/kzt-groups.h diff --git a/configs/latx-x86_64.conf b/configs/latx-x86_64.conf index 936c8c387a7..41f68884379 100644 --- a/configs/latx-x86_64.conf +++ b/configs/latx-x86_64.conf @@ -12,6 +12,12 @@ # Notes: # - Section names are case-sensitive. # - Keys represent environment variables. +# - KZT library groups select wrapper eligibility. Custom wrappers may still +# re-enter guest code when required. +# - LATX_KZT_LIBS=-name removes a group; LATX_KZT_LIBS=name selects one group +# and its dependencies. # #[devcpp.exe] #LATX_SOFTFPU = 1 +#LATX_KZT = 1 +#LATX_KZT_LIBS = -x11 diff --git a/docs/user/latx-environment.rst b/docs/user/latx-environment.rst index 1acbf3df47a..907da3e9fac 100644 --- a/docs/user/latx-environment.rst +++ b/docs/user/latx-environment.rst @@ -117,11 +117,15 @@ Meson 安装目标会把模板安装到 configure 指定的 ``sysconfdir``。默 - ``0`` - 控制 64 位构建中的库直通。``1`` 表示按兼容性检查启用,``2`` 是供测试 使用的强制模式。32 位构建不提供该选项。 + * - ``LATX_KZT_LIBS`` + - ``stable`` + - 可选的 KZT 库族选择。``-x11`` 从稳定集合关闭 X11,``x11`` 表示只启用 + X11 及其依赖,``+name`` 用于在稳定集合上增加已知的实验库族。 * - ``LATX_KZT_LOG`` - ``0`` - 控制 KZT 关键降级日志。设为 ``1`` 时,release 构建也会在某个装载对象 - 无法安全完成直通绑定时向标准错误输出原因;默认不输出,也不会改变 - KZT 的启用状态或安全降级行为。仅 64 位 KZT 构建提供该选项。 + 无法安全完成直通绑定时向标准错误输出原因,并记录最终库族集合和每个库 + 是否启用 KZT wrapper 的决策;默认不输出,也不会改变安全降级行为。 * - ``LATX_SOFTFPU`` - ``0`` - 浮点结果异常时可尝试 ``1``;``2`` 是另一种软浮点模式。非零值会自动 @@ -144,6 +148,76 @@ Meson 安装目标会把模板安装到 configure 指定的 ``sysconfdir``。默 ``-runtime-info`` 确认当前选择,避免掩盖运行时安装问题。 +KZT 库族控制 +============ + +``LATX_KZT`` 仍然是 KZT(库直通)总开关。这里的库族选择控制 guest 动态库 +是否可以使用对应的 KZT wrapper,并不表示该库的所有函数都无条件调用 host +实现。为了保持 guest 可见状态,loader 协调、回调等自定义 wrapper 仍可能有意 +回到 guest 翻译执行。 + +普通用户只需设置 +``LATX_KZT=1``,此时启用当前版本的稳定库族。只有兼容性排查、二分和实验性 +wrapper 测试需要设置 ``LATX_KZT_LIBS``。总开关为 ``0`` 时忽略库族选择。 + +库族名称、稳定状态和依赖关系由当前 LATX 构建定义,不在文档中维护一份容易 +过期的静态清单。下面的 ``x11``、``gl`` 等名称只用于说明选择语法。 + +``LATX_KZT_LIBS`` 只有两种写法,不能混用: + +* 不带符号的名称表示“只启用这些库族”,例如 ``x11`` 或 ``x11,gl``; +* 全部带 ``+`` 或 ``-`` 时,以稳定集合为起点增加或关闭库族,例如 + ``-x11`` 或 ``+x11,-vulkan``。 + +未设置、空值和 ``stable`` 都表示稳定集合。``stable`` 必须单独使用。库族名 +大小写不敏感,逗号两侧允许空白。这里不提供 ``all``:未来新增实验库族时, +旧配置不应在升级后自动启用尚未验证的 wrapper。 + +依赖由 LATX 自动处理。例如 ``LATX_KZT_LIBS=gl`` 实际启用 +``core,x11,gl``;``LATX_KZT_LIBS=-x11`` 会保留 ``core``,并同时关闭依赖 +X11 的 ``gl``、``vulkan`` 和 ``vaapi``。这样不会把 host 库创建的对象交给已经 +回退 guest 翻译的依赖库。 + +以 ``libdl`` 为例,guest ``dlopen`` 会先进入 LAT 的自定义 wrapper。目标库有 +安全 KZT wrapper 时,LAT 才装载对应的 host 库;目标库没有 wrapper 时,LAT +会重新进入 guest ``dlopen``,由 ``cpu_loop`` 翻译执行 guest loader。因而 +``core`` 是 KZT 的基础 wrapper 和 loader 协调库族,不是“完整原生 libdl”开关。 + +未知库族、空项、混合两种写法,或者同时写 ``+x11`` 和 ``-x11`` 都属于配置 +错误。LATX 会报告原因、关闭本次运行的全部 KZT,并继续完整翻译 guest 库, +不会忽略错误后继续走非预期的 native 路径。``LATX_KZT`` 只接受 ``0``、``1``、 +``2``,``LATX_KZT_LOG`` 只接受 ``0``、``1``;其他值同样按配置错误处理。 + +常见用法: + +.. code-block:: bash + + # 关闭全部 KZT + LATX_KZT=0 latx-x86_64 /path/to/program + + # 启用当前稳定库族 + LATX_KZT=1 latx-x86_64 /path/to/program + + # 从稳定集合临时关闭 X11 及其依赖者 + LATX_KZT=1 LATX_KZT_LIBS=-x11 \ + latx-x86_64 /path/to/program + + # 只启用 X11 及其必要依赖,便于调试和二分 + LATX_KZT=1 LATX_KZT_LIBS=x11 LATX_KZT_LOG=1 \ + latx-x86_64 /path/to/program + +所有选项都可以写入应用 section。例如只对 ``gtkperf`` 关闭 X11: + +.. code-block:: ini + + [gtkperf] + LATX_KZT = 1 + LATX_KZT_LIBS = -x11 + +高优先级配置会完整替换低优先级的 ``LATX_KZT_LIBS`` 字符串,不会跨配置来源 +拼接集合,因此环境变量覆盖应用配置后的结果仍可直接复现。 + + 指定 guest 运行时 ================== diff --git a/linux-user/elfload.c b/linux-user/elfload.c index cdb9b714dd1..3aa16df9bd4 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -3484,23 +3484,14 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info) } #if defined(CONFIG_LATX_KZT) if (!elf_interpreter) { - if(option_kzt && getenv("LATX_KZT")) { - char * arg_kzt = getenv("LATX_KZT"); - option_kzt = strtol(arg_kzt, NULL, 0); - - /* option_kzt == 1 is normal kzt, - disable kzt for static or direct exec ld.so - option_kzt == 2 is forced kzt, used for test */ - if (option_kzt == 1) { - if (latx_wine) { - wine_option_kzt = option_kzt; - } - option_kzt = 0; - } - } else { - if (latx_wine) { - wine_option_kzt = option_kzt; - } + /* Wine maps its real main image later, so defer either KZT mode + * until that image is available. For other static/direct-ld.so + * guests, normal mode is disabled while forced mode remains a test + * override. option_kzt already reflects config and CLI precedence. */ + if (latx_wine && option_kzt) { + wine_option_kzt = option_kzt; + option_kzt = 0; + } else if (option_kzt == 1) { option_kzt = 0; } } diff --git a/linux-user/main.c b/linux-user/main.c index 47281e85906..c538ce6612b 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -74,6 +74,7 @@ int mydebug = 1; #include "librarian.h" #include "wrapper.h" #if defined(CONFIG_LATX_KZT) +#include "kzt-groups.h" #include "wrappertbbridge.h" box64context_t* my_context = NULL; elfheader_t* elf_header = NULL; @@ -668,12 +669,36 @@ static void handle_arg_latx_avx_cpuid(const char *arg) #if defined(CONFIG_LATX_KZT) static void handle_arg_latx_kzt(const char *arg) { - option_kzt = strtol(arg, NULL, 0); + int value; + + g_clear_pointer(&option_kzt_error, g_free); + if (qemu_strtoi(arg, NULL, 0, &value) || value < 0 || value > 2) { + option_kzt = 0; + option_kzt_error = g_strdup_printf( + "LATX_KZT must be exactly 0, 1, or 2 (got '%s')", arg); + return; + } + option_kzt = value; +} + +static void handle_arg_latx_kzt_libs(const char *arg) +{ + g_free(option_kzt_libs); + option_kzt_libs = g_strdup(arg); } static void handle_arg_latx_kzt_log(const char *arg) { - option_kzt_log = strtol(arg, NULL, 0) != 0; + int value; + + g_clear_pointer(&option_kzt_log_error, g_free); + if (qemu_strtoi(arg, NULL, 0, &value) || value < 0 || value > 1) { + option_kzt_log = 1; + option_kzt_log_error = g_strdup_printf( + "LATX_KZT_LOG must be exactly 0 or 1 (got '%s')", arg); + return; + } + option_kzt_log = value; } #endif @@ -889,6 +914,8 @@ static const struct qemu_argument arg_table[] = { #if defined(CONFIG_LATX_KZT) {"latx-kzt", "LATX_KZT", true, handle_arg_latx_kzt, "", "enable kuzhitong"}, + {"latx-kzt-libs", "LATX_KZT_LIBS", true, handle_arg_latx_kzt_libs, + "group,...", "select KZT library groups"}, {"latx-kzt-log", "LATX_KZT_LOG", true, handle_arg_latx_kzt_log, "0|1", "log important KZT binding and fallback decisions"}, #endif @@ -1396,6 +1423,13 @@ int main(int argc, char **argv, char **envp) /* set environment variables */ options_set(target_argv); + if (!latx_options_finalize()) { +#if defined(CONFIG_LATX_KZT) + error_report("invalid KZT configuration: %s; KZT disabled", + kzt_groups_last_error()); +#endif + } + if (runtime_info_requested) { print_runtime_info(); return EXIT_SUCCESS; diff --git a/target/i386/latx/context/elfloader.c b/target/i386/latx/context/elfloader.c index 5a14832fe5f..e959bb9a895 100755 --- a/target/i386/latx/context/elfloader.c +++ b/target/i386/latx/context/elfloader.c @@ -32,6 +32,7 @@ #include "symbols.h" #include "lsenv.h" #include "qemu.h" +#include "kzt-groups.h" #include "kzt_relocation_transaction.h" static int kzt_relocation_slot_fits_page(uintptr_t slot_addr) @@ -692,6 +693,9 @@ int CheckEnableKZT(elfheader_t* h, char** target_argv, int target_argc) /* check KZT libs in paths */ int nb = sizeof(wrappedlibs_name) / sizeof(char*); for (int i=0; istr); + g_string_free(valid, true); +} + +static const char *kzt_skip_space(const char *cursor) +{ + while (*cursor && g_ascii_isspace(*cursor)) { + cursor++; + } + return cursor; +} + +static bool kzt_parse_group_spec(const char *spec, KztGroupSpecMode *mode, + uint32_t *selected, uint32_t *added, + uint32_t *removed, bool *use_stable) +{ + const char *cursor; + bool saw_token = false; + + if (!spec || !*kzt_skip_space(spec)) { + return true; + } + + cursor = spec; + while (true) { + char token[32]; + const char *start; + const char *end; + char operation = '\0'; + size_t length; + KztLibraryGroup group; + + cursor = kzt_skip_space(cursor); + if (!*cursor || *cursor == ',') { + snprintf(group_error, sizeof(group_error), + "contains an empty library group"); + return false; + } + if (*cursor == '+' || *cursor == '-') { + operation = *cursor++; + } + start = cursor; + while (*cursor && *cursor != ',') { + cursor++; + } + end = cursor; + while (end > start && g_ascii_isspace(end[-1])) { + end--; + } + length = end - start; + if (!length) { + snprintf(group_error, sizeof(group_error), + "contains a sign without a library group"); + return false; + } + if (length >= sizeof(token)) { + snprintf(group_error, sizeof(group_error), + "contains a group name longer than %zu bytes", + sizeof(token) - 1); + return false; + } + memcpy(token, start, length); + token[length] = '\0'; + + if (!strcasecmp(token, "stable")) { + if (operation || saw_token || *cursor == ',') { + snprintf(group_error, sizeof(group_error), + "'stable' must be used by itself"); + return false; + } + *mode = KZT_GROUP_SPEC_EXACT; + *use_stable = true; + saw_token = true; + } else { + group = kzt_group_from_name(token); + if (group == KZT_GROUP_NONE) { + kzt_set_unknown_group_error(token); + return false; + } + + if (operation) { + if (*mode == KZT_GROUP_SPEC_EXACT) { + snprintf(group_error, sizeof(group_error), + "cannot mix exact groups with + or - modifiers"); + return false; + } + *mode = KZT_GROUP_SPEC_MODIFY; + if (operation == '+') { + if (*removed & group) { + snprintf(group_error, sizeof(group_error), + "configures group '%s' as both enabled " + "and disabled", token); + return false; + } + *added |= group; + } else { + if (*added & group) { + snprintf(group_error, sizeof(group_error), + "configures group '%s' as both enabled " + "and disabled", token); + return false; + } + *removed |= group; + } + } else { + if (*mode == KZT_GROUP_SPEC_MODIFY) { + snprintf(group_error, sizeof(group_error), + "cannot mix exact groups with + or - modifiers"); + return false; + } + *mode = KZT_GROUP_SPEC_EXACT; + *selected |= group; + } + saw_token = true; + } + + if (!*cursor) { + break; + } + cursor++; + if (!*kzt_skip_space(cursor)) { + snprintf(group_error, sizeof(group_error), + "contains a trailing comma"); + return false; + } + } + return true; +} + +static uint32_t kzt_add_dependencies(uint32_t groups) +{ + uint32_t previous; + + do { + previous = groups; + for (size_t i = 0; i < ARRAY_SIZE(kzt_group_definitions); i++) { + if (groups & kzt_group_definitions[i].group) { + groups |= kzt_group_definitions[i].dependencies; + } + } + } while (groups != previous); + return groups; +} + +static uint32_t kzt_prune_missing_dependencies(uint32_t groups) +{ + uint32_t previous; + + do { + previous = groups; + for (size_t i = 0; i < ARRAY_SIZE(kzt_group_definitions); i++) { + const KztGroupDefinition *definition = + &kzt_group_definitions[i]; + + if ((groups & definition->group) && + (groups & definition->dependencies) != + definition->dependencies) { + groups &= ~definition->group; + } + } + } while (groups != previous); + return groups; +} + +static void kzt_groups_log_mask(const char *label, uint32_t groups) +{ + bool first = true; + + fprintf(stderr, "KZT: %s: ", label); + for (size_t i = 0; i < ARRAY_SIZE(kzt_group_definitions); i++) { + if (!(groups & kzt_group_definitions[i].group)) { + continue; + } + fprintf(stderr, "%s%s", first ? "" : ",", + kzt_group_definitions[i].name); + first = false; + } + fprintf(stderr, "%s\n", first ? "none" : ""); +} + +static void kzt_groups_log_effective(const char *spec, uint32_t dependencies, + uint32_t removed, uint32_t pruned) +{ + if (!group_log_enabled) { + return; + } + fprintf(stderr, "KZT: requested library groups: %s\n", + spec && *kzt_skip_space(spec) ? spec : "stable"); + if (dependencies) { + kzt_groups_log_mask("added required library groups", dependencies); + } + if (removed) { + kzt_groups_log_mask("explicitly disabled library groups", removed); + } + if (pruned) { + kzt_groups_log_mask("disabled dependent library groups", pruned); + } + kzt_groups_log_mask("enabled library groups", enabled_groups); +} + +KztLibraryGroup kzt_group_for_library(const char *soname) +{ + if (!soname) { + return KZT_GROUP_NONE; + } + + for (size_t i = 0; i < ARRAY_SIZE(kzt_library_groups); i++) { + if (!strcmp(soname, kzt_library_groups[i].soname)) { + return kzt_library_groups[i].group; + } + } + + return KZT_GROUP_NONE; +} + +const char *kzt_group_name(KztLibraryGroup group) +{ + for (size_t i = 0; i < ARRAY_SIZE(kzt_group_definitions); i++) { + if (group == kzt_group_definitions[i].group) { + return kzt_group_definitions[i].name; + } + } + return "none"; +} + +void kzt_groups_reset(void) +{ + enabled_groups = KZT_GROUP_STABLE; + group_log_enabled = false; + group_error[0] = '\0'; + memset(library_decision_logged, 0, sizeof(library_decision_logged)); +} + +bool kzt_groups_configure(const char *spec, bool log_enabled) +{ + KztGroupSpecMode mode = KZT_GROUP_SPEC_UNSET; + uint32_t selected = KZT_GROUP_NONE; + uint32_t added = KZT_GROUP_NONE; + uint32_t removed = KZT_GROUP_NONE; + uint32_t groups; + uint32_t before_dependencies; + uint32_t before_prune; + uint32_t dependencies; + uint32_t pruned; + bool use_stable = false; + + group_error[0] = '\0'; + memset(library_decision_logged, 0, sizeof(library_decision_logged)); + if (!kzt_parse_group_spec(spec, &mode, &selected, &added, &removed, + &use_stable)) { + enabled_groups = KZT_GROUP_NONE; + group_log_enabled = log_enabled; + return false; + } + + if (mode == KZT_GROUP_SPEC_EXACT && !use_stable) { + groups = selected; + } else { + groups = KZT_GROUP_STABLE; + } + if (mode == KZT_GROUP_SPEC_MODIFY) { + groups |= added; + } + before_dependencies = groups; + groups = kzt_add_dependencies(groups); + dependencies = groups & ~before_dependencies; + groups &= ~removed; + before_prune = groups; + enabled_groups = kzt_prune_missing_dependencies(groups); + pruned = before_prune & ~enabled_groups; + group_log_enabled = log_enabled; + kzt_groups_log_effective(spec, dependencies, removed, pruned); + return true; +} + +void kzt_groups_reject_configuration(const char *reason, bool log_enabled) +{ + enabled_groups = KZT_GROUP_NONE; + group_log_enabled = log_enabled; + snprintf(group_error, sizeof(group_error), "%s", reason); +} + +uint32_t kzt_groups_enabled_mask(void) +{ + return enabled_groups; +} + +bool kzt_group_is_enabled(KztLibraryGroup group) +{ + return group != KZT_GROUP_NONE && (enabled_groups & group) == group; +} + +bool kzt_library_is_enabled(const char *soname) +{ + return kzt_group_is_enabled(kzt_group_for_library(soname)); +} + +const char *kzt_groups_last_error(void) +{ + return group_error; +} + +void kzt_groups_log_library(const char *soname, bool enabled) +{ + if (!group_log_enabled) { + return; + } + + for (size_t i = 0; i < ARRAY_SIZE(kzt_library_groups); i++) { + if (strcmp(soname, kzt_library_groups[i].soname)) { + continue; + } + + g_mutex_lock(&group_log_lock); + if (!library_decision_logged[i]) { + library_decision_logged[i] = true; + fprintf(stderr, "KZT: %s KZT wrapper for %s (group %s)\n", + enabled ? "using" : "skipping", soname, + kzt_group_name(kzt_library_groups[i].group)); + } + g_mutex_unlock(&group_log_lock); + return; + } +} diff --git a/target/i386/latx/context/library.c b/target/i386/latx/context/library.c index df0a7e6b7cc..af2ae878fea 100755 --- a/target/i386/latx/context/library.c +++ b/target/i386/latx/context/library.c @@ -29,6 +29,7 @@ #include "librarian.h" #include "librarian_private.h" #include "pathcoll.h" +#include "kzt-groups.h" #define GO(P, N, G) int wrapped##N##_init(library_t* lib, box64context_t *box64); \ void wrapped##N##_fini(library_t* lib); \ @@ -201,7 +202,11 @@ int FindLibIsWrapped(char * name) int nb = sizeof(wrappedlibs) / sizeof(wrappedlib_t); for (int i=0; iname, wrappedlibs[i].name)==0) { + if (!kzt_library_is_enabled(lib->name)) { + kzt_groups_log_library(lib->name, false); + return; + } if(wrappedlibs[i].init(lib, context)) { // error! const char* error_str = dlerror(); @@ -244,6 +253,7 @@ static void initNativeLib(library_t *lib, box64context_t* context) { lm->l_addr = real_lm.l_addr; lm->l_name = real_lm.l_name; lm->l_ld = real_lm.l_ld; + kzt_groups_log_library(lib->name, true); break; } } diff --git a/target/i386/latx/context/meson.build b/target/i386/latx/context/meson.build index fbf30369509..60db56cbea2 100644 --- a/target/i386/latx/context/meson.build +++ b/target/i386/latx/context/meson.build @@ -59,6 +59,7 @@ my_file = files( 'dictionnary.c', 'symbols.c', 'library.c', + 'kzt-groups.c', 'pathcoll.c', 'fileutils.c', 'elfparser.c', diff --git a/target/i386/latx/include/kzt-groups.h b/target/i386/latx/include/kzt-groups.h new file mode 100644 index 00000000000..eeb8d7d6f51 --- /dev/null +++ b/target/i386/latx/include/kzt-groups.h @@ -0,0 +1,53 @@ +/* + * SPDX-FileCopyrightText: 2026 LAT Project Authors + * + * SPDX-License-Identifier: GPL-2.0-only + */ + +#ifndef LATX_KZT_GROUPS_H +#define LATX_KZT_GROUPS_H + +#include +#include + +#include "kzt-group-list.h" + +typedef enum KztLibraryGroup { + KZT_GROUP_NONE = 0, +#define KZT_GROUP_ENUM(identifier, name, bit, stability, dependencies) \ + KZT_GROUP_##identifier = 1U << bit, + KZT_GROUP_LIST(KZT_GROUP_ENUM) +#undef KZT_GROUP_ENUM +} KztLibraryGroup; + +/* + * Group selection controls whether a guest library is eligible for its KZT + * wrapper. It does not imply that every custom wrapper function executes + * only host code: loader coordination and callback wrappers may deliberately + * re-enter guest execution to preserve guest-visible state. + */ + +#define KZT_GROUP_STABLE_MASK_STABLE(group) | (group) +#define KZT_GROUP_STABLE_MASK_EXPERIMENTAL(group) +#define KZT_GROUP_STABLE_MASK(identifier, name, bit, stability, dependencies) \ + KZT_GROUP_STABLE_MASK_##stability(KZT_GROUP_##identifier) +enum { + KZT_GROUP_STABLE = KZT_GROUP_NONE + KZT_GROUP_LIST(KZT_GROUP_STABLE_MASK), +}; +#undef KZT_GROUP_STABLE_MASK +#undef KZT_GROUP_STABLE_MASK_EXPERIMENTAL +#undef KZT_GROUP_STABLE_MASK_STABLE + +KztLibraryGroup kzt_group_for_library(const char *soname); +const char *kzt_group_name(KztLibraryGroup group); +void kzt_groups_reset(void); +bool kzt_groups_configure(const char *spec, bool log_enabled); +void kzt_groups_reject_configuration(const char *reason, bool log_enabled); +uint32_t kzt_groups_enabled_mask(void); +bool kzt_group_is_enabled(KztLibraryGroup group); +bool kzt_library_is_enabled(const char *soname); +const char *kzt_groups_last_error(void); +void kzt_groups_log_library(const char *soname, bool enabled); + +#endif /* LATX_KZT_GROUPS_H */ diff --git a/target/i386/latx/include/latx-options.h b/target/i386/latx/include/latx-options.h index 98814baddbe..bb396086e45 100644 --- a/target/i386/latx/include/latx-options.h +++ b/target/i386/latx/include/latx-options.h @@ -33,6 +33,9 @@ extern int option_tu_link; #ifdef CONFIG_LATX_KZT extern int option_kzt_log; +extern char *option_kzt_libs; +extern char *option_kzt_error; +extern char *option_kzt_log_error; #endif #ifdef CONFIG_LATX_AVX_OPT @@ -152,6 +155,7 @@ extern unsigned long long counter_mips_tr; #if defined(CONFIG_LATX) && defined(CONFIG_LATX_KZT) #define ENVSUP_KZT \ ENVFUN(LATX_KZT, handle_arg_latx_kzt) \ + ENVFUN(LATX_KZT_LIBS, handle_arg_latx_kzt_libs) \ ENVFUN(LATX_KZT_LOG, handle_arg_latx_kzt_log) #else #define ENVSUP_KZT @@ -230,6 +234,7 @@ extern unsigned long long counter_mips_tr; ENVSUP_PLUGIN void options_init(void); +bool latx_options_finalize(void); void options_parse_opt(const char *opt); void options_parse_imm_reg(const char *bits); void options_parse_dump(const char *bits); diff --git a/target/i386/latx/latx-options.c b/target/i386/latx/latx-options.c index 08c920392b5..df1feab32ce 100644 --- a/target/i386/latx/latx-options.c +++ b/target/i386/latx/latx-options.c @@ -12,10 +12,16 @@ #include "latx-runtime.h" #include "latx-string-utils.h" #include "translate.h" +#if defined(CONFIG_LATX_KZT) +#include "kzt-groups.h" +#endif #if defined(CONFIG_LATX_KZT) int option_kzt = 0; int option_kzt_log = 0; +char *option_kzt_libs; +char *option_kzt_error; +char *option_kzt_log_error; #endif #ifdef CONFIG_LATX_AVX_OPT @@ -210,6 +216,14 @@ void conf_init(char **argv) void options_init(void) { latx_runtime_reset(); +#if defined(CONFIG_LATX_KZT) + option_kzt = 0; + option_kzt_log = 0; + g_clear_pointer(&option_kzt_libs, g_free); + g_clear_pointer(&option_kzt_error, g_free); + g_clear_pointer(&option_kzt_log_error, g_free); + kzt_groups_reset(); +#endif option_debug_lative = 0; option_save_xmm = 0xff; option_dump_host = 0; @@ -271,6 +285,33 @@ void options_init(void) option_fast_atomic = 0; } +bool latx_options_finalize(void) +{ +#if defined(CONFIG_LATX_KZT) + if (option_kzt_log_error) { + kzt_groups_reject_configuration(option_kzt_log_error, true); + option_kzt = 0; + return false; + } + if (option_kzt_error) { + kzt_groups_reject_configuration(option_kzt_error, + option_kzt_log != 0); + option_kzt = 0; + return false; + } + if (option_kzt == 0) { + kzt_groups_reset(); + return true; + } + if (!kzt_groups_configure(option_kzt_libs, + option_kzt_log != 0 && option_kzt != 0)) { + option_kzt = 0; + return false; + } +#endif + return true; +} + #define OPTIONS_IMM_REG 0 #define OPTIONS_IMM_RIP 1 #define OPTIONS_IMM_COMPLEX 2 From 68acac5f2d7015c24674e5d2a9bb6f1bfc436507 Mon Sep 17 00:00:00 2001 From: Hanlu Li Date: Thu, 13 Aug 2026 15:53:41 +0800 Subject: [PATCH 3/4] linux-user, fix: Expose help in product builds The help handler and usage formatter were compiled only for LATX or TCG debug configurations, so product binaries rejected -h and --help. Make help available in all builds and tolerate argument-table entries without an environment-variable name. Both single- and double-dash option spellings remain supported. Signed-off-by: Hanlu Li --- linux-user/main.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index c538ce6612b..0efddf652a1 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -184,9 +184,7 @@ static int last_log_mask; unsigned long reserved_va; -#if defined(CONFIG_LATX_DEBUG) || defined(CONFIG_DEBUG_TCG) static void usage(int exitcode); -#endif const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX; const char *qemu_uname_release; @@ -423,11 +421,6 @@ static void handle_arg_latx_disassemble_trace_cmp(const char *arg) #endif -static void handle_arg_help(const char *arg) -{ - usage(EXIT_SUCCESS); -} - static void handle_arg_imm_skip_pc(const char *arg) { imm_skip_pc = strtol(arg, NULL, 16); } @@ -605,6 +598,12 @@ static void handle_arg_plugin(const char *arg) #endif #endif +static void handle_arg_help(const char *arg) +{ + (void)arg; + usage(EXIT_SUCCESS); +} + #ifdef CONFIG_LATX static void handle_arg_version(const char *arg) { @@ -992,10 +991,6 @@ static const struct qemu_argument arg_table[] = { true, handle_arg_latx_disassemble_trace_cmp, "", "LATX Compare different disassemble."}, #endif - {"h", "", false, handle_arg_help, - "", "print this help"}, - {"help", "", false, handle_arg_help, - "", ""}, {"g", "LAT_GDB", true, handle_arg_gdb, "port", "wait gdb connection to 'port'"}, {"s", "LAT_STACK_SIZE", true, handle_arg_stack_size, @@ -1040,6 +1035,10 @@ static const struct qemu_argument arg_table[] = { "", "[file=][,arg=]"}, #endif #endif + {"h", NULL, false, handle_arg_help, + "", "print this help"}, + {"help", NULL, false, handle_arg_help, + "", "print this help"}, {"L", "LAT_LD_PREFIX", true, handle_arg_ld_prefix, "path", "set the elf interpreter prefix to 'path'"}, {"runtime-info", NULL, false, handle_arg_runtime_info, @@ -1049,7 +1048,6 @@ static const struct qemu_argument arg_table[] = { {NULL, NULL, false, NULL, NULL, NULL} }; -#if defined(CONFIG_LATX_DEBUG) || defined(CONFIG_DEBUG_TCG) static void usage(int exitcode) { const struct qemu_argument *arginfo; @@ -1073,8 +1071,10 @@ static void usage(int exitcode) if (arginfo->has_arg) { arglen += strlen(arginfo->example) + 1; } - if (strlen(arginfo->env) > maxenvlen) { - maxenvlen = strlen(arginfo->env); + const char *env = arginfo->env ? arginfo->env : ""; + + if (strlen(env) > maxenvlen) { + maxenvlen = strlen(env); } if (arglen > maxarglen) { maxarglen = arglen; @@ -1085,13 +1085,15 @@ static void usage(int exitcode) maxenvlen, "Env-variable"); for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) { + const char *env = arginfo->env ? arginfo->env : ""; + if (arginfo->has_arg) { printf("-%s %-*s %-*s %s\n", arginfo->argv, (int)(maxarglen - strlen(arginfo->argv) - 1), - arginfo->example, maxenvlen, arginfo->env, arginfo->help); + arginfo->example, maxenvlen, env, arginfo->help); } else { printf("-%-*s %-*s %s\n", maxarglen, arginfo->argv, - maxenvlen, arginfo->env, + maxenvlen, env, arginfo->help); } } @@ -1116,11 +1118,11 @@ static void usage(int exitcode) " LAT_SET_ENV=var1=val2,var2=val2 LAT_UNSET_ENV=LD_PRELOAD,LD_DEBUG\n" "Note that if you provide several changes to a single variable\n" "the last change will stay in effect.\n" + "Both -option and --option spellings are accepted.\n" "\n"); exit(exitcode); } -#endif struct ParseOption { const char *opt_name; From 85c5f0e4d5ac23028a95363212bf6d53d9881f4b Mon Sep 17 00:00:00 2001 From: Hanlu Li Date: Thu, 13 Aug 2026 15:54:46 +0800 Subject: [PATCH 4/4] LATX, feat: Add KZT library group query Add --kzt-libs as a no-guest query for the library groups, stability status, dependencies, and accepted LATX_KZT_LIBS syntax compiled into the installed translator. Keep the README independent of a duplicated group inventory by directing users to the query command. The existing -h and --help output advertises both the selector and query. Signed-off-by: Hanlu Li --- README.en.rst | 23 +++++++++++++++++++--- README.rst | 19 +++++++++++++++++- docs/user/latx-environment.rst | 6 ++++++ linux-user/main.c | 20 ++++++++++++++----- target/i386/latx/context/kzt-groups.c | 28 +++++++++++++++++++++++++++ target/i386/latx/include/kzt-groups.h | 1 + 6 files changed, 88 insertions(+), 9 deletions(-) diff --git a/README.en.rst b/README.en.rst index e4c52a5da58..8d06bea529a 100644 --- a/README.en.rst +++ b/README.en.rst @@ -232,9 +232,10 @@ x86 instruction set coverage: Runtime behavior notes: -- Library pass-through (``LATX_KZT``) is available only in 64-bit builds and - is enabled subject to compatibility checks by default. 32-bit builds do - not provide this option. +- KZT wrappers (``LATX_KZT``) are available only in 64-bit builds. Run + ``latx-x86_64 --kzt-libs`` to list the library groups, stability status, and + dependencies provided by the installed version. 32-bit builds do not + provide this option. - Multi-threaded guests use the QEMU user-mode threading model; atomic instructions select an optimized path according to host kernel capabilities. @@ -254,6 +255,22 @@ command-line options. The `LATX configuration reference `_ describes precedence and common settings. This reference is currently available in Chinese. +Common KZT library-group controls: + +.. code-block:: bash + + # List the groups provided by this version + latx-x86_64 --kzt-libs + + # Enable the current stable set + LATX_KZT=1 latx-x86_64 /path/to/program + + # Remove one group and its dependents from the stable set + LATX_KZT=1 LATX_KZT_LIBS=-x11 latx-x86_64 /path/to/program + + # Select one group and its required dependencies + LATX_KZT=1 LATX_KZT_LIBS=x11 latx-x86_64 /path/to/program + AVX Instruction Support ======================= diff --git a/README.rst b/README.rst index 0b71415edbc..116f0213453 100644 --- a/README.rst +++ b/README.rst @@ -211,7 +211,8 @@ x86 指令集覆盖: 运行行为说明: -- 库直通( ``LATX_KZT`` )仅在 64 位构建中提供,默认按兼容性检查启用; +- KZT wrapper( ``LATX_KZT`` )仅在 64 位构建中提供。可以运行 + ``latx-x86_64 --kzt-libs`` 查询当前版本提供的库族、稳定状态和依赖关系; 32 位构建没有该选项。 - 多线程 guest 程序沿用 QEMU 用户态多线程模型,原子指令根据宿主内核能力 选择优化路径。 @@ -227,6 +228,22 @@ x86 指令集覆盖: LATX 支持系统配置文件、用户配置文件、环境变量和命令行参数。优先级、常用配置 及示例见 `LATX 配置信息 `_。 +KZT 库族控制的常用方式: + +.. code-block:: bash + + # 查询当前版本提供的库族 + latx-x86_64 --kzt-libs + + # 启用当前稳定库族 + LATX_KZT=1 latx-x86_64 /path/to/program + + # 从稳定集合关闭一个库族及其依赖者 + LATX_KZT=1 LATX_KZT_LIBS=-x11 latx-x86_64 /path/to/program + + # 只启用一个库族及其必要依赖 + LATX_KZT=1 LATX_KZT_LIBS=x11 latx-x86_64 /path/to/program + AVX 指令支持 ============ diff --git a/docs/user/latx-environment.rst b/docs/user/latx-environment.rst index 907da3e9fac..97fe62cded5 100644 --- a/docs/user/latx-environment.rst +++ b/docs/user/latx-environment.rst @@ -163,6 +163,12 @@ wrapper 测试需要设置 ``LATX_KZT_LIBS``。总开关为 ``0`` 时忽略库 库族名称、稳定状态和依赖关系由当前 LATX 构建定义,不在文档中维护一份容易 过期的静态清单。下面的 ``x11``、``gl`` 等名称只用于说明选择语法。 +运行以下命令可以查询当前安装版本提供的清单,无需指定 guest 程序: + +.. code-block:: bash + + latx-x86_64 --kzt-libs + ``LATX_KZT_LIBS`` 只有两种写法,不能混用: * 不带符号的名称表示“只启用这些库族”,例如 ``x11`` 或 ``x11,gl``; diff --git a/linux-user/main.c b/linux-user/main.c index 0efddf652a1..5023a23807b 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -699,6 +699,13 @@ static void handle_arg_latx_kzt_log(const char *arg) } option_kzt_log = value; } + +static void handle_arg_kzt_libs_info(const char *arg) +{ + (void)arg; + kzt_groups_print_available(); + exit(EXIT_SUCCESS); +} #endif static void handle_arg_latx_fputag(const char *arg) @@ -917,6 +924,8 @@ static const struct qemu_argument arg_table[] = { "group,...", "select KZT library groups"}, {"latx-kzt-log", "LATX_KZT_LOG", true, handle_arg_latx_kzt_log, "0|1", "log important KZT binding and fallback decisions"}, + {"kzt-libs", NULL, false, handle_arg_kzt_libs_info, + "", "list available KZT library groups and exit"}, #endif {"latx-fputag", "LATX_FPUTAG", true, handle_arg_latx_fputag, "", "enable fputag"}, @@ -1257,12 +1266,13 @@ static int parse_args(int argc, char **argv) } else { if (!strcmp(r, "version") || !strcmp(r, "h") || !strcmp(r, "help") - || !strcmp(r, "runtime-info")) { + || !strcmp(r, "runtime-info") + || !strcmp(r, "kzt-libs")) { /* - * runtime-info must take effect here so it can be used - * without a guest. options_set() intentionally - * replays its idempotent handler with the other - * command-line options. + * Query options must take effect here so they can be + * used without a guest. options_set() intentionally + * replays the idempotent runtime-info handler with the + * other command-line options. */ arginfo->handle_opt(NULL); } diff --git a/target/i386/latx/context/kzt-groups.c b/target/i386/latx/context/kzt-groups.c index 39b72c59e8e..ca51d4e9d17 100644 --- a/target/i386/latx/context/kzt-groups.c +++ b/target/i386/latx/context/kzt-groups.c @@ -296,6 +296,34 @@ const char *kzt_group_name(KztLibraryGroup group) return "none"; } +void kzt_groups_print_available(void) +{ + puts("Available KZT library groups:"); + for (size_t i = 0; i < ARRAY_SIZE(kzt_group_definitions); i++) { + const KztGroupDefinition *definition = &kzt_group_definitions[i]; + uint32_t dependencies = + kzt_add_dependencies(definition->group) & ~definition->group; + bool first = true; + + printf(" %-8s status=%s requires=", definition->name, + definition->stable ? "stable" : "experimental"); + for (size_t j = 0; j < ARRAY_SIZE(kzt_group_definitions); j++) { + if (!(dependencies & kzt_group_definitions[j].group)) { + continue; + } + printf("%s%s", first ? "" : ",", + kzt_group_definitions[j].name); + first = false; + } + puts(first ? "none" : ""); + } + puts("Selection syntax:"); + puts(" LATX_KZT_LIBS=stable use the current stable set"); + puts(" LATX_KZT_LIBS=name,... use only the named groups and " + "dependencies"); + puts(" LATX_KZT_LIBS=+name,-name modify the current stable set"); +} + void kzt_groups_reset(void) { enabled_groups = KZT_GROUP_STABLE; diff --git a/target/i386/latx/include/kzt-groups.h b/target/i386/latx/include/kzt-groups.h index eeb8d7d6f51..0986c548e73 100644 --- a/target/i386/latx/include/kzt-groups.h +++ b/target/i386/latx/include/kzt-groups.h @@ -41,6 +41,7 @@ enum { KztLibraryGroup kzt_group_for_library(const char *soname); const char *kzt_group_name(KztLibraryGroup group); +void kzt_groups_print_available(void); void kzt_groups_reset(void); bool kzt_groups_configure(const char *spec, bool log_enabled); void kzt_groups_reject_configuration(const char *reason, bool log_enabled);