#qt #cross-platform #arm #cross-compiling
#qt #кроссплатформенность #arm #кросс-компиляция
Вопрос:
Я борюсь с этой проблемой уже больше недели и все еще не могу найти решение…
Я пытаюсь кросс-скомпилировать встроенную версию Qt 4.7 с открытым исходным кодом для устройства ARM. Сам процесс сборки завершается без проблем, но сгенерированные двоичные файлы, похоже, содержат инструкции, которые процессор не понимает.
- Хостом сборки является Debian 5 (Etch) на i386 (запущенный на виртуальном ПК)
- Устройство представляет собой карманный компьютер Trimble Nomad с процессором ARM (смотрите полную информацию о процессоре и конфигурацию ядра)
- Я использую оригинальный набор инструментов сборки, который был создан для устройства и который на сегодняшний день отлично работал (даже смог успешно собрать Gnash) — см. Настройки компилятора и версию
- Я использую пользовательский,
qmake.conf
основанный наlinux-arm-gnueabi-g
и адаптированный для использования правильного набора инструментов — смотрите исходный код здесь - У меня было частичное улучшение, путем добавления
-msoft-float -D__GCC_FLOAT_NOT_NEEDED
к флагам компилятора, но я все еще получаю ошибки «Незаконной инструкции» в некоторых ситуациях (но, по крайней мере, это было большое улучшение) - Сами двоичные файлы в основном работают, но в определенных ситуациях программа вылетает с ошибкой «Незаконная инструкция». Я полагаю, что это происходит во время определенных операций с плавающей запятой при выполнении графических операций.
- Добавление
-mcpu=xscale
,-march=armv4
,-O0
,-march=armv4
,-mtune=arm920t
(не все одновременно) не помогло в любом случае. - Сборка Qt с
--debug
флагом , похоже, решает все проблемы, но добавление-O2
флага повторно вводит их. Как ни странно,-O0
настройка без —debug не помогает. - Компиляцию
configure
иmake
выходные данные можно увидеть здесь. Существует множество предупреждений о выравнивании, но они считаются ложными предупреждениями компилятора. - должно быть, в Qt 4.7.2 произошли какие-то изменения, потому что более ранние версии (4.7.1, 4.7.0) работают нормально.
configure
Настройки:
./configure
-embedded arm
-xplatform qws/linux-arm-angstrom-gnueabi-g
-debug
-no-largefile
-no-multimedia
-no-audio-backend
-no-phonon
-no-phonon-backend
-webkit
-javascript-jit
-no-xshape
-no-xvideo
-no-xsync
-no-xinerama
-no-xcursor
-no-xfixes
-no-xrandr
-no-xrender
-no-xinput
-no-xkb
-no-opengl
-nomake docs
-nomake examples
-nomake tools
-nomake demos
-nomake translations
-opensource
-qt-mouse-tslib
-qt-libjpeg
-qt-gif
выполните настройку перед сбоем:
$ LD_LIBRARY_PATH=. QT_QWS_FONTDIR=$PWD/fonts QT_PLUGIN_PATH=$PWD/plugins QWS_MOUSE_PROTO=tslib:/dev/input/touchscreen0 strace ./digitalclock -qws test.htm
...
lseek(15, 0, SEEK_END) = 16998
write(15, "tnf367t", 6) = 6
write(15, " 234325343306{3J370377351301336377"..., 120) = 120
lseek(15, 0, SEEK_END) = 17124
write(15, "10101037110", 6) = 6
write(15, "6j25126020127227637735133437734632K377"..., 64) = 64
lseek(15, 0, SEEK_END) = 17194
write(15, "710103717", 6) = 6
write(15, "4c245263224 1271377367315356PI377364"..., 64) = 64
lseek(15, 0, SEEK_END) = 17264
write(15, "10n10136610", 6) = 6
write(15, "37 33743773437437734"..., 80) = 80
fcntl64(15, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
lseek(15, 0, SEEK_END) = 17350
mremap(0x415f5000, 16552, 17350, MREMAP_MAYMOVE) = 0x415f5000
--- SIGILL (Illegal instruction) @ 0 (0) ---
rt_sigaction(SIGILL, {SIG_DFL}, {0x401b7d34, [ILL], SA_RESTART|0x4000000}, 8) = 0
socket_subcall(0x1f8004, 0, 0x100, 0, 0, 0x18844, 0x18840, 0x12c) = 0
ioctl(12, KDSKBMODE, 0x2) = 0
ioctl(12, SNDCTL_TMR_START or TCSETS, {B38400 -opost -isig -icanon -echo ...}) = 0
close(12) = 0
ioctl(10, KDSETMODE, 0x1) = 0
write(10, "33[9;15]33[?33h33[?25h33[?0c", 25) = 25
close(10) = 0
statfs64(umovestr: Input/output error
0x6d4f, 27983, {???}) = 0
sigreturn() = ? (mask now [ILL ABRT BUS FPE USR1 SEGV USR2 PIPE STKFLT CHLD CONT STOP TTOU URG XCPU VTALRM PROF WINCH IO PWR RTMIN])
--- SIGILL (Illegal instruction) @ 0 (0) ---
killed by SIGILL
Process 27983 detached
обратная трассировка сбоя в gdb (мне не хватает символов отладки, поскольку компиляция с использованием отладочной информации решает проблему):
(gdb) run -qws
Starting program: /home/.qt-test2/digitalclock -qws
Program received signal SIGILL, Illegal instruction.
0x4130268c in __sigsetjmp () from /lib/libc.so.6
(gdb) bt
#0 0x4130268c in __sigsetjmp () from /lib/libc.so.6
#1 0x4046ee5c in ?? () from ./libQtGui.so.4
(gdb)
Обратите внимание, что устройство поставляется с предустановленной Qtopia 4.3, и поставщик также не может объяснить проблему с моей сборкой.
Обновить
С помощью Игоря Скочинского я смог найти точную инструкцию ассемблера, которая вызывает SIGILL. По какой-то причине инструкция работает нормально 47 раз, прежде чем вызвать ошибку. Смотрите gdb
Вывод ниже (обратите внимание, что я вообще не знаком с ассемблером ARM):
$ LD_LIBRARY_PATH=. QT_QWS_FONTDIR=$PWD/fonts QT_PLUGIN_PATH=$PWD/plugins QWS_MOUSE_PROTO=tslib:/dev/input/touchscreen0 gdb ./digitalclock
GNU gdb 6.6
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "arm-angstrom-linux-gnueabi"...
Using host libthread_db library "/lib/libthread_db.so.1".
(gdb) start -qws
Breakpoint 1 at 0xaa58: file main.cpp, line 47.
Starting program: /home/.qt-test2/digitalclock -qws
[Thread debugging using libthread_db enabled]
[New Thread 1073870720 (LWP 2799)]
[Switching to Thread 1073870720 (LWP 2799)]
main (argc=2, argv=0xbea17d04) at main.cpp:47
47 main.cpp: No such file or directory.
in main.cpp
(gdb) display/i $pc
1: x/i $pc 0xaa58 <main 24>: sub r3, r11, #28 ; 0x1c
(gdb) display/x $r2
2: /x $r2 = 0xbea17d10
(gdb) display/x $f2
3: /x $f2 = 0x0
(gdb) b *0x41302684
Breakpoint 2 at 0x41302684
(gdb) continue
Continuing.
---> no problem here:
Breakpoint 2, 0x41302684 in __sigsetjmp () from /lib/libc.so.6
3: /x $f2 = 0x0
2: /x $r2 = 0x293
1: x/i $pc 0x41302684 <__sigsetjmp 52>: beq 0x413026a0 <Lno_iwmmxt>
(gdb) si
0x41302688 in __sigsetjmp () from /lib/libc.so.6
3: /x $f2 = 0x0
2: /x $r2 = 0x293
1: x/i $pc 0x41302688 <__sigsetjmp 56>: stfp f2, [r12], #8
(gdb) si
0x4130268c in __sigsetjmp () from /lib/libc.so.6
3: /x $f2 = 0x0
2: /x $r2 = 0x293
1: x/i $pc 0x4130268c <__sigsetjmp 60>: stfp f3, [r12], #8
(gdb) si
0x41302690 in __sigsetjmp () from /lib/libc.so.6
3: /x $f2 = 0x0
2: /x $r2 = 0x293
1: x/i $pc 0x41302690 <__sigsetjmp 64>: stfp f4, [r12], #8
(gdb) continue
Continuing.
Breakpoint 2, 0x41302684 in __sigsetjmp () from /lib/libc.so.6
3: /x $f2 = 0x0
2: /x $r2 = 0x293
1: x/i $pc 0x41302684 <__sigsetjmp 52>: beq 0x413026a0 <Lno_iwmmxt>
(gdb) continue 46
Will ignore next 45 crossings of breakpoint 2. Continuing.
---> __sigsetjmp still working fine, but then:
Breakpoint 2, 0x41302684 in __sigsetjmp () from /lib/libc.so.6
3: /x $f2 = 0x0
2: /x $r2 = 0x293
1: x/i $pc 0x41302684 <__sigsetjmp 52>: beq 0x413026a0 <Lno_iwmmxt>
(gdb) si
0x41302688 in __sigsetjmp () from /lib/libc.so.6
3: /x $f2 = 0x0
2: /x $r2 = 0x293
1: x/i $pc 0x41302688 <__sigsetjmp 56>: stfp f2, [r12], #8
(gdb) si
Program received signal SIGILL, Illegal instruction.
0x4130268c in __sigsetjmp () from /lib/libc.so.6
3: /x $f2 = 0x0
2: /x $r2 = 0x293
1: x/i $pc 0x4130268c <__sigsetjmp 60>: stfp f3, [r12], #8
Есть предложения, что я мог бы попробовать дальше?
Комментарии:
1. Вы пробовали дизассемблировать подозрительный код из GDB? Возможно, вам удастся определить инструкцию, которая вызывает проблему. А вы тоже пробовали
-O0 -g
? Если вы воспроизведете проблему с помощью этих параметров, GDB может выдать более полезный результат.2. как мне это сделать? Я не знаком с разборкой..
3. @Udo: в GDB есть
disassemble
команда4. @thkala: Смотрите вывод здесь . вам это о чем-то говорит? Кроме того, в настоящее время я перестраиваю с помощью
-O0 -g
(а не--debug
), как было предложено. Это займет около получаса.5. nvm, смотрите мой ответ ниже
Ответ №1:
Опубликованная разборка довольно интересна.
0x41302678 <__sigsetjmp 40>: fmrx r2, fpscr
0x4130267c <__sigsetjmp 44>: str r2, [r12], #4
0x41302680 <__sigsetjmp 48>: tst r2, #512 ; 0x200
0x41302684 <__sigsetjmp 52>: beq 0x413026a0 <__sigsetjmp 80>
0x41302688 <__sigsetjmp 56>: stfp f2, [r12], #8
*0x4130268c <__sigsetjmp 60>: stfp f3, [r12], #8*
0x41302690 <__sigsetjmp 64>: stfp f4, [r12], #8
0x41302694 <__sigsetjmp 68>: stfp f5, [r12], #8
0x41302698 <__sigsetjmp 72>: stfp f6, [r12], #8
0x4130269c <__sigsetjmp 76>: stfp f7, [r12], #8
Код проверяет наличие бита 9 в fpscr и, если он установлен, пытается сохранить регистры f2-f7. Что это такое? Я никогда не видел их в последних процессорах, но я думаю, что это регистры FPA («Ускоритель с плавающей запятой»), реализованные в нескольких старых ядрах и использовавшиеся для soft FP до появления VFP.
Итак, вот что, я думаю, происходит:
- Libc на вашем устройстве был скомпилирован с поддержкой FPA, вероятно, по ошибке.
- В процессорах FPA бит 9 означал «FPA включен» или что-то подобное
- В отладочной версии Qt бит 9 FPSCR (DZE = Бит включения исключения с делением на ноль) не установлен, поэтому они не пытаются сохранить регистры FPA. Однако он устанавливается в релизной версии.
Я вижу здесь два варианта:
- Перестройте libc без поддержки FPA
- Найдите, где устанавливается DZE в версии выпуска (не уверен, как это сделать)
Обновление: я был неправ. Дизассемблирование gdb сбило меня с толку. Я нашел исходный файл setjmp.S, вот соответствующая часть:
tst a3, #HWCAP_ARM_VFP
beq Lno_vfp
/* Store the VFP registers. */
/* Following instruction is fstmiax ip!, {d8-d15}. */
stc p11, cr8, [r12], #68
/* Store the floating-point status register. */
/* Following instruction is fmrx r2, fpscr. */
mrc p10, 7, r2, cr1, cr0, 0
str r2, [ip], #4
Lno_vfp:
tst a3, #HWCAP_ARM_IWMMXT
beq Lno_iwmmxt
/* Save the call-preserved iWMMXt registers. */
/* Following instructions are wstrd wr10, [ip], #8 (etc.) */
stcl p1, cr10, [r12], #8
stcl p1, cr11, [r12], #8
stcl p1, cr12, [r12], #8
stcl p1, cr13, [r12], #8
stcl p1, cr14, [r12], #8
stcl p1, cr15, [r12], #8
Lno_iwmmxt:
Итак, он пытается сохранить регистры WMMMXT, а не FPA. Однако здесь есть ошибка. Для временного хранения fpscr используется r2, но при этом ov перезаписывает ранее загруженное значение hwcap в a3 (a3 — это имя APCS для r2). Возможно, автор имел в виду использовать a2, а не r2, или, возможно, две части были выполнены разными людьми. В любом случае, каким-то образом релизная версия Qt изменяет FPSCR (который, скорее всего, эмулируется ядром) и запускается код, хранящий правила iwmmxt.
Тем не менее, это не вся история. В hwcaps, которые вы вставили, утверждается, что процессор поддерживает iWMMXt, поэтому я не уверен, почему эти инструкции могут создавать проблемы. Возможно, сообщенное значение PC каким-то образом неверно. Я думаю, вам следует попробовать установить точку останова в __sigsetjmp и выполнить ее пошагово с помощью инструкции (stepi), чтобы увидеть, где именно происходит сбой.
Комментарии:
1. Есть ли способ проверить , подходит libc или нет? Эта тестовая программа работает нормально при компиляции с использованием тех же параметров компилятора (включая
-O2
). И я предполагаю, что для варианта # 2 в исходном коде Qt должен быть какой-то код на ассемблере. Какое выражение я могу использовать grep, чтобы найти потенциально подходящие файлы исходного кода, содержащие asm-код?2. Вот
stepi
выходные данные gdb: pastebin.com/A53Jkh7S Надеюсь, это вам о чем-то говорит… Дайте мне знать, что я могу сделать дальше.3.@Udo: Похоже, что с первого раза все проходит нормально. Давайте посмотрим, сможем ли мы ее запустить. Введите это в gdb:
display/i $pc
display/x $r2
. Затем запустите программу снова, выполните __sigsetjmp (кстати, вы можете использовать ‘si’), но продолжайте, как только достигнете 0x413026a0 (b 0x413026b0
).4. Вот результат того, что вы запросили: pastebin.com/eZ5UXT7Z однако я так и не достиг указанного вами адреса. Вместо этого я не получаю символ при пошаговом выполнении. Вероятно, это потому, что я «случайно» установил пакет glibc *-dbg * (для моего устройства есть репозиторий ipkg ), и это могло что-то изменить. Тем не менее, я все еще получаю «Незаконную инструкцию», и здесь вы можете увидеть обновленный результат предыдущих тестов: pastebin.com/HUWcM6Zn Надеюсь, это все равно даст вам еще несколько подсказок?
5. Hrm, похоже, что в новом glibc адрес отличается. Можете ли вы попробовать продолжить, когда дойдете до этой строки:
0x40013400 <Lno_iwmmxt>: b 0x40012430 <__sigjmp_save>
?
Ответ №2:
Здравствуйте, у меня была похожая проблема несколько дней назад… Но я запускаю Qt Creator 5.7 на моем Slackware Linux в VMware Player (не на устройстве ARM).
После успешной установки я не смог запустить Qt Creator. Я попытался запустить Qt Creator с помощью следующей команды терминала /opt/Qt5.7.0/Tools/QtCreator/bin/qtcreator
, и это выдало мне ошибку Illegal instruction
.
После нескольких часов, проведенных с Google, я попытался запустить Qt Creator с помощью этих команд терминала /opt/Qt5.7.0/Tools/QtCreator/bin/qtcreator -noload Welcome
, и у меня это сработало.
Надеюсь, это кому-то поможет. Извините за поздний ответ.