Android使用chroot或proot容器运行ubuntu25.10(questing)使用llvmpipe渲染图形时出现非法指令(illegal instruction)的解决办法

一、原因分析

在llvm的某次提交后,aarch64架构会无条件地生成sve指令,但是对于现在市面上绝大部分手机来说,cpu普遍不支持该指令集。因此,在使用llvmpipe硬件渲染GUI程序时,llvm jit错误地生成了sve指令,而cpu无法识别该指令,导致了程序崩溃,使很多GUI程序无法运行。而ubuntu25.10(questing)的mesa使用了较新版本的llvm,在chroot和proot容器中引入了该问题。

二、解决方案

1.使用softpipe

我们可以弃用llvmpipe转而使用softpipe。添加以下环境变量:

export GALLIUM_DRIVER=softpipe

然后再运行GUI程序。虽然softpipe相较于llvmpipe效率低了很多,但是勉强可以用了。

2.重新编译mesa

为了解决这个问题我们需要重新编译mesa,在代码中加入cpu是否支持sve指令集的判断,防止jit时错误生成sve指令

首先拉取mesa的源代码:

git clone --recursive https://gitlab.freedesktop.org/mesa/mesa.git -b mesa-25.3.1

进入mesa目录:

cd mesa

启用源码源,将/etc/apt/sources.list改为:

deb [signed-by="/usr/share/keyrings/ubuntu-archive-keyring.gpg"] http://ports.ubuntu.com/ubuntu-ports questing main universe multiverse
deb [signed-by="/usr/share/keyrings/ubuntu-archive-keyring.gpg"] http://ports.ubuntu.com/ubuntu-ports questing-updates main universe multiverse
deb [signed-by="/usr/share/keyrings/ubuntu-archive-keyring.gpg"] http://ports.ubuntu.com/ubuntu-ports questing-security main universe multiverse
deb-src [signed-by="/usr/share/keyrings/ubuntu-archive-keyring.gpg"] http://ports.ubuntu.com/ubuntu-ports questing main universe multiverse
deb-src [signed-by="/usr/share/keyrings/ubuntu-archive-keyring.gpg"] http://ports.ubuntu.com/ubuntu-ports questing-updates main universe multiverse
deb-src [signed-by="/usr/share/keyrings/ubuntu-archive-keyring.gpg"] http://ports.ubuntu.com/ubuntu-ports questing-security main universe multiverse

然后

sudo apt update

完成之后安装mesa依赖:

sudo apt build-dep mesa

写入修复sve生成错误的补丁

nano sve-detect.patch

输入以下内容:

https://github.com/llvm/llvm-project/issues/114987
https://github.com/termux/termux-packages/issues/24544

--- a/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp
+++ b/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp
@@ -88,6 +88,23 @@
 #include "lp_bld_misc.h"
 #include "lp_bld_debug.h"

+#if __has_include(<sys/auxv.h>)
+#include <sys/auxv.h>
+#define HAVE_SYS_AUXV 1
+#ifndef AT_HWCAP
+#define AT_HWCAP    16
+#endif
+#ifndef AT_HWCAP2
+#define AT_HWCAP2   26
+#endif
+#ifndef HWCAP_SVE
+#define HWCAP_SVE   (1 << 22)
+#endif
+#ifndef HWCAP2_SVE2
+#define HWCAP2_SVE2 (1 << 1)
+#endif
+#endif
+
 static void lp_run_atexit_for_destructors(void);

 namespace {
@@ -446,6 +463,29 @@
    MAttrs.push_back("-lasx");
 #endif
 #endif
+
+#if DETECT_ARCH_AARCH64 && defined(HAVE_SYS_AUXV)
+   // Guess SVE/SVE2 support on ARM64
+   bool has_sve  = getauxval(AT_HWCAP)  & HWCAP_SVE;
+   bool has_sve2 = getauxval(AT_HWCAP2) & HWCAP2_SVE2;
+   MAttrs.push_back(has_sve  ? "+sve"  : "-sve");
+   MAttrs.push_back(has_sve2 ? "+sve2" : "-sve2");
+#endif
+
+   // Allow adding extra MAttrs through envs
+   char *env_extra_mattrs = getenv("GALLIVM_EXTRA_MATTRS");
+   if (env_extra_mattrs != NULL) {
+      char *dup = strdup(env_extra_mattrs);
+      if (dup != NULL) {
+         char *state;
+         char *token = strtok_r(dup, ",", &state);
+         while (token) {
+            MAttrs.push_back(token);
+            token = strtok_r(NULL, ",", &state);
+         }
+         free(dup);
+      }
+   }
 }

 void

保存退出。

应用补丁:

patch -p1 < ./sve-detect.patch

设置编译选项:

meson setup build/ \
    --prefix=/usr \
    -Dgbm=enabled \
    -Dopengl=true \
    -Degl=enabled \
    -Degl-native-platform=x11 \
    -Dgles1=disabled \
    -Dgles2=enabled \
    -Dglx=dri \
    -Dllvm=enabled \
    -Dshared-llvm=enabled \
    -Dplatforms=x11,wayland \
    -Dgallium-drivers=llvmpipe,softpipe,virgl,zink \
    -Dgallium-rusticl=true \
    -Dglvnd=enabled \
    -Dxmlconfig=disabled

如果上面出现错误,请检查llvm和clang的依赖是否缺失。

开始编译:

ninja -C build/

这个过程可能持续20-30分钟。编译完成后安装:

sudo ninja -C build/ install

刷新动态连接器缓存:

sudo ldconfig

原先崩溃的GUI程序应该能正常运行了。

三、总结

直接使用softpipe是最省时省力的解决方案,但是性能非常差,一些对图形性能要求高的应用可能会卡成ppt。

采用源码编译的方式虽然可以完美修复出现的问题,但是编译的依赖和编译产物会占用大量储存空间,编译过程中会使手机极度发烫。

大家可以根据自己的实际情况选择适合的方法。

发表评论