首页 > 解决方案 > 在其他机器上运行预编译程序时出现“非法指令”

问题描述

我必须在 CentOS 7 上构建我的程序并部署在其他 Linux 机器上。该程序需要更新的版本glibc,以及一些没有(也不会)安装在目标机器上的库。所以我决定用动态库发布可执行文件。我曾经patchelf修补interpreterrpath.

我在我的机器上测试了可执行文件并且它工作(也检查ldd以确保使用新的 rpath)。但是当我使用库复制到其他机器时,程序无法运行。只打印了这一行:

非法指令

这是来自 gdb 的回溯 在此处输入图像描述

更新: 二进制 在此处输入图像描述 所以 SIGILL 是由函数中的shlx指令引起的__tls_init()。我不知道哪个库提供了这个功能,我不确定它来自 glibc。

我删除了我的 glibc,它是从另一台计算机上复制的,并使用目标计算机上已经安装的 glibc,但问题没有解决。

标签: glibcdynamic-linkingrpath

解决方案


我使用 patchelf 来修补解释器和 rpath

您的问题非常不清楚:您将解释器和 rpath 更改为what

认为你所做的是:

  1. 在非标准路径中构建新的 GLIBC 版本
  2. 用于patchelf更改二进制文件以指向非标准路径
  3. 将二进制和非标准 GLIBC 复制到目标机器
  4. 观察到SIGILL

最可能的原因:您构建的非标准 GLIBC 没有为您的目标处理器配置,这与构建机器上使用的处理器不同。

默认情况下,GCC 将使用-march=native,这意味着如果您在 Haswell 机器上构建,那么二进制文件将使用AVX2目标机器不支持的指令。

要解决此问题,您需要向(和)添加或,-march=generic并重建 GLIBC 和主程序。-march=$target_architectureCFLAGSCXXFLAGS

另一方面,您的 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 指令,那可能就是答案。


推荐阅读