簡體   English   中英

GCC的-Wpsabi選項究竟做了什么?抑制它有什么影響?

[英]What exactly does GCC's -Wpsabi option do? What are the implications of supressing it?

背景

去年我使用的是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( 應用程序二進制接口 )是一種標准,它定義了高級語言中的低級概念與特定硬件/ OS平台的機器代碼的能力之間的映射。 這包括以下內容:

  • 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 這些注冊表,因此需要澄清現有的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變化。 (實際上,它是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

當您跨越圖書館邊界時,您只需要擔心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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM