交叉编译Qt 4.7时的"Illegal instruction"



这个问题我已经纠结了一个多星期了,但仍然找不到解决办法…

我正在尝试交叉编译Qt 4.7嵌入式开源版本的ARM设备。构建过程本身没有问题,但是生成的二进制文件似乎包含处理器不理解的指令。

  • 在i386上安装Debian 5 (Etch)(在虚拟PC上运行)
  • 设备是带有ARM处理器的Trimble Nomad手持设备(参见完整的cpuinfo和内核配置)
  • 我使用为设备制作的原始构建工具链,并且迄今为止工作良好(甚至可以成功构建Gnash) -参见编译器设置和版本
  • 我使用基于linux-arm-gnueabi-g++的自定义qmake.conf,并适应使用正确的工具链-参见源代码在这里
  • 我有一个部分改进通过将-msoft-float -D__GCC_FLOAT_NOT_NEEDED添加到编译器标志,但我仍然得到"非法指令"错误在一些情况(但至少这是一个很大的改进)
  • 二进制文件本身基本工作,但在某些情况下,程序崩溃与"非法指令"错误。我相信这发生在某些浮点操作时,而做图形的东西。
  • 添加-mcpu=xscale, -march=armv4, -O0, -march=armv4, -mtune=arm920t(不是同时添加)没有任何帮助。
  • --debug标志构建Qt似乎解决了所有问题,但添加-O2标志重新引入了它们。奇怪的是,-O0设置没有——debug, 没有帮助。
  • configuremake的编译输出可以在这里看到。有很多对齐警告,但它们被认为是编译器的错误警告。
  • Qt 4.7.2一定有一些变化,因为早期版本(4.7.1,4.7.0)运行良好。

configure settings:

  ./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,供应商也无法解释我的构建中的问题。


<标题> 更新在Igor Skochinsky的帮助下,我可以找到导致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

有什么建议我下一步可以尝试吗?

张贴的反汇编相当有趣。

 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

代码检查fpscr中的位9,如果设置,则尝试保存寄存器f2-f7。那些是什么?我从未在最近的处理器中见过它们,但我认为这些是FPA("浮点加速器")寄存器,在一些旧内核中实现,在VFP出现之前用于软FP。

所以,这是我认为会发生的:

  1. 设备上的libc已编译有FPA的支持,可能是错误。
  2. 在FPA处理器位9意思是"FPA启用"之类的类似
  3. 在Qt的调试版本中FPSCR的第9位(DZE = Division)by Zero例外启用位)不是所以他们不会试图挽救FPA寄存器。然而,它被设定了发布版本。

这里有两个选项:

    在不支持FPA的情况下重建libc
  1. 找到DZE在发布版本中设置的位置(不确定如何做到这一点)

Update:我错了。gdb的反汇编使我感到困惑。我找到了麻烦的根源。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:

所以,它试图存储WMMXt寄存器,而不是FPA。但是这里有一个bug。它使用r2来临时存储fpscr, 覆盖a3中先前加载的hwcap值(a3是r2的APCS名称)。也许作者想用a2,而不是r2,或者这两部分是由不同的人完成的。无论哪种情况,Qt的发布版本都会改变FPSCR(这很可能是由内核模拟的),并且会触发存储iwmmxt regs的代码。

不过,这还不是故事的全部。您粘贴的hwcaps声明CPU不支持iWMMXt,所以我不确定为什么这些指令会带来麻烦。也许报告的PC值是错误的。我认为你应该尝试在__sigsetjmp上设置断点,并通过指令(stepi)逐步执行它,看看它到底在哪里崩溃。

你好,几天前我有类似的问题…但是我在VMware播放器(不是ARM设备)的Slackware Linux上运行Qt Creator 5.7。安装成功后,我无法启动Qt Creator。我试着用下面的终端命令/opt/Qt5.7.0/Tools/QtCreator/bin/qtcreator运行Qt Creator,它给了我一个错误Illegal instruction。在谷歌呆了几个小时后,我试着用这个终端命令/opt/Qt5.7.0/Tools/QtCreator/bin/qtcreator -noload Welcome运行Qt Creator,这对我很有效。

希望这能帮助到别人。抱歉回复晚了

相关内容

最新更新