Я пытаюсь портировать более крупное приложение с x86 на вооружение cortex a9, но я получаю странные ошибки сегментации с функциями с плавающей запятой, такими как modf, при кросс-компиляции приложения, другие функции libc ++, кажется, просто обрабатывают с плавающей точкой неправильно, но не дают сбоя (увидеть ниже).
Поэтому я попробовал эту небольшую тестовую программу, которая также может вызвать ошибку.
Вывод тестовой программы (см. Ниже) должен продемонстрировать мою проблему.
#include <iostream>
int main(int argc, char *argv[])
{
double x = 80;
double y = 0;
std::cout << x << "\t" << y << std::endl;
return 0;
}
составлено на руку кору а9:
@tegra$ g++ -Wall test.cpp -o test_nativ
@tegra$ ./test_nativ
80 0
кросс составлен
@x86$ arm-cortex_a9-linux-gnueabi-g++ test.cpp -o test_cc
@tegra$ ./test_cc
0 1.47895e-309
кросс-компилируется с опцией компоновщика -static.
@x86$ arm-cortex_a9-linux-gnueabi-g++ -static test.cpp -o test_cc_static
@tegra$ ./test_cc_static
80 0
.
@x86$ arm-cortex_a9-linux-gnueabi-objdump -S test_cc
see: http://pastebin.com/3kqHHLgQ
@tegra$ objdump -S test_nativ
see: http://pastebin.com/zK35KL4X
.
Чтобы ответить на некоторые комментарии ниже:
— Кросс-компилятор настроен для little-endian, как и нативный компилятор на машине Tegra.
— Я не верю, что это проблема выравнивания памяти, у меня была их доля при переносе на arm, и они должны были посылать SIGBUS в приложение или регистрироваться в syslog, см. Документацию для / proc / cpu / alignment.
Мой текущий обходной путь — скопировать кросс-скомпилированную цепочку инструментов и использовать ее с LD_LIBRARY_PATH … не очень хорошо, но пока достаточно хорошо.
Редактировать:
Спасибо за ответ.
Тем временем я обнаружил, что дистрибутив linux на устройстве tegra был скомпилирован с помощью ‘-mfloat-abi = softfp’, хотя в документации указано, что требуется цепочка инструментов, скомпилированная с ‘-mfloat-abi = hard’.
Смена набора инструментов принесла успех.
Кажется, что разницу между hard и softfp можно увидеть с помощью ‘readelf -A’ в любом двоичном файле системы:
Если вывод содержит строку: «Tag_ABI_VFP_args: VFP registers», он компилируется с помощью «-mfloat-abi = hard». Если эта строка отсутствует, двоичный файл, скорее всего, компилируется с помощью ‘-mfloat-abi = softfp’.
Строка ‘Tag_ABI_HardFP_use: SP и DP’ не указывает на флаг компилятора ‘-mfloat-abi = hard’.
Глядя на вывод сборки, мы можем увидеть расхождение в двух файлах.
В test_nativ
:
86ec: 4602 mov r2, r0
86ee: 460b mov r3, r1
86f0: f241 0044 movw r0, #4164 ; 0x1044
86f4: f2c0 0001 movt r0, #1
86f8: f7ff ef5c blx 85b4 <_init+0x20>
Это прохождение double
в r2:r3
, а также std::cout
в r0
,
В test_cc
:
86d8: e28f3068 add r3, pc, #104 ; 0x68
86dc: e1c320d0 ldrd r2, [r3]
86e0: e14b21f4 strd r2, [fp, #-20] ; 0xffffffec
86e4: e3010040 movw r0, #4160 ; 0x1040
86e8: e3400001 movt r0, #1
86ec: ed1b0b03 vldr d0, [fp, #-12]
86f0: ebffffa5 bl 858c <_init+0x20>
Это проходит double
в d0
(регистр VFP) и std::cout
в r0
, Обратите внимание, что здесь r2:r3
загружен ( ldrd
) со значением с плавающей запятой, которое выводится вторым, то есть 0,0. Потому что динамически связанный ostream::operator<<(double val)
ожидает своего аргумента в r2:r3
, 0 печатается первым.
Я могу объяснить и второй странный вид поплавка. Вот где напечатано второе число:
8708: e1a03000 mov r3, r0
870c: e1a00003 mov r0, r3
8710: ed1b0b05 vldr d0, [fp, #-20] ; 0xffffffec
8714: ebffff9c bl 858c <_init+0x20>
Видеть, что r3
установлен в r0
Адрес cout
, Сверху, r0 = 0x011040
, Таким образом, регистр пары r2:r3
становится 0x0001104000000000, который декодируется в 1.478946186471156e-309 как двойной.
Таким образом, проблема в том, что библиотеки GCC вашего настольного компьютера используют инструкции VFP / NEON, которые не используются динамическими библиотеками на устройстве. Если вы используете -static
, вы получаете библиотеки VFP / NEON, и все снова работает.
Мое предложение было бы просто выяснить, почему библиотеки устройств и компиляторов различаются, и разобраться с этим.
мой УгадайБез правильных переключателей, указывающих на поддержку аппаратного обеспечения vfp, компилятор будет использовать библиотеки программного обеспечения для выполнения математических операций с плавающей запятой на руке. Если вы компилируете со статической связью, эти библиотеки будут включены в двоичный файл — результат: он работает. Если вы используете нормальный (динамический) режим компоновки, библиотеки не включаются — результат: по какой-то причине он не работает. Библиотеки в вашей системе Tegra каким-то образом несовместимы (вероятно, из-за соглашения о вызовах) с тем, что создает ваш кросс-компилятор.