ilyakurdyukov / e2k-ports

Performance patches and build fixes for Elbrus 2000 (e2k) architecture.
44 stars 5 forks source link

libffi - а как это вообще работает? #2

Open DuratarskeyK opened 2 years ago

DuratarskeyK commented 2 years ago

2 момента:

  1. https://github.com/ilyakurdyukov/e2k-ports/blob/main/libffi-3.4.2-e2k.patch#L128 - выделяем на стэке память и сразу выходим за границы куда-то ниже(?) по стэку. По логике у нас там как раз regs_t ret, но так ли это на самом деле? Нельзя выделить память под sizeof(regs_t) + 8 байт?
  2. https://github.com/ilyakurdyukov/e2k-ports/blob/main/libffi-3.4.2-e2k.patch#L128 - что вообще происходит при конвертации указателя на функцию, которая ничего не возвращает и никаких аргуметов не принимает, в функцию, которая возвращает указатель на структуру и принимает его же. По стандарту так вроде делать вообще нельзя, но возможно lcc это проглатывает? Просто при сборке с оптимизациями это иногда падает с SIGILL на https://github.com/ilyakurdyukov/e2k-ports/blob/main/libffi-3.4.2-e2k.patch#L180 , видимо что-то портится на стэке во время вызова самой функции. Без оптимизаций падений не замечено.
ilyakurdyukov commented 2 years ago
  1. (long*)alloca(asize) - ARG_REGS Для вызова функции компилятор добавит дополнительные 64 байта аллокации стека от себя (которые не будет никак использовать).
  2. Это не указатель на структуру, а буквально структура из 64 байт. А по сути просто сохранение первых 8-ми регистров.

Я знаю почему может падать, это из-за спекулятивных операций в вызываемой функции, которые помечают регистры как недоступные, и когда они сохраняются в этом месте, то выпадет SIGILL если такие были. Надо подумать, как такое решить. Точно можно решить через проверку rsize на блоки по 4 байта и сделать некрасивый switch на 16 вариантов вызовов (возможно меньше, если структуры выравниваются по 8).

ilyakurdyukov commented 2 years ago

Можно попробовать сделать так, главное чтобы компилятор не сохранил ret на стек перед switch, а держал на регистрах как получил из функции. Если структура больше 64 байт, то она сразу на стеке сохраняется и на регистрах не передаётся.


  ret = (*(regs_t(*)(regs_t))fn)(*(regs_t*)frame);

#define COPY4(i) *(int*)(frame + i) = ret.r[i];
#define COPY8(i) frame[i] = ret.r[i];
#define COPY16(i) COPY8(i) COPY8(i+1)
#define COPY32(i) COPY16(i) COPY16(i+2)

  if (rvalue)
    {
      switch((rsize + 3) >> 2)
        {
        case 1: COPY4(0) break;
        case 2: COPY8(0) break;
        case 3: COPY8(0) COPY4(1) break;
        case 4: COPY16(0) break;
        case 5: COPY16(0) COPY4(2) break;
        case 6: COPY16(0) COPY8(2) break;
        case 7: COPY16(0) COPY8(2) COPY4(3) break;
        case 8: COPY32(0) break;
        case 9: COPY32(0) COPY4(4) break;
        case 10: COPY32(0) COPY8(4) break;
        case 11: COPY32(0) COPY8(4) COPY4(5) break;
        case 12: COPY32(0) COPY16(4) break;
        case 13: COPY32(0) COPY16(4) COPY4(6) break;
        case 14: COPY32(0) COPY16(4) COPY8(6) break;
        case 15: COPY32(0) COPY16(4) COPY8(6) COPY4(7) break;
        case 16: COPY32(0) COPY32(4) break;
        }
      memcpy(rvalue, frame, rsize);
    }
ilyakurdyukov commented 2 years ago

что вообще происходит при конвертации указателя на функцию, которая ничего не возвращает и никаких аргуметов не принимает, в функцию, которая возвращает указатель на структуру и принимает его же.

