代码之家  ›  专栏  ›  技术社区  ›  E. Moffat

这个g++“非法指令错误”是因为用于构建gcc的cpu的体系结构吗?

  •  2
  • E. Moffat  · 技术社区  · 7 年前

    我们有一个基于映像的图像,它使用GCC 5.4构建一个大型C++代码库。docker映像从源代码构建并安装gcc。由于我们的私有Docker注册表中有一些数据丢失,我们不得不重新生成/将此Docker映像推回到注册表中,并开始发现使用此Docker映像的本地生成有问题。

    我们看到的错误是:

    /usr/include/c++/5.4.0/limits:1601:7: internal compiler error: Illegal instruction
           max() _GLIBCXX_USE_NOEXCEPT { return __FLT_MAX__; }
           ^
    0xa4f0cf crash_signal
            ../../gcc-5.4.0/gcc/toplev.c:383
    

    我的理论是,这个错误是由于运行构建的底层cpu的体系结构造成的,因为我们是从源代码构建gcc的。

    以前,我们有一个基于xeone5v3cpu(haswell架构)的ci基础设施。这个Docker图像的构建最初是在其中一台CI机器上完成的,因此在本地的Haswell开发箱上运行良好。我们的CI基础设施已经迁移到使用Xeon Platinum CPU(Skylake架构)。当我重建图像时,我在一个新的Skylake盒子上做了。

    由于我有一个新的开发框,我有一个基于Broadwell的CPU,无法在本地重现问题。我们的ci构建运行得非常好。在本地获取此错误的用户具有Haswell CPU。

    我的理论正确吗? 我已经要求用户在他们的CPU上本地构建Docker映像并测试结果,但是有没有更通用的方法来解决这个问题呢?

    我遇到了 this answer 让我直指 this documentation 哪些状态我可以通过 -march=*** . 我的想法是:

    1. 集合 -march=haswell 在构建gcc以防止启用较新的指令集时
    2. 集合 -mno-*** 为haswell上不可用但存在于broadwell/skylake上的指令集扩展构建gcc时。

    作为参考,输出 lscpu 有没有哈斯韦尔盒子上没有的布罗德韦尔旗 - MnO-** 标志):

    3dnowprefetch
    hle
    rtm
    rdseed
    adx
    smap
    arch_capabilities
    

    如果这些想法中的任何一个解决了这个问题,是否值得测试?我希望得到一些外部输入,因为这个docker构建的开发循环相当长,我真的不知道这些 -m 标志将解决问题。

    同样作为参考,以下是我们构建GCC的方法:

    # build/install gcc
    RUN tar xvf /tmp/archive/gcc-5.4.0.tar.gz && \
      mkdir gcc-build && \
      pushd gcc-build && \
      ../gcc-5.4.0/configure --prefix=/usr --enable-languages=c,c++,fortran --disable-multilib --with-gmp=/usr --with-mpfr=/usr --with-mpc=/usr && \
      make -j32 && \
      popd && \
      yum remove -y gcc gcc-c++ gcc-gfortran && \
      pushd gcc-build && \
      make install && \
      popd && \
      rm -rf gcc-build gcc-5.4.0
    
    1 回复  |  直到 7 年前
        1
  •  3
  •   Matthieu Brucher    7 年前

    如维基百科所示( https://en.wikipedia.org/wiki/List_of_Intel_CPU_microarchitectures ,天空湖在布罗德韦尔之后,它自己在哈斯韦尔之后。

    因此,Skylake上的构建可能无法在较旧的CPU上运行,您应该始终添加 -march=haswell 生成必须在haswell和更高版本上运行的二进制文件的默认生成。

    使用 -march ,知道启用其他指令集时可能会有数值差异。

    你也可以使用 -mtune 要指定将优化代码的目标(这意味着在这个平台上,代码应该更快)。你可以两者混合,只要 march 低于 mtune .