ChatGPT解决这个技术问题 Extra ChatGPT

GCC 的 -Wpsabi 选项到底有什么作用?压制它有什么影响?

背景

去年,我使用了 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如何工作......)答案这些是:特定于语言的(因此你有一个 C ABI、C++ ABI、Fortran ABI、Pascal ABI,......即使是 Java 字节码规范,虽然针对的是“虚拟”处理器而不是真实硬件,但也是一个 ABI )、操作系统特定(同一硬件上的 MS Windows 和 Linux 使用不同的 ABI)、硬件/CPU 特定(ARM 和 x86 ABI 不同)。随着(长时间)的发展(现有的 ABI 经常被更新/修订,以便可以使用新的 CPU 功能,例如,指定应用程序如何使用 x86 SSE 寄存器当然只有一次可能CPU 具有这些 regs,因此需要澄清现有的 ABI)。

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

我的问题

我遇到的问题是

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

因此,我不确定 -Wno-psabi 究竟会影响什么,不会影响什么。相关选项 -Wabi 已记录:[8]

-Wabi(仅限 C、Objective-C、C++ 和 Objective-C++)当 G++ 生成的代码可能与供应商中立的 C++ ABI 不兼容时发出警告...它还警告与 psABI 相关的更改。此时已知的 psABI 更改包括: 对于 SysV/x86-64,具有长双精度成员的联合在 psABI 中指定的内存中传递。例如: union U { long double ld;诠释我; }; union U 总是在内存中传递。

我对这一切的理解是

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

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

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

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

参考

https://github.com/nlohmann/json https://github.com/nlohmann/json/issues/658 https://stackoverflow.com/a/48149400 https://stackoverflow.com/a/13915796/10270632 https://gcc.gnu.org/ml/gcc/2017-05/msg00073.html https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81831 https://gcc.gnu.org/ onlinedocs/gcc-8.2.0/gcc https://gcc.gnu.org/onlinedocs/gcc-8.2.0/gcc/C_002b_002b-Dialect-Options.html https://gcc.gnu.org/bugzilla/show_bug。 cgi?id=77728 https://gcc.gnu.org/gcc-7/changes.html https://stackoverflow.com/a/8063350

@jesper-juhl 谢谢。我搜索 SO、邮件列表等寻找答案。我什至在 GCC 源代码中花了一些时间试图弄明白(也许可以贡献一个补丁来修复 the missing documentation),但我对 GCC 内部结构不够熟悉,无法弄明白。感觉就像用大锤敲钉子,然后忘记了普通锤子的存在......
我只是很难过我没有给你一个好的答案。但希望有人会过来。 :)
@jesper-juhl 这让我们两个:) 我想有一天我会不可避免地遇到一个还没有 SO 答案的问题,并且会被迫注册一个帐户来询问它。
我不认为这会影响你。如果标准库使用与您使用的相同 GCC 版本(我的意思是使用相同 abi 的版本)编译(这很可能),那么一切都应该没问题。
@Peter,是的,我们只使用 nlohmann 作为标题

A
Alan Birtles

当您跨越图书馆边界时,您只需要担心 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

很抱歉让一篇很老的帖子复活,但你说当从用 ABI2 编译的应用程序调用用 ABI1 编译的库时,应用程序会崩溃,这是有保证的行为,还是你使用术语“崩溃”作为一般术语描述“应用程序将行为不端”。以 Redhat 为例,他们只是说它不受支持且不能保证工作,而不是它会崩溃。老实说,我宁愿崩溃,但想了解这句话的来源。
是的,不保证它会崩溃,行为将是未定义的
undefined 是一个危险区域,当事情“看起来还不错”时,它会给粗心的人一种错误的安全感,然后当一切都崩溃时。更确切地说,应用程序无法启动并且问题得到了排序
@alan-birtles 哇,我好几年没登录了,甚至忘记了我问过这个问题。我会将您的答案标记为已接受,因为我认为它触及了我一直想知道的所有要点。 IIRC,由于这是针对嵌入式目标的,并且我们拥有所有 3rd 方库的源代码,因此我们最终只是使用更新的交叉编译器重新编译了所有内容。
对我来说,gcc 诊断编译指示无法识别“-Wno-psabi”。代码不会在其中构建该行。