Первые аргументы передаются на 8-ми регистрах, это просто значит что компилятор инициализирует данные регистры из этой структуры. Тут тонкая игра на том, что компилятор должен правильно это скомпилировать (поэтому важно запускать тесты от libffi для проверки), но видимо ситуация с SIGILL проходит мимо тестов.

ilyakurdyukov commented 2 years ago

Обновил патч, грануляцию по 4 байта невозможно реализовать на Си, но она и не нужна, потому что возвращаемый результат расширяется компилятором до целого регистра.

DuratarskeyK commented 2 years ago

Хм, фикс похоже не помог, потому что падает там же, где и раньше. В оригинальном патче МЦСТ вроде часть вызова функции на ассемблере написана и она вроде рабочая, а вот касты указателей на функцию из одного типа в другой кажется сломаным. Пример нерабочего - blivet из питона для анаконды например или webkit minibrowser.

ilyakurdyukov commented 2 years ago

Еще про ffi_closure_e2k() забыл, там с приходящими регистрами нужно так же делать.

ilyakurdyukov commented 2 years ago

Обновил патч, сделал то же самое для ffi_closure, судя по ассемблеру компилятор сделал как надо.

ilyakurdyukov commented 2 years ago

Нет, на тестах питона падает, похоже нужна инструкция спекулятивного сохранения в память, даже сохранение находится под условным выполнением и условие не выполнено.

ilyakurdyukov commented 2 years ago

Проблему с "грязными" значениями из спекулятивных вычислений решил, патч обновил.

fedya commented 2 years ago

libffi так и не работает нормально Пробую с libffi-3.3 и патчем отсюда ловлю сегфолт у anaconda

Anaconda received signal 04!.
/usr/lib64/python3.8/site-packages/pyanaconda/_isys.so(+0x1a50)[0x4623c0525a50]
<signal handler called>
/usr/lib64/libffi.so.7(ffi_call+0x708)[0x4623bee9e370]
/usr/lib64/python3.8/site-packages/gi/_gi.cpython-38.so(+0x8e898)[0x4623be93e898]
/usr/lib64/python3.8/site-packages/gi/_gi.cpython-38.so(+0x55f38)[0x4623be905f38]
/usr/lib64/libpython3.8.so.1.0(_PyObject_MakeTpCall+0x480)[0x4623afe517e8]
/usr/lib64/libpython3.8.so.1.0(+0x443928)[0x4623b019a928]
/usr/lib64/libpython3.8.so.1.0(_PyEval_EvalFrameDefault+0x176d0)[0x4623b018f4b0]
/usr/lib64/libpython3.8.so.1.0(PyEval_EvalFrameEx+0x90)[0x4623b0177dc8]
/usr/lib64/libpython3.8.so.1.0(_PyFunction_Vectorcall+0x820)[0x4623afe53740]
/usr/lib64/libpython3.8.so.1.0(+0x444148)[0x4623b019b148]
/usr/lib64/libpython3.8.so.1.0(_PyEval_EvalFrameDefault+0x17730)[0x4623b018f510]
/usr/lib64/libpython3.8.so.1.0(PyEval_EvalFrameEx+0x90)[0x4623b0177dc8]
/usr/lib64/libpython3.8.so.1.0(_PyEval_EvalCodeWithName+0x17f0)[0x4623b0196b00]
/usr/lib64/libpython3.8.so.1.0(+0x444148)[0x4623b019b148]
/usr/lib64/libpython3.8.so.1.0(_PyEval_EvalFrameDefault+0x17730)[0x4623b018f510]
/usr/lib64/libpython3.8.so.1.0(PyEval_EvalFrameEx+0x90)[0x4623b0177dc8]
/usr/lib64/libpython3.8.so.1.0(_PyFunction_Vectorcall+0x820)[0x4623afe53740]
/usr/lib64/libpython3.8.so.1.0(+0x444148)[0x4623b019b148]
/usr/lib64/libpython3.8.so.1.0(_PyEval_EvalFrameDefault+0x17730)[0x4623b018f510]
ilyakurdyukov commented 2 years ago

Пишите что-ли версию компилятора и опции компиляции, и работает ли с либой пропатченной МЦСТ (если у вас есть доступ). Запускали ли тесты в самом libffi после сборки.

