交叉编译Qt 4.7时的“非法指令”

时间:2011-04-11 12:40:32

标签: qt cross-platform arm cross-compiling

我现在已经在这个问题上挣扎了一个多星期了,仍然无法找到解决方案......

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

  • 在i386上构建主机是Debian 5(Etch)(在虚拟PC上运行)
  • 该设备是带有ARM处理器的Trimble Nomad手持设备(see full cpuinfokernel configuration
  • 我使用为设备制作的原始构建工具链,并且迄今工作正常(甚至可以成功构建Gnash) - 请参阅compiler settings and version
  • 我正在使用基于qmake.conf的自定义linux-arm-gnueabi-g++并使用正确的工具链 - see source code here
  • 我通过向编译器标志添加-msoft-float -D__GCC_FLOAT_NOT_NEEDED来获得 部分改进,但我仍然遇到“非法指令”错误一些情况(但至少这是一个很大的改进)
  • 二进制文件本身基本上可以工作,但在某些情况下,程序会因“非法指令”错误而崩溃。我相信这种情况发生在某些浮点运算期间进行图形处理时。
  • 添加-mcpu=xscale-march=armv4-O0-march=armv4-mtune=arm920t(并非所有同时)都没有任何帮助。
  • 使用--debug标记构建Qt似乎可以解决所有问题,但添加-O2标记会重新引入它们。奇怪的是,-O0设置没有 --debug会帮助。
  • 可以看到编译器configuremake输出here。有许多对齐警告但they are said to be false warnings of the compiler
  • 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 
在崩溃前

strace:

$ 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, "\t\n\f\0\367\t", 6)          = 6
write(15, "\0\0+\234\325\343\306{\3\0\0\0\0J\370\377\351\301\336\377"..., 120) = 120
lseek(15, 0, SEEK_END)                  = 17124
write(15, "\10\10\10\0\371\10", 6)      = 6
write(15, "\0\6j\251\260\201\27\0\2\276\377\351\334\377\346\32K\377"..., 64) = 64
lseek(15, 0, SEEK_END)                  = 17194
write(15, "\7\10\10\0\371\7", 6)        = 6
write(15, "\0\4c\245\263\224 \0\1\271\377\367\315\356P\0I\377\364"..., 64) = 64
lseek(15, 0, SEEK_END)                  = 17264
write(15, "\10\n\10\1\366\10", 6)       = 6
write(15, "\37 \3\0\0\0\0\0\374\377\34\0\0\0\0\0\374\377\34\0\0\0"..., 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[?33h\33[?25h\33[?0c\0", 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

我可以尝试下一步的建议吗?

2 个答案:

答案 0 :(得分:4)

posted disassembly非常有趣。

 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 由零异常使能位)不是 设置,所以他们不试图保存FPA 寄存器。然而,它被设置了 发布版本。
  4. 我在这里看到两个选项:

    1. 在没有FPA支持的情况下重建libc
    2. 查找DZE在发布版本中设置的位置(不确定如何操作)

    3. 更新:我错了。 gdb反汇编让我很困惑。我找到了setjmp.S的the source,这是相关的部分:

              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。 然而,这里有一个错误。它使用r2临时存储fpscr,但是,它会先前加载a3中的hwcap值(a3是r2的APCS name)。也许作者意味着使用a2而不是r2,或者这两个部分可能是由不同的人完成的。在任何一种情况下,Qt的发布版本都会以某种方式更改FPSCR(最有可能由内核模拟),并且会触发存储iwmmxt regs的代码。

      不过,这不是整个故事。 hwcaps you pasted声称CPU确实支持iWMMXt,所以我不确定为什么这些指令会给你带来麻烦。也许报告的PC值在某种程度上是错误的。我认为你应该尝试在__sigsetjmp上放置断点并通过指令(stepi)逐步执行它,看看它到底崩溃的位置。

答案 1 :(得分:0)

您好我前几天有过类似的问题......但是我在我的Slackware Linux上运行Qt Creator 5.7的VMware播放器(不是ARM设备)。
安装成功后,我无法启动Qt Creator。我尝试使用以下终端命令/opt/Qt5.7.0/Tools/QtCreator/bin/qtcreator运行Qt Creator并且它给了我一个错误Illegal instruction
在与Google合作几个小时后,我尝试使用此终端命令/opt/Qt5.7.0/Tools/QtCreator/bin/qtcreator -noload Welcome运行Qt Creator,这对我有用。

希望这有助于某人。很抱歉迟到的回复。