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。
采用源码编译的方式虽然可以完美修复出现的问题,但是编译的依赖和编译产物会占用大量储存空间,编译过程中会使手机极度发烫。
大家可以根据自己的实际情况选择适合的方法。
发表评论