fedya commented 2 years ago

Лог сборки, тут есть и флаги и оции сборки https://file-store.rosalinux.ru/api/v1/file_stores/9238cbe3eefe30d13f81515c152624711014b3e3.log?show=true

версия компилятора 1.25.24 спек https://abf.io/import/libffi/blob/rosa2021.1/libffi.spec

ilyakurdyukov commented 2 years ago

--without check

Добавьте проверку в спек, в Альте сделано так:

%check
[ -w /dev/ptmx -a -f /proc/self/maps ] || exit
make -k check
fedya commented 2 years ago

Тесты падают вот таким образом.

                === libffi tests ===

Schedule of variations:
    unix

Running target unix
Using /usr/share/dejagnu/baseboards/unix.exp as board description file for target.
Using /usr/share/dejagnu/config/unix.exp as generic interface file for target.
Using ../../testsuite/config/default.exp as tool-and-target-specific interface file.
Running ../../testsuite/libffi.bhaible/bhaible.exp ...
FAIL: libffi.bhaible/test-callback.c -W -Wall -Wno-psabi -DDGTEST=10 -Wno-unused-variable -Wno-unused-parameter -Wno-unused-but-set-variable -Wno-uninitialized -O2 (test for excess errors)

WARNING: program timed out
FAIL: libffi.bhaible/test-callback.c -W -Wall -Wno-psabi -DDGTEST=11 -Wno-unused-variable -Wno-unused-parameter -Wno-unused-but-set-variable -Wno-uninitialized -O2 (test for excess errors)

Running ../../testsuite/libffi.call/call.exp ...
Running ../../testsuite/libffi.closures/closure.exp ...
ERROR: tcl error sourcing ../../testsuite/libffi.closures/closure.exp.
ERROR: tcl error code NONE
ERROR: lcc: error: no input files
    while executing
"exec $compiler --print-multi-lib"
    (procedure "get_multilibs" line 62)
    invoked from within
"get_multilibs"
    (procedure "g++_include_flags" line 9)
    invoked from within
"g++_include_flags"
    (procedure "default_target_compile" line 58)
    invoked from within
"default_target_compile $source $destfile $type $options"
    (procedure "target_compile" line 6)
    invoked from within
"target_compile $source $dest $type $options"
    (procedure "libffi_target_compile" line 62)
    invoked from within
"libffi_target_compile "$prog" "$output_file" "$compile_type" $options"
    (procedure "libffi-dg-test-1" line 52)
    invoked from within
"libffi-dg-test-1 target_compile $prog $do_what $extra_tool_flags"
    (procedure "libffi-dg-test" line 2)
    invoked from within
"${tool}-dg-test $prog [lindex ${dg-do-what} 0] "$tool_flags ${dg-extra-tool-flags}""
    (procedure "saved-dg-test" line 112)
    invoked from within
"saved-dg-test ../../testsuite/libffi.closures/unwindtest.cc {-W -Wall -Wno-psabi -O0} {}"
    ("eval" body line 1)
    invoked from within
"eval saved-dg-test $args "
    (procedure "dg-test" line 6)
    invoked from within
"dg-test $test $options """
    (procedure "run-many-tests" line 63)
    invoked from within
"run-many-tests $tlist  $additional_options"
    (file "../../testsuite/libffi.closures/closure.exp" line 55)
    invoked from within
"source ../../testsuite/libffi.closures/closure.exp"
    ("uplevel" body line 1)
    invoked from within
"uplevel #0 source ../../testsuite/libffi.closures/closure.exp"
    invoked from within
"catch "uplevel #0 source $test_file_name" msg"
Running ../../testsuite/libffi.complex/complex.exp ...
Running ../../testsuite/libffi.go/go.exp ...

                === libffi Summary ===

# of expected passes            1534
# of unexpected failures        2
# of unresolved testcases       3
# of unsupported tests          1
ERROR: -------------------------------------------
ERROR: in testcase ../../testsuite/libffi.closures/closure.exp
ERROR:  lcc: error: no input files
ERROR:  tcl error code NONE
ERROR:  tcl error info:
lcc: error: no input files
    while executing
