代码之家  ›  专栏  ›  技术社区  ›  Ciro Santilli OurBigBook.com

如何在编译时检查GNU气体组件代码中的BIUTILS版本?

  •  2
  • Ciro Santilli OurBigBook.com  · 技术社区  · 6 年前

    我有一些气体装配代码,我通过GCC直接编译它,使用预处理器的特性。 #include 以下内容:

    gcc main.S
    

    我遇到了一个给定的BiUTILS版本的BIUTILS错误,我希望有两个版本的代码,在编译时决定:

    • buggy binutils版本的解决方案版本
    • 否则主代码版本

    对于gcc本身的版本,我可以使用 __GNUC__ 以及相关宏,如中所述: How do I test at compile time the current version of GCC?

    比努提尔版本有类似的东西吗?

    我可以修改构建系统来检查 as --version 我自己通过了 gcc -D 定义,但我想知道这是否可以避免。

    2 回复  |  直到 6 年前
        1
  •  2
  •   Florian Weimer    6 年前

    有一个特殊的符号叫做 .gasversion. (有一个前后点)。你可以这样使用它:

            .data
    .if .gasversion. >= 22900
            .ascii "binutils 2.29 or newer"
    .endif
    .if .gasversion. >= 22800
            .ascii "binutils 2.28 or newer"
    .endif
    

    注意,这不是一个预处理器特性(因为GCC不知道GAND/BFD版本,并且不把它传递给预处理器)。所以你必须使用像 .if .macro 去实现你所需要的。

    通常情况下,如果实际存在的bug是在 configure 脚本和工作区仅在必要时才被激活。这意味着只在绝对需要的情况下使用解决方案,版本号不反映可能会修复bug的分发后备端口。显然,如果解决方案成本很高(因为它引入了额外的运行时开销),这是有意义的。

        2
  •  1
  •   jww    5 年前

    如何在编译时检查GNU气体组件代码中的BIUTILS版本?

    crypto++也有类似的问题。他们需要知道AS和LD版本,以确保ISA的指令部分,如SSE4( -msse4.1 ),爱依斯( -maes )和沙( -msha )在构建期间可用(以英特尔为例)。

    在gnumakefile密码中++ used to perform 以下内容:

    GCC_COMPILER := $(shell $(CXX) --version 2>/dev/null | $(GREP) -v -E '(llvm|clang)' | $(GREP) -i -c -E '(gcc|g\+\+)')
    ...
    
    ifneq ($(GCC_COMPILER),0)
      IS_GCC_29 := $(shell $(CXX) -v 2>&1 | $(GREP) -i -c -E gcc-9[0-9][0-9])
      GCC42_OR_LATER := $(shell $(CXX) -v 2>&1 | $(GREP) -i -c -E "gcc version (4\.[2-9]|[5-9]\.)")
      GCC46_OR_LATER := $(shell $(CXX) -v 2>&1 | $(GREP) -i -c -E "gcc version (4\.[6-9]|[5-9]\.)")
    endif
    
    ifneq ($(HAVE_GAS),0)
      GAS210_OR_LATER := $(shell $(CXX) -xc -c /dev/null -Wa,-v -o/dev/null 2>&1 | $(GREP) -c -E "GNU assembler version (2\.[1-9][0-9]|[3-9])")
      GAS217_OR_LATER := $(shell $(CXX) -xc -c /dev/null -Wa,-v -o/dev/null 2>&1 | $(GREP) -c -E "GNU assembler version (2\.1[7-9]|2\.[2-9]|[3-9])")
      GAS218_OR_LATER := $(shell $(CXX) -xc -c /dev/null -Wa,-v -o/dev/null 2>&1 | $(GREP) -c -E "GNU assembler version (2\.1[8-9]|2\.[2-9]|[3-9])")
      GAS219_OR_LATER := $(shell $(CXX) -xc -c /dev/null -Wa,-v -o/dev/null 2>&1 | $(GREP) -c -E "GNU assembler version (2\.19|2\.[2-9]|[3-9])")
      GAS224_OR_LATER := $(shell $(CXX) -xc -c /dev/null -Wa,-v -o/dev/null 2>&1 | $(GREP) -c -E "GNU assembler version (2\.2[4-9]|2\.[3-9]|[3-9])")
    endif
    

    后来Crypto++会做如下事情:

    ifeq ($(HAVE_GAS)$(GAS224_OR_LATER),10)
      CXXFLAGS += -DCRYPTOPP_DISABLE_SHA
    endif
    

    这个 10 String基本上等价于以下内容。这是执行布尔表达式的gnu makefile方法:

    if HAVE_GAS==true && GAS224_OR_LATER==false
      CXXFLAGS += -DCRYPTOPP_DISABLE_SHA
    fi
    

    顺便说一下,gas版本检查在clang和集成汇编程序中中断了。叮当不回应 -Wa,-v 就像这样。LLVM Bug 24200被归档是因为它: Fail to fetch version string of assembler when using integrated assembler 是的。


    Crypto++发现的是,这并不能很好地扩展。10年或20年前就可以了(字面上,最初使用时)。然而,当(1)新平台使用古老的工具链,如现代BSD固定到GPL2工具链时,(2)新编译器安装在旧平台上,如POWER6机器上的Clang7.0,以及(3)Clang及其集成汇编器,这不需要组装更高的ISA。

    ARM平台也很麻烦,因为项目无法 可靠的 确定何时包括 <arm_neon.h> <arm_acle.h> 基于平台和编译器版本。有时,报头可用于平台和编译器,有时它们不可用(甚至在同一平台上使用同一编译器的不同版本)。预处理器宏 __ARM_ACLE__ 完全不见了(见 ARM C Language Extensions (ACLE) )中。android和ios只是做了它想做的事情,从armhf和friends上发生的事情或者文档中声明的事情中解脱出来。微软找到了一个新的方法来打破他们的标题 <arm64_neon.h> 是的。

    现在crypto++通过gnu makefile执行测试编译,以查看程序是否可以编译、组装和链接。然而,它并不是像自动工具或CMAD那样头脑清醒。Crypto++查找任何诊断,但未通过任何诊断测试。这起案件中,AutoTo工具和Cmake失踪了,就像SunCC发出的一样。 “非法选项:-xarch=sha” 是的。AutoToobe和Cmake将报告成功,稍后构建失败。(显然,AutoTooCAD和CFEAR只检查编译器返回代码,而不是诊断消息,如“非法选项”)。

    crypto++测试 now look like 以下内容:

    SUN_COMPILER := $(shell $(CXX) -V 2>&1 | $(GREP) -i -c -E 'CC: (Sun|Studio)')
    ...
    
    ifeq ($(SUN_COMPILER),1)
      SSE2_FLAG = -xarch=sse2
    else
      SSE2_FLAG = -msse2
    endif
    ...
    
    TPROG = TestPrograms/test_x86_sse2.cxx
    TOPT = $(SSE2_FLAG)
    HAVE_OPT = $(shell $(CXX) $(TCXXFLAGS) $(ZOPT) $(TOPT) $(TPROG) -o $(TOUT) 2>&1 | tr ' ' '\n' | wc -l)
    ifeq ($(strip $(HAVE_OPT)),0)
      CHACHA_FLAG = $(SSE2_FLAG)
      SUN_LDFLAGS += $(SSE2_FLAG)
    else
      SSE2_FLAG =
    endif
    

    以及 test_x86_sse2.cxx ,编译于 -O0 所以优化程序不会删除代码:

    $ cat TestPrograms/test_x86_sse2.cxx
    #include <emmintrin.h>
    int main(int argc, char* argv[])
    {
        __m128i x = _mm_setzero_si128();
        x=_mm_add_epi64(x,x);
        return 0;
    }
    
    推荐文章