Что именно делает GCC -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 (Application Binary Interface) - это стандарт, который определяет сопоставление между низкоуровневыми концепциями на языках высокого уровня и возможностями конкретного машинного кода платформы аппаратного/ОС. Это включает в себя такие вещи, как:

  • как типы данных C/C++/Fortran/... располагаются в памяти (размеры/выравнивания данных)
  • как работают вложенные вызовы функций (где и как хранится информация о том, как вернуться к вызывающему функции, где в регистре CPU и/или аргументы функции памяти передаются)
  • как работает запуск/инициализация программы (какой формат данных имеет "исполняемый файл", как загружается код/​​данные, как работают DLL...)

Ответы на них следующие:

  • (следовательно, у вас есть C ABI, C++ ABI, Fortran ABI, Pascal ABI... даже спецификация байт-кода Java, хотя таргетинг на "виртуальный" процессор вместо реального оборудования - это ABI)
  • специфическая для операционной системы (MS Windows и Linux на одном и том же оборудовании используют другой ABI),
  • аппаратное обеспечение/процессор (ARM и x86 ABI разные).
  • (длинные) (существующие ABI часто обновлялись/обновлялись так, чтобы можно было использовать новые функции процессора, например, указать, как регистры SSE x86 будут использоваться приложениями, конечно, возможно только один раз У процессоров были эти регистры, поэтому существующие ABI необходимо было уточнить).

Таким образом, ABI является всеобъемлющим компонентом, а один из его компонентов (детали, специфичные для оборудования/ЦП) - это psABI.

Мой вопрос

Проблема, с которой я сталкиваюсь, - это

  1. Мне не нравятся универсальные отключения предупреждений, не понимая последствий.
  2. Совет "использование -Wno-psabi для -Wno-psabi заметок" кажется довольно распространенным советом для этих типов диагностических заметок, которые "внезапно появляются" после обновления компилятора. [2][3][4] Даже один из разработчиков GCC предлагает сделать это. [5]
  3. Ни -Wpsabi ни " -Wno-psabi не документированы [6] в руководстве GCC. [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 зафиксировал ошибку ABI [9], введенную в GCC 5, которая влияет на цели ARM.
    • В примечаниях к выпуску указано, что "это изменение ABI". [10]
    • По какой-то причине в примечаниях к выпуску указано, что связанные диагностические заметки генерируются при использовании недокументированного -Wpsabi, а не документально подтвержденного -Wabi.
    • Это изменение ABI не упоминается в руководстве.
  3. Объединяя "это изменение ABI" и "используйте -Wpsabi ", мне кажется, что это именно изменение psABI, а не другое изменение ABI. (В действительности это изменение в реализации GCC psABI, а не psABI)

Я знаю, что документация не всегда актуальна, особенно для того, что является известным недокументированным вариантом. Но я обеспокоен тем, что "использование -Wno-psabi ", по-видимому, является стандартным ответом на несколько разных типов этих загадочных диагностических заметок. Но, в моем основном понимании ABIs, не изменение ABI большое дело? Разве я не должен беспокоиться об изменении ABI, а не просто отбрасывать сообщение? Между недокументированным материалом и некоторыми более точными деталями ABI против psABI, я не совсем уверен...

Например, если я добавлю -Wno-psabi в свой make файл, чтобы -Wno-psabi эти заметки, что, если в будущем будет другое изменение ABI, которое повлияет на мой проект? Действительно ли я заставил замолчать будущие предупреждения или заметки, которые могут быть важны?

Кроме того, несмотря на то, что нам говорят: "Если вы перекомпилируете весь код, вам не о чем беспокоиться", [5] что такое "весь код"? Это мой исходный код? GLibC? Любая другая общедоступная библиотека в масштабе всей системы, которую я могу использовать?

Рекомендации

  1. https://github.com/nlohmann/json
  2. https://github.com/nlohmann/json/issues/658
  3. qaru.site/info/14949793/...
  4. qaru.site/info/1452703/...
  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. qaru.site/info/224888/...

Ответ 1

Вам нужно только беспокоиться об 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

Ответ 2

@Алан Биртлз

Прагма GCC диагностики игнорируется "-Wno-psabi"

"-Wno-psabi" недействителен в arm-gcc 8.2.1