"exec $compiler --print-multi-lib"
    (procedure "get_multilibs" line 62)
    invoked from within
"get_multilibs"
    (procedure "g++_include_flags" line 9)
    invoked from within
"g++_include_flags"
    (procedure "default_target_compile" line 58)
    invoked from within
"default_target_compile $source $destfile $type $options"
    (procedure "target_compile" line 6)
    invoked from within
"target_compile $source $dest $type $options"
    (procedure "libffi_target_compile" line 62)
    invoked from within
"libffi_target_compile "$prog" "$output_file" "$compile_type" $options"
    (procedure "libffi-dg-test-1" line 52)
    invoked from within
"libffi-dg-test-1 target_compile $prog $do_what $extra_tool_flags"
    (procedure "libffi-dg-test" line 2)
    invoked from within
"${tool}-dg-test $prog [lindex ${dg-do-what} 0] "$tool_flags ${dg-extra-tool-flags}""
    (procedure "saved-dg-test" line 112)
    invoked from within
"saved-dg-test ../../testsuite/libffi.closures/unwindtest.cc {-W -Wall -Wno-psabi -O0} {}"
    ("eval" body line 1)
    invoked from within
"eval saved-dg-test $args "
    (procedure "dg-test" line 6)
    invoked from within
"dg-test $test $options """
    (procedure "run-many-tests" line 63)
    invoked from within
"run-many-tests $tlist  $additional_options"
    (file "../../testsuite/libffi.closures/closure.exp" line 55)
    invoked from within
"source ../../testsuite/libffi.closures/closure.exp"
    ("uplevel" body line 1)
    invoked from within
"uplevel #0 source ../../testsuite/libffi.closures/closure.exp"
    invoked from within
"catch "uplevel #0 source $test_file_name" msg"
--------------------------------------------------
make[3]: *** [Makefile:452: check-DEJAGNU] Error 1
make[3]: Leaving directory '/root/libffi/BUILD/libffi-3.3/e2kv4-rosa-linux-gnu/testsuite'
make[2]: *** [Makefile:528: check-am] Error 2
make[2]: Target 'check' not remade because of errors.
make[2]: Leaving directory '/root/libffi/BUILD/libffi-3.3/e2kv4-rosa-linux-gnu/testsuite'
Making check in man
make[2]: Entering directory '/root/libffi/BUILD/libffi-3.3/e2kv4-rosa-linux-gnu/man'
make[2]: Nothing to be done for 'check'.
make[2]: Leaving directory '/root/libffi/BUILD/libffi-3.3/e2kv4-rosa-linux-gnu/man'
Making check in doc
make[2]: Entering directory '/root/libffi/BUILD/libffi-3.3/e2kv4-rosa-linux-gnu/doc'
make[2]: Nothing to be done for 'check'.
make[2]: Leaving directory '/root/libffi/BUILD/libffi-3.3/e2kv4-rosa-linux-gnu/doc'
make[2]: Entering directory '/root/libffi/BUILD/libffi-3.3/e2kv4-rosa-linux-gnu'
make[2]: Leaving directory '/root/libffi/BUILD/libffi-3.3/e2kv4-rosa-linux-gnu'
make[1]: *** [Makefile:1344: check-recursive] Error 1
make[1]: Target 'check' not remade because of errors.
make[1]: Leaving directory '/root/libffi/BUILD/libffi-3.3/e2kv4-rosa-linux-gnu'
make: *** [Makefile:2990: check] Error 2
error: Bad exit status from /var/tmp/rpm-tmp.uIVNn7 (%check)

Я так понимаю по большей части make check отрабатывает нормально и ничего интересного тут нет, однако анаконда всегда сегфолтится.

ilyakurdyukov commented 2 years ago

Может каких-то пакетов не хватает для сборки с проверкой, вроде С++ компилятора.

testsuite/libffi.closures содержит два С++ теста.

Также из спеки Альта:

%{?!_without_check:%{?!_disable_check:BuildRequires: dejagnu, gcc-c++, /proc, /dev/pts}}
%configure --disable-exec-static-tramp

Что один из тестов завис нехорошо.

Есть ли в логах ошибки какое-то указание какую функцию вызывает pyanaconda через FFI?

fedya commented 2 years ago

%configure --disable-exec-static-tramp Я спек альта смотрю тут https://packages.altlinux.org/ru/sisyphus_e2k/srpms/libffi/specfiles/ и там этой опции нет

Вот еще наблюдение я взял libffi_3.3-vd7_e2k-8c.deb из PDK 7.2 и подложил бинарники и все запустилось как надо. Однако в самом pdk патчей никаких в дире с libffi нет /libffi-3.3

-rw-r--r--@ 1 fdrt  staff    37B  4 авг 16:53 atom.conf
-rw-r--r--@ 1 fdrt  staff   1,2K 17 авг 16:59 libffi.build
-rw-r--r--@ 1 fdrt  staff    93B  4 авг 16:53 meta.txt
-rw-r--r--@ 1 fdrt  staff   120B 17 авг 16:59 x86.sh

опции сборки тоже не хитрые

src_config() {
    autoconf
    econf \
        --enable-debug \
        --libdir="/usr/lib${addP}"
}

Подозреваю что в PDK забыли положить патчей

по остальным пунктам что не хватает чего типа с++ всего хватает.

ilyakurdyukov commented 2 years ago

и там этой опции нет

Это в старом спеке нет, который для 3.2 с патчами от МЦСТ (закрытыми под NDA).

Подозреваю что в PDK забыли положить патчей

Не положили потому что у них патчи закрытые, надо требовать и долго ждать пока выложат и если выложат когда-то. Я пытаюсь делать опенсорсные, но секретных знаний иногда не хватает. Если бы я знал что там вызывается через FFI, было бы понятнее как исправить.

Можете через gdb попробовать понять в каком месте падает.

fedya commented 2 years ago

А вот с gdb большой вопрос я не понимаю как туда пропихнуть gdb чтобы выяснить что за падение происходит подробнее а corefile который генерится получается кривой

[New LWP 1578156]
[New LWP 1578201]
.reg section in corefile is damaged
.reg section in corefile is damaged

в результате не понятно как вытащит хороший трейс

fedya commented 2 years ago

А можете выложить libffi.so* собранные на альте 3.3 версии Хочу проверить с этими либами запустится ли

ilyakurdyukov commented 2 years ago

Я заметил, что ffi_call вызывают используя для результата тип ffi_arg, равный по размеру 8 байт. И я написал код, что сохраняет в него ровно столько, сколько возвращается, например 1 байт для char. Но код для x86_64 расширяет числа до 8 байт. И если код для вызова FFI написан так, что вызываемая функция возвращает менее 8 байт, а использует все 8, то будет работать не правильно. Но тесты такого не проверяют.

Код из теста, для примера:

    ffi_arg result;
    ffi_call(&cif, FFI_FN(doit), &result, values);
    printf ("The result is %d\n", (int)result);
ilyakurdyukov commented 2 years ago

Где исходники вашего pyanaconda? У них код слишком меняется в isys, я нашел две версии со значительными различиями.

fedya commented 2 years ago

git: https://abf.io/import/anaconda бранч rosa2021.1

srpm: http://abf-downloads.rosalinux.ru/rosa2021.1/container/4105557/SRPMS/main/release/anaconda-34.25.0.10-1.47.src.rpm

rpms: http://abf-downloads.rosalinux.ru/rosa2021.1/container/4105557/e2kv4/main/release/

файл /usr/lib64/python3.8/site-packages/pyanaconda/_isys.so внутри пакета anaconda-core

fedya commented 2 years ago

мне тут говорят что в альте актуальная версия для e2k libffi6-3.2.1-alt3.E2K.1.e2kv5.rpm то есть все та же 3.2.1 с major 6

ilyakurdyukov commented 2 years ago

мне тут говорят что в альте актуальная версия для e2k libffi6-3.2.1-alt3.E2K.1.e2kv5.rpm то есть все та же 3.2.1 с major 6

