GCC的-Wpsabi选项到底能做什么?抑制它的含义是什么?

时间:2018-08-25 18:51:01

标签: c++ linux gcc gcc-warning abi

背景

去年,我使用了nlohmann json库 [1] ,并且在没有警告的情况下使用GCC 5.x arm-linux-gnueabi-*在x86_64上进行了交叉编译。当我将GCC更新为较新版本时,GCC会生成含糊的诊断说明页面。例如,这是笔记之一

In file included from /usr/arm-linux-gnueabi/include/c++/7/vector:69:0,
             from include/json.hpp:58,
             from src/write_hsi.cpp:23:
/usr/arm-linux-gnueabi/include/c++/7/bits/vector.tcc: In member function ‘void std::vector<_Tp, _Alloc>::_M_realloc_insert(std::vector<_Tp, _Alloc>::iterator, _Args&& ...) [with _Args = {nlohmann::basic_json<std::map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long long int, long long unsigned int, double, std::allocator, nlohmann::adl_serializer>}; _Tp = nlohmann::basic_json<>; _Alloc = std::allocator<nlohmann::basic_json<> >]’:
/usr/arm-linux-gnueabi/include/c++/7/bits/vector.tcc:394:7: note: parameter passing for argument of type ‘std::vector<nlohmann::basic_json<>, std::allocator<nlohmann::basic_json<> > >::iterator {aka __gnu_cxx::__normal_iterator<nlohmann::basic_json<>*, std::vector<nlohmann::basic_json<>, std::allocator<nlohmann::basic_json<> > > >}’ changed in GCC 7.1
   vector<_Tp, _Alloc>::
   ^~~~~~~~~~~~~~~~~~~
/usr/arm-linux-gnueabi/include/c++/7/bits/vector.tcc: In member function ‘nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer> nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer>::parser::parse_internal(bool) [with ObjectType = std::map; ArrayType = std::vector; StringType = std::__cxx11::basic_string<char>; BooleanType = bool; NumberIntegerType = long long int; NumberUnsignedType = long long unsigned int; NumberFloatType = double; AllocatorType = std::allocator; JSONSerializer = nlohmann::adl_serializer]’:
/usr/arm-linux-gnueabi/include/c++/7/bits/vector.tcc:105:21: note: parameter passing for argument of type ‘__gnu_cxx::__normal_iterator<nlohmann::basic_json<>*, std::vector<nlohmann::basic_json<>, std::allocator<nlohmann::basic_json<> > > >’ changed in GCC 7.1
_M_realloc_insert(end(), std::forward<_Args>(__args)...);
~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

找到解决方案很容易,即在编译器选项中添加-Wno-psabi。实际上,这就是库中实现的修复程序。 [2]

我了解应用程序二进制接口(ABI)和特定于处理器的ABI(psABI)的基础。作为参考,此答案 [11] 简要介绍了ABI:

  

ABI( 应用程序二进制接口 )是一种标准,它定义了高级语言中的低级概念与特定硬件/操作系统的功能之间的映射。平台的机器代码。其中包括:

     
      
  • C / C ++ / Fortran / ... 数据类型在内存中的布局方式(数据大小/对齐方式)
  •   
  • 函数调用的工作方式(在哪里以及如何存储如何返回函数调用者的信息,在CPU寄存器和/或内存中传递函数参数的位置)
  •   
  • 程序启动/初始化的工作方式(“可执行文件”具有什么数据格式,如何从那里加载代码/数据,DLL如何工作...)
  •   
     

这些问题的答案是:

     
      
  • 特定于语言的(因此,尽管您针对的是“虚拟”处理器而不是Java字节码规范,但您已经拥有了C ABI,C ++ ABI,Fortran ABI,Pascal ABI ...真正的硬件,是ABI)
  •   
  • 特定于操作系统(同一硬件上的MS Windows和Linux使用不同的ABI),
  •   
  • 硬件/ CPU专用(ARM和x86 ABI不同)。
  •   
  • (长时间)演进(现有的ABI经常被更新/修订,以便可以利用新的CPU功能,例如,指定x86 SSE寄存器如何当然,只有在具有个CPU的情况下,应用程序才能使用它,因此需要澄清现有的ABI。
  •   

因此,ABI是总体组件,而其组件之一(“特定于硬件/ CPU”的详细信息)是psABI。

我的问题

我遇到的问题是

  1. 我不喜欢在不理解其含义的情况下普遍禁用警告。
  2. 对于使用编译器升级后“突然出现”的这些类型的诊断注释,“使用-Wno-psabi消除注释”的建议似乎是非常普遍的建议。 [2] [3] [4] 即使是一位GCC开发人员也建议这样做。 [5]
  3. GCC手册中没有记录-Wpsabi-Wno-psabi [6] [7]

因此,我不确定-Wno-psabi到底会和不会影响什么。记录了一个相关选项-Wabi [8]

  

-Wabi (C, Objective-C, C++ and Objective-C++ only)

     

警告,当G ++生成的代码可能与与供应商无关的C ++ ABI不兼容时...

     

它还警告与psABI相关的更改。此时已知的psABI更改包括:

     
      
  • 对于SysV / x86-64,具有长双精度成员的并集将按照psABI中的指定在内存中传递。例如:
  •   
     

union U {   long double ld;   int i;   };

     

union U始终在内存中传递。

我对这一切的理解是

  1. -Wabi将在psABI更改时生成警告。
  2. GCC 7修复了GCC 5中引入的会影响ARM目标的ABI错误 [9]
    • 在发行说明中指出:“这是ABI更改。” [10]
    • 出于某种原因,发行说明指出,相关的诊断说明是在使用未记录的-Wpsabi而不是已记录的-Wabi时生成的。
    • 此ABI更改未在手册中提及。
  3. 将“这是ABI更改”和“使用-Wpsabi”放在一起,在我看来,这是具体 psABI更改,而不是另一种ABI更改。 (实际上,这是海湾合作委员会对psABI实施的一种改变,而不是psABI本身)

我知道文档不一定总是最新的,尤其是对于某些已知的未文档记录的选项。但我担心的是,“使用-Wno-psabi”似乎是几种不同类型的这些神秘诊断说明的标准响应。但是,就我对ABI的基本了解而言,ABI的变化不是很大吗?我是否应该关注ABI的变化,而不仅仅是让信息消失?在未记录的内容和ABI与psABI的一些更详细的细节之间,我不太确定...

例如,如果我将-Wno-psabi添加到我的makefile中以使那些注释消失,那么如果将来 对我的项目有影响的另一项ABI更改怎么办?我是否有效地消除了将来可能很重要的警告或注意事项?

即使我们被告知“如果重新编译所有代码,也没有什么可担心的”, [5] “所有代码”到底是什么?那是我的源代码吗? glibc?我可能正在使用任何其他系统范围的共享库吗?

参考文献

  1. https://github.com/nlohmann/json
  2. https://github.com/nlohmann/json/issues/658
  3. https://stackoverflow.com/a/48149400
  4. https://stackoverflow.com/a/13915796/10270632
  5. https://gcc.gnu.org/ml/gcc/2017-05/msg00073.html
  6. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81831
  7. https://gcc.gnu.org/onlinedocs/gcc-8.2.0/gcc
  8. https://gcc.gnu.org/onlinedocs/gcc-8.2.0/gcc/C_002b_002b-Dialect-Options.html
  9. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77728
  10. https://gcc.gnu.org/gcc-7/changes.html
  11. https://stackoverflow.com/a/8063350

1 个答案:

答案 0 :(得分:3)

您只需要在跨越库边界时担心ABI。在您自己的应用程序/库中,ABI并不重要,因为您所有的目标文件都可以使用相同的编译器版本和开关进行编译。

如果您有一个使用ABI1编译的库和一个使用ABI2编译的应用程序,那么当它尝试从库中调用函数时,该应用程序将崩溃,因为它将无法正确传递参数。要解决崩溃问题,您需要使用ABI2重新编译该库(及其依赖的任何其他库)。

在特定情况下,只要您使用与应用程序相同的编译器版本(或者仅使用nlohmann作为标头)来编译nlohmann,那么您就不必担心ABI的更改。

全局禁止显示警告似乎是一个危险的选择,因为它将阻止您看到以后的任何ABI问题。更好的选择是使用#pragma仅为相关功能禁用警告,例如:

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wno-psabi"
void foo()
{
}
#pragma GCC diagnostic pop