海湾合作委员会的-Wpsabi 选项到底是做什么的? 抑制它的影响是什么?

背景资料

去年,我使用 nlohmann json 库 [1],在 x86 _ 64上使用 GCC 5.x arm-linux-gnueabi-*进行交叉编译,没有任何警告。当我将 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 是如何工作的... ...)

这些问题的答案是:

  • 特定于语言的 (因此你有一个 C ABI,C + + ABI,Fortran ABI,Pascal ABI,... 甚至 Java 字节码规范,虽然目标是一个“虚拟”处理器而不是实际的硬件,是一个 ABI) ,
  • 特定于操作系统的 (MS Windows 和 Linux 在同一硬件上使用不同的 ABI) ,
  • 特定于硬件/CPU 的 (ARM 和 x86ABI 是不同的)。
  • 随着时间的推移而发展(现有的 ABI 经常被更新/加速,以便新的 CPU 特性可以被利用,比如说,指定应用程序如何使用 x86 SSE 寄存器当然只有在 CPU 曾经这些规则时才可能,因此现有的 ABI 需要被澄清)。

因此,ABI 是总体组件,其中一个组件(“硬件/CPU 特定的”细节)是 psABI。

我的问题

我的问题是

  1. 我不喜欢在不了解其含义的情况下全面禁用警告。
  2. 对于这种在编译器升级后“突然出现”的诊断注释来说,“使用 -Wno-psabi使注释消失”似乎是相当常见的建议。甚至一个 GCC 开发人员也建议这样做
  3. 在 GCC 手册中,-Wpsabi-Wno-psabi都没有记录在 [6]

因此,我真的不知道究竟什么 -Wno-psabi会和不会影响。记录了一个相关的选项 -Wabi : [8]

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

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

此时已知的 psABI 变化包括:

  • 对于 SysV/x86-64,具有长双成员的联合按照 psABI 中指定的方式在内存中传递:

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

union U总是在内存中传递。

我对这一切的理解是

  1. 当 psABI 发生变化时,-Wabi将生成警告。
  2. GCC 7修复了 GCC 5中引入的 ABI bug [9],该 bug 会影响 ARM 目标。
    • 在发布说明中说明“这是 ABI 的改变”
    • 出于某种原因,发布说明指出,相关的诊断说明是在使用未记录的 -Wpsabi时生成的,而不是记录的 -Wabi
    • 手册中没有提到这个 ABI 变化。
  3. 把“这是一个 ABI 变化”和“使用 -Wpsabi”放在一起,在我看来,这是 特别是一个 psABI 变化,而不是一个不同类型的 ABI 变化。(实际上,这是 GCC 实现 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
11564 次浏览

You only need to worry about ABIs when you are crossing library boundaries. Within your own applications/libraries the ABI doesn't really matter as presumably all your object files are compiled with the same compiler version and switches.

If you have a library compiled with ABI1 and an application compiled with ABI2 then the application will crash when it tries to call functions from the library as it wont pass the arguments correctly. To fix the crash you would need to recompile the library (and any other libraries it depends on) with ABI2.

In your specific case as long as you compile nlohmann with the same compiler version as your application (or are just using nlohmann as a header) then you don't need to worry about the ABI change.

Globally suppressing the warning seems to be a dangerous option as it will prevent you from seeing any future ABI issues. A better option would be to use #pragma to disable the warning just for the functions in question, e.g.:

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