Эльбрус/портирование
Перенос ПО на платформу Эльбрус
При сборке существующих программ порой возникает ряд типичных проблем и вопросов, которые отчасти систематизированы ниже (см. тж. страничку по компилятору).
В ALT RPM реализован макрос %e2k, рекомендуемый к применению в %ifarch.
configure: error: cannot guess build type; you must specify one
В архив исходников программы включены устаревшие копии этих файлов, поддержка e2k добавлена в gnu-config в 2015 году; достаточно обновить их вручную из свежей системной версии этого пакета или automake (который с большей вероятностью окажется под рукой) либо выполнить autoreconf -fisv:
cp -aLt . -- /usr/share/automake/config.{guess,sub}
В %changelog можно добавить, например[1]:
- fix build on newer arches
тесты на порядок байтов/битность
Нередко попадаются программы, которые интересует только длина указателей (размер integer) и, возможно, endianness; поскольку e2k -- 64-разрядная LE-архитектура, ищем подстроку вроде __amd64__, читаем контекст, добавляем аналогично __e2k__.
В альтовых пакетах на cmake исправления проверок битности порой выглядят примерно так[2]:
-%ifarch x86_64 +%if "%_lib" == "lib64" export LIB_SUFFIX=64 %endif
- fixed build on 64-bit architectures
В проектах на boost порой попадается тот ax_boost_base.m4, где в тест на lib64 забит список архитектур; его придётся поправить перед запуском autoreconf[3] как-то так:
%ifarch %e2k ppc64le riscv64 sed -i 's,aarch64,&|riscv64|ppc64le|e2k,' m4/ax_boost_base.m4 %endif
Про невыровненный доступ к памяти на версиях архитектуры до пятой включительно ("Эльбрус-8СВ") известно, что он достаточно дорогой; поэтому про unaligned access интересующемуся коду можно сообщить, что таковой отсутствует.
SIMD
Алгоритм портирования таких программ простой:
- ищем в исходниках макрос __x86_64__[4] или на худой конец i386; если они покрывают фрагменты кода с SIMD-интринсиками (функции, имена которых начинаются на _mm_), то нам повезло;
- заменяем defined __x86_64__ на defined __x86_64__ || defined __e2k__;
- если попадается динамическая проверка наличия MMX/SSE, то указываем, что у нас всё есть до SSE4.1[5];
- к asm-вставкам нужно творчески подходить, но чаще проще готовый generic-вариант кода использовать.
компилятор/архитектура
Имейте в виду при выписывании #ifdef:
- __e2k__ — это архитектура,
- __LCC__ — компилятор.
Во-первых, lcc есть не только для e2k (привет sparc), поэтому если делается патч под особенности lcc (и, вероятнее всего, фроентенда edg), то правильнее использовать __LCC__ .
Во-вторых, со временем на e2k могут появится и другие компиляторы, например, clang через соответствующий бэкенд на основе lcc. И у них уже может не быть макроса __LCC__ , а вот __e2k__ будет.
Поэтому мне представляется правильным архитектурно-зависимые изменения в e2k заворачивать, а компиляторо-зависимые в LCC. Понятно, что в реальной жизни их отличить не всегда просто. - @bircoph
отсутствие makecontext()
На Эльбрусах makecontext_e2k() выделяет память под дополнительные стеки, поэтому если просто заменить s/makecontext/makecontext_e2k/, в программе может появиться утечка памяти. Нужно ещё поставить вызов freecontext_e2k() там, где выделенный для makecontext_e2k() ucp.uc_stack перестаёт использоваться под данный контекст, т.е. где:
- ucp.uc_stack освобождается через free();
- ucp.uc_stack переиспользуется, например, под другой контекст.
отсутствие cpuid.h
Обуславливаем соответствующий #include и обращения к функциям так:
#if defined(__i386__) || defined(__x86_64__)
...не забывая добавить подходящую по смыслу заглушку вместо результата функции.
При необходимости подробного различения процессоров "Эльбрус" обратите внимание на __builtin_cpu_is(); в lcc от 1.23.23 и 1.24.10 должны быть доступны более удобные __builtin_cpu_name() и __builtin_cpu_arch() (#4484).
SIGILL вместо ожидаемого сигнала
Обратите внимание, что на e2k в некоторых случаях можно получить SIGILL (Illegal instruction) вместо ожидаемого SIGSEGV (Segmentation fault), SIGBUS (Bus error) или SIGFPE (Floating point exception).
Не тот сигнал приходит, как правило, либо в результате работы оптимизаций, либо при ручном написании кода на ассемблере или ассемблерных вставках. Если по каким-то причинам нужно поймать именно тот сигнал, который бы поймался на других архитектурах, то следует использовать режим с отключением оптимизаций, задействующих полуспекулятивный режим исполнения:
- -O0 -- режим компиляции без оптимизаций;
- -O1 -- минимальный набор оптимизаций;
- -fcontrol-spec -- запрет полуспекулятивных обращений к памяти (для сохранения сингалов SIGSEGV и SIGBUS);
- -fno-fp-spec -- запрет полуспекулятивных вещественных операций (для сохранения сигнала SIGFPE).
См. тж. Руководство и posix_signals.html[6].
Ссылки
- эльбрус/lcc
- Руководство по эффективному программированию на платформе «Эльбрус». 3. Отличия в интерфейсах
- Доклады из серии ALT на e2k:
- Free software porting on the Elbrus architecture
- Особенности портирования СПО на Эльбрус (Андрей Савченко, OSSDEVCONF-2019)
- Портирование Embox: [1], [2], [3]
- Портирование Java на Эльбрус
- Портирование JS на Эльбрус
- Константин Трушкин: ответы на вопросы (видео)
- Yandex Day: 3. Компилятор для процессоров "Эльбрус". Алексей Маркин (видео)
- Yandex Day: 4. Прикладное программирование на Эльбрусе. Антон Аникин (видео)
Примечания
- ↑ поскольку затрагивает и riscv64, и обычно aarch64
- ↑ либо можно задействовать %_libsuff
- ↑ или найти этот фрагмент в уже сгенерированном configure, что несколько сложней
- ↑ или же __amd64__
- ↑ расширения системы команд SSE4.2 и AVX1 в каком-то виде также поддержаны в компиляторе, но, возможно, быстрее не будет
- ↑ в составе lcc1.25-doc или аналогичного пакета на ОС Альт, по пути /opt/mcst/doc/posix_signals.html при установленной системе программирования в Эльбрус Линукс