arm皮质a9交叉编译奇怪的浮点行为

我试图将一个更大的应用程序从x86移植到arm cortex a9,但是当交叉编译应用程序时,我得到了像modf这样的浮点函数的奇怪分段错误,其他libc ++函数似乎只是处理浮动错误,但不会崩溃(见下文)。

所以我尝试了这个小测试程序,它也可以触发错误。 测试程序的输出(见下文)应该certificate我的问题。

#include  int main(int argc, char *argv[]) { double x = 80; double y = 0; std::cout << x << "\t" << y << std::endl; return 0; } 

编译在arm cortex 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 

使用’-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 

要回答以下一些评论:
– 交叉编译器是为小端设置的,就像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 ,在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为double。

所以问题是您的桌面GCC库使用VFP / NEON指令,这些指令不会被设备上的动态库使用。 如果使用-static ,则会获得VFP / NEON库,一切都可以正常工作。

我的建议只是弄清楚为什么设备和编译器库不同,并将其整理出来。

我的猜测 :如果没有正确的开关指示vfp硬件支持,编译器将使用软件库来进行浮点数学运算。 如果使用静态链接进行编译,这些库将包含在二进制文件中 – 结果:它可以工作。 如果使用普通(动态)链接模式,则不会包含库 – 结果:由于某种原因它不起作用。 tegra系统上的库与您的交叉编译器生成的内容在某种程度上是不兼容的(可能是由于调用约定)。