use*_*210 7 c c++ floating-point arm cross-compiling
我试图将一个更大的应用程序从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;
}
Run Code Online (Sandbox Code Playgroud)
编译在arm cortex a9上:
@tegra$ g++ -Wall test.cpp -o test_nativ
@tegra$ ./test_nativ
80 0
Run Code Online (Sandbox Code Playgroud)
交叉编译
@x86$ arm-cortex_a9-linux-gnueabi-g++ test.cpp -o test_cc
@tegra$ ./test_cc
0 1.47895e-309
Run Code Online (Sandbox Code Playgroud)
使用'-static'链接器选项进行交叉编译.
@x86$ arm-cortex_a9-linux-gnueabi-g++ -static test.cpp -o test_cc_static
@tegra$ ./test_cc_static
80 0
Run Code Online (Sandbox Code Playgroud)
.
@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
Run Code Online (Sandbox Code Playgroud)
.
回答下面的一些评论:
- 交叉编译器是为小端设置的,就像tegra机器上的本机编译器一样.
- 我不相信它的内存对齐问题,在移植到arm时有我的共享,这些应该将SIGBUS发送到应用程序或登录到syslog,请参阅/ proc/cpu/alignment的文档.
我目前的解决方法是复制交叉编译的工具链并将其与LD_LIBRARY_PATH一起使用......不是很好,但暂时还不错.
编辑:
谢谢你的回答.
与此同时,我发现tegra设备上的linux发行版是使用'-mfloat-abi = softfp'编译的,尽管文档说明,需要使用'-mfloat-abi = hard'编译的工具链.
改变工具链带来了成功.
似乎可以在任何系统二进制文件上使用'readelf -A'看到hard和softfp之间的区别:
如果Output包含行:'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>
Run Code Online (Sandbox Code Playgroud)
这是传递一个doublein r2:r3, and std::coutin r0。
在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>
Run Code Online (Sandbox Code Playgroud)
这传递了doublein d0(VFP 寄存器)和std::coutin r0。观察这里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>
Run Code Online (Sandbox Code Playgroud)
请参阅r3设置为r0的地址cout。从上面,r0 = 0x011040。因此,寄存器r2:r3对变为 0x0001104000000000,它解码为双精度数 1.478946186471156e-309。
所以问题是你的桌面 GCC 库使用了 VFP/NEON 指令,而设备上的动态库不使用这些指令。如果您使用-static,您将获得 VFP/NEON 库,并且一切都会恢复正常。
我的建议只是找出设备和编译器库不同的原因,并解决这个问题。