手臂皮层a9交叉编译奇怪的浮点行为

我试图将一个更大的应用程序从x86移植到arm 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;
}

编译在手臂皮层a9:

@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

用'静态'链接器选项交叉编译。

@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一起使用...并不好,但暂时足够了。




编辑:
谢谢您的回答。
与此同时,我发现tegra设备上的linux发行版是用'-mfloat-abi = softfp'编译的,虽然文档说明了,需要用'-mfloat-abi = hard'编译的工具链。
改变工具链带来了成功。

似乎可以在任何系统二进制文件中使用'readelf -A'来看到hard和softfp之间的区别:
如果输出包含以下行:'Tag_ABI_VFP_args:VFP寄存器',则使用'-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>

这是在r2:r3传递一个double r2:r3 ,并在r0传递std::cout

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>

这在d0 (一个VFP寄存器)中传递一个double ,并在r0传递std::cout 。 在这里观察到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系统上的库在某种程度上与您的交叉编译器生产的不兼容(可能是由于调用约定)。

链接地址: http://www.djcxy.com/p/64465.html

上一篇: arm cortex a9 cross compiling strange floating point behaviour

下一篇: @Transactional(readOnly = true) leads to LazyInitializationException