glibc - 在其他机器上运行预编译程序时出现“非法指令”
问题描述
我必须在 CentOS 7 上构建我的程序并部署在其他 Linux 机器上。该程序需要更新的版本glibc
,以及一些没有(也不会)安装在目标机器上的库。所以我决定用动态库发布可执行文件。我曾经patchelf
修补interpreter
和rpath
.
我在我的机器上测试了可执行文件并且它工作(也检查ldd
以确保使用新的 rpath)。但是当我使用库复制到其他机器时,程序无法运行。只打印了这一行:
非法指令
更新:
二进制
所以 SIGILL 是由函数中的shlx
指令引起的__tls_init()
。我不知道哪个库提供了这个功能,我不确定它来自 glibc。
我删除了我的 glibc,它是从另一台计算机上复制的,并使用目标计算机上已经安装的 glibc,但问题没有解决。
解决方案
我使用 patchelf 来修补解释器和 rpath
您的问题非常不清楚:您将解释器和 rpath 更改为what?
我认为你所做的是:
- 在非标准路径中构建新的 GLIBC 版本
- 用于
patchelf
更改二进制文件以指向非标准路径 - 将二进制和非标准 GLIBC 复制到目标机器
- 观察到
SIGILL
。
最可能的原因:您构建的非标准 GLIBC 没有为您的目标处理器配置,这与构建机器上使用的处理器不同。
默认情况下,GCC 将使用-march=native
,这意味着如果您在 Haswell 机器上构建,那么二进制文件将使用AVX2
目标机器不支持的指令。
要解决此问题,您需要向(和)添加或,-march=generic
并重建 GLIBC 和主程序。-march=$target_architecture
CFLAGS
CXXFLAGS
另一方面,您的 GDB 回溯显示了 GLIBC的标准/lib64/ld-linux-x86-64.so.2
路径:并且/lib64/libc.so.6
,所以也许我根本不理解您所做的步骤。
更新:
我没有构建新的 glibc,而是将其从我的机器复制到目标机器。我的机器使用 E5-2690v4,但目标机器使用 E5-2470。
E5-2690v4 是Broadwell . E5-2470 是常春藤桥。
前者支持AVX2,但后者不支持。将使用 AVX2 构建的 GLIBC 复制到 Ivy Bridge 很可能会失败,并会出现您所描述的症状(实际上应该会使 Ivy Bridge 完全无法工作;我很惊讶 它完全可以工作)。
使用 GDBx/i $pc
命令,您可以查看生成了SIGILL
. 如果它是 AVX2 指令,那可能就是答案。
推荐阅读
- angular - 角度导航栏问题
- ethereum - 向 Ropsten RPC 错误添加流动性:执行恢复:TransferHelper:TRANSFER_FROM_FAILED
- delphi - 为什么 Delphi 在添加新语言时会为项目的每个配置创建一个单独的 .rc 文件?
- java - 如何使用 Firebase ML Kit 文本识别检测图像中的小数
- python - TensorFlow 动态填充
- firebase - 文本小部件将实时 Fireabase 值检测为空
- python - Tkinter Button 通过单击鼠标具有打开和关闭功能
- python - kivy冻结屏幕
- twitter-oauth - Twitter oauth_signature 需要 urlencode(百分比十六进制编码)在签名库中的回调 url 上运行两次
- javascript - 脚本中未处理的 Promise Rejection