Как проверить версию Binutils на коде сборки GNU GAS во время компиляции? - PullRequest
0 голосов

У меня есть некоторый код сборки GAS, и я собираю его напрямую через GCC, чтобы использовать такие функции препроцессора, как #include:

gcc main.S

Я столкнулся с сообщенной ошибкой Binutils для данной версии Binutils, и мне хотелось бы иметь две версии кода, определенные во время компиляции:

  • обходной вариант для ошибочной версии Binutils
  • основная версия кода в противном случае

Для самой версии GCC я могу использовать __GNUC__ и связанные макросы, как описано в: Как проверить во время компиляции текущую версию GCC?

Есть ли что-то подобное для версии Binutils?

Я мог бы изменить свою систему сборки, чтобы сам проверить as --version и передать определение gcc -D, но мне интересно, можно ли этого избежать.

Ответы [ 2 ]

0 голосов
/ 16 января 2019

Как проверить версию Binutils в коде сборки GNU GAS во время компиляции?

В Crypto ++ возникла похожая проблема.Им нужно было знать версии AS и LD, чтобы обеспечить наличие инструкций ISA, таких как SSE4 (-msse4.1), AES (-maes) и SHA (-msha) во время сборки (на примере Intel).

В GNUmakefile Crypto ++ используется для выполнения :

GCC_COMPILER := $(shell $(CXX) --version 2>/dev/null | $(GREP) -v -E '(llvm|clang)' | $(GREP) -i -c -E '(gcc|g\+\+)')
...

ifneq ($(GCC_COMPILER),0)
  IS_GCC_29 := $(shell $(CXX) -v 2>&1 | $(GREP) -i -c -E gcc-9[0-9][0-9])
  GCC42_OR_LATER := $(shell $(CXX) -v 2>&1 | $(GREP) -i -c -E "gcc version (4\.[2-9]|[5-9]\.)")
  GCC46_OR_LATER := $(shell $(CXX) -v 2>&1 | $(GREP) -i -c -E "gcc version (4\.[6-9]|[5-9]\.)")
endif

ifneq ($(HAVE_GAS),0)
  GAS210_OR_LATER := $(shell $(CXX) -xc -c /dev/null -Wa,-v -o/dev/null 2>&1 | $(GREP) -c -E "GNU assembler version (2\.[1-9][0-9]|[3-9])")
  GAS217_OR_LATER := $(shell $(CXX) -xc -c /dev/null -Wa,-v -o/dev/null 2>&1 | $(GREP) -c -E "GNU assembler version (2\.1[7-9]|2\.[2-9]|[3-9])")
  GAS218_OR_LATER := $(shell $(CXX) -xc -c /dev/null -Wa,-v -o/dev/null 2>&1 | $(GREP) -c -E "GNU assembler version (2\.1[8-9]|2\.[2-9]|[3-9])")
  GAS219_OR_LATER := $(shell $(CXX) -xc -c /dev/null -Wa,-v -o/dev/null 2>&1 | $(GREP) -c -E "GNU assembler version (2\.19|2\.[2-9]|[3-9])")
  GAS224_OR_LATER := $(shell $(CXX) -xc -c /dev/null -Wa,-v -o/dev/null 2>&1 | $(GREP) -c -E "GNU assembler version (2\.2[4-9]|2\.[3-9]|[3-9])")
endif

А позже Crypto ++ будет выполнять такие вещи, как:

ifeq ($(HAVE_GAS)$(GAS224_OR_LATER),10)
  CXXFLAGS += -DCRYPTOPP_DISABLE_SHA
endif

Строка 10в основном эквивалентно следующему.Это способ создания логических выражений в GNU Makefile:

if HAVE_GAS==true && GAS224_OR_LATER==false
  CXXFLAGS += -DCRYPTOPP_DISABLE_SHA
fi

Кстати, проверка версии GAS не работает с Clang и Integrated Assembler.Clang не отвечает на -Wa,-v, как AS.Ошибка LLVM 24200 была вызвана из-за этого: Не удалось получить строку версии ассемблера при использовании встроенного ассемблера .


То, что обнаружил Crypto ++, не очень хорошо масштабировалось.Это было нормально 10 или 20 лет назад (буквально, когда оно использовалось изначально).Однако это сломалось, когда (1) новые платформы используют древние цепочки инструментов, такие как современные BSD, прикрепляемые к цепям инструментов GPL2 (2) новые компиляторы были установлены на старые платформы, такие как Clang 7.0 на машине Power6, и (3) Clang и его интегрированный ассемблер,который не нуждался в AS для сборки более высоких ISA.

Платформы ARM также были очень хлопотными, потому что проект не мог надежно определить, когда включать <arm_neon.h> и <arm_acle.h> на основе платформ и компилятораверсии.Иногда заголовки были доступны для платформы и компилятора, иногда - нет (даже на одной и той же платформе с разными версиями одного и того же компилятора).Макросы препроцессора, такие как __ARM_ACLE__, полностью отсутствовали (см. ARM C Language Extensions (ACLE) ).Android и iOS просто делают то, что хотят, ломаясь от того, что происходит с armhf и друзьями или с тем, что указано в документации.И Microsoft нашла новый способ сломать его с помощью своего заголовка <arm64_neon.h>.

Теперь Crypto ++ выполняет тестовую компиляцию через Makefile GNU, чтобы посмотреть, можно ли скомпилировать, собрать и связать программу,Тем не менее, это не мозговой мертвец, как Autotools или Cmake.Crypto ++ ищет любую диагностику и не проходит тест на любую диагностику.Это обнаруживало случаи, когда Autotools и Cmake отсутствовали, например, SunCC излучал как "недопустимый параметр: -xarch = sha" .Autotools и Cmake сообщат об успехе, и позже сборка не удастся.(Очевидно, что Autotools и Cmake проверяют только коды возврата компилятора, а не диагностические сообщения, такие как «недопустимая опция»).

Тесты Crypto ++ теперь выглядят как :

SUN_COMPILER := $(shell $(CXX) -V 2>&1 | $(GREP) -i -c -E 'CC: (Sun|Studio)')
...

ifeq ($(SUN_COMPILER),1)
  SSE2_FLAG = -xarch=sse2
else
  SSE2_FLAG = -msse2
endif
...

TPROG = TestPrograms/test_x86_sse2.cxx
TOPT = $(SSE2_FLAG)
HAVE_OPT = $(shell $(CXX) $(TCXXFLAGS) $(ZOPT) $(TOPT) $(TPROG) -o $(TOUT) 2>&1 | tr ' ' '\n' | wc -l)
ifeq ($(strip $(HAVE_OPT)),0)
  CHACHA_FLAG = $(SSE2_FLAG)
  SUN_LDFLAGS += $(SSE2_FLAG)
else
  SSE2_FLAG =
endif

И test_x86_sse2.cxx, который компилируется в -O0, поэтому оптимизатор не удаляет код:

$ cat TestPrograms/test_x86_sse2.cxx
#include <emmintrin.h>
int main(int argc, char* argv[])
{
    __m128i x = _mm_setzero_si128();
    x=_mm_add_epi64(x,x);
    return 0;
}
0 голосов
/ 24 июня 2018

Существует специальный символ, который называется .gasversion. (с начальной и задней точкой). Вы можете использовать это так:

        .data
.if .gasversion. >= 22900
        .ascii "binutils 2.29 or newer"
.endif
.if .gasversion. >= 22800
        .ascii "binutils 2.28 or newer"
.endif

Обратите внимание, что это не функция препроцессора (поскольку GCC не знает версию GAS / BFD и не передает ее препроцессору). Таким образом, вы должны использовать конструкции GAS, такие как .if и .macro, чтобы реализовать то, что вам нужно.

Часто используется альтернативный подход, когда фактическое наличие ошибки проверяется в каком-то скрипте configure, и обходной путь активируется только при необходимости. Это означает, что обходной путь используется только тогда, когда он абсолютно необходим - номера версий не отражают бэкпорты распространения, которые могли бы исправить ошибку. Очевидно, что это имеет смысл только в том случае, если обходной путь является дорогостоящим (поскольку он вводит дополнительные накладные расходы времени выполнения).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...