Для Эльбруса (и для большинства архитектур) не существует такого пакета, только для riscv64 и mipsel:

https://packages.altlinux.org/ru/sisyphus_mipsel/srpms/libffi6/specfiles/

И я не знаю зачем он вообще создан, для этих архитектур это старая версия, а не актуальная.

ilyakurdyukov commented 2 years ago

Лучше дайте мне свой libffi собранный с патчем, я дизассемблирую и посмотрю это место:

/usr/lib64/libffi.so.7(ffi_call+0x708)[0x4623bee9e370]

ilyakurdyukov commented 2 years ago

Я обновил патч на основе моих предположений что это могло быть.

Одно из предположений неверное, второе с расширением целых чисел - вряд ли влияет, так что наверное будет падать так же. Мне надо стектрейс падения и библиотеку от одной и той же компиляции библиотеки.

fedya commented 2 years ago

либа в рпм http://abf-downloads.rosalinux.ru/rosa2021.1/repository/e2kv4/main/release/lib64ffi7-3.3-3-rosa2021.1.e2kv4.rpm

Обновленный патч сейчас наложу и попробую запустить.

Попробовал, не помогло

Anaconda received signal 04!.
/usr/lib64/python3.8/site-packages/pyanaconda/_isys.so(+0x1a50)[0x4618a6617a50]
<signal handler called>
/usr/lib64/libffi.so.7(ffi_call+0x718)[0x4618a4f807c0]
/usr/lib64/python3.8/site-packages/gi/_gi.cpython-38.so(+0x8e898)[0x4618a4a0b898]
/usr/lib64/python3.8/site-packages/gi/_gi.cpython-38.so(+0x55f38)[0x4618a49d2f38]
/usr/lib64/libpython3.8.so.1.0(_PyObject_MakeTpCall+0x480)[0x461895ef77f8]
/usr/lib64/libpython3.8.so.1.0(+0x443938)[0x461896240938]

На всякий случай вот еще работающей libffi.so.7 от м ц с т https://file-store.rosalinux.ru/download/3ba89c8dd1e48ed8a36b57e0ee8e13149082482e от него если либу подложить то все ок

ilyakurdyukov commented 2 years ago

Место падения выглядит странно, это сохранение в стек возвращаемого значения после вызова функции.

Указатель неправильным быть не может, значит возвращаемое значение было спекулятивным с тегом указывающим ошибку. Что может случиться когда вызывают функцию что не возвращает аргументов, и от неё приходит какой-то мусор.

Да, с кодом МЦСТ это будет работать, потому что они сохраняют возврат инструкцией что не кидает ошибку на тегах указывающих ошибку.

Я сейчас переписал кусок ffi_call на ассемблер и тестирую такую версию. В такой ситуации это должно работать так же как в коде МЦСТ. Вот только тут может баг в anaconda.

fedya commented 2 years ago

Можно мне патч? Я быстро протестирую.

ilyakurdyukov commented 2 years ago

Вот предварительный патч https://pastebin.com/FSPBatTw Тесты libffi проходит, тоже проверяйте сначала на них.

fedya commented 2 years ago

А помогло!

Please make a selection from the above ['c' to continue, 'q' to quit, 'r' to
refresh]: 2
================================================================================
================================================================================
Installation

1) [x] Language settings                 2) [x] Time settings
       (English (United States))                (Europe/Moscow timezone)
3) [!] Installation Destination          4) [ ] Network configuration
       (Processing...)                          (No network devices available)
5) [x] Root password                     6) [!] User creation
       (Root account is disabled.)              (No user will be created)

Please make a selection from the above ['b' to begin installation, 'h' to help,
'q' to quit, 'r' to refresh]:
An unknown error has occured, look at the /tmp/anaconda-tb* file(s) for more details
ilyakurdyukov commented 2 years ago

Пару макросов переименовал и закоммитил этот патч.

fedya commented 2 years ago

А можешь дать свой тг? У меня есть кое-что, что тут выложить не могу.

ilyakurdyukov commented 2 years ago

Почта в патче написана, если "тг" означает Телеграм, то там меня нет и не будет.