问题描述
限时送ChatGPT账号..我正在尝试将一个更大的应用程序从 x86 移植到 arm cortex a9,但是我在交叉编译应用程序时遇到了带有浮点函数(如 modf)的奇怪分段错误,其他 libc++ 函数似乎只是错误地处理了浮点数,但不要不会崩溃(见下文).
I am trying to port a larger application from x86 to arm cortex a9, but I'm getting strange segmentation faults with floating point functions like modf when cross compiling the application, other libc++ functions just seem to handle floats wrong, but don't crash(see below).
所以我尝试了这个小测试程序,它也会触发错误.测试程序的输出(见下文)应该说明我的问题.
So I tried this small test programm, which can trigger the error too. The output of the test programm(see below) should demonstrate my problem.
#include <iostream>
int main(int argc, char *argv[])
{
double x = 80;
double y = 0;
std::cout << x << "\t" << y << std::endl;
return 0;
}
在 arm cortex a9 上编译:
compiled on 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"链接器选项交叉编译.
cross compiled with '-static' linker option.
@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/3kqHHLgQ
@tegra$ objdump -S test_nativ
see: http://pastebin/zK35KL4X
.
回答下面的一些评论:
- 交叉编译器是为 little endian 设置的,就像 tegra 机器上的本机编译器一样.
- 我不认为它是内存对齐问题,在移植到 arm 时我有这些问题,这些应该将 SIGBUS 发送到应用程序或记录到系统日志,请参阅/proc/cpu/alignment 的文档.
To answer some of the comments below:
- Cross compiler is setup for little endian, as is the native compiler on the tegra machine.
- I don't believe its a memory alignment issue, had my share of these while porting to arm and these should send SIGBUS to application or log to syslog, see documentation for /proc/cpu/alignment.
我目前的解决方法是复制交叉编译的工具链并将其与 LD_LIBRARY_PATH 一起使用......不太好,但暂时足够了.
感谢您的回答.
与此同时,我发现 tegra 设备上的 linux 发行版是使用-mfloat-abi=softfp"编译的,尽管文档指出,需要使用-mfloat-abi=hard"编译的工具链.
改变工具链带来了成功.
似乎在任何系统二进制文件上使用readelf -A"都可以看出 hardfp 和 softfp 之间的区别:
如果输出包含以下行:Tag_ABI_VFP_args: VFP registers",则使用-mfloat-abi=hard"编译.如果缺少这一行,则二进制文件很可能是用-mfloat-abi=softfp"编译的.
'Tag_ABI_HardFP_use: SP and DP' 行不指示编译器标志 '-mfloat-abi=hard'.
My current workaround is to copy over the crosscompiled toolchain and use it with LD_LIBRARY_PATH ... not nice, but good enough for the time being.
Thank you for your Answers.
In the meantime I found out that the linux distribution on the tegra device was compiled with '-mfloat-abi=softfp' though the documentation stated, that a toolchain compiled with '-mfloat-abi=hard' is required.
Changing the toolchain brought the success.
It seems that the difference between hard and softfp can be seen using 'readelf -A' on any system binary:
If the Output contains the line: 'Tag_ABI_VFP_args: VFP registers' it is compiled with '-mfloat-abi=hard'. If this line is missing the binary is most likely compiled with '-mfloat-abi=softfp'.
The line 'Tag_ABI_HardFP_use: SP and DP' does not indicate the compilerflag '-mfloat-abi=hard'.
推荐答案
查看汇编输出,我们可以看到两个文件存在差异.
Looking at the assembly output, we can see a discrepancy in the two files.
在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
.
This is passing a double
in r2:r3
, and std::cout
in 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>
这会在 d0
(一个 VFP 寄存器)中传递一个 double
,在 r0
中传递一个 std::cout
.在这里观察到 r2:r3
被加载(通过 ldrd
)与第二个打印出来的浮点值,即 0.0.因为动态链接的 ostream::operator<<(double val)
需要 r2:r3
中的参数,所以首先打印出 0.
This passes a double
in d0
(a VFP register), and std::cout
in r0
. Observe here that r2:r3
is loaded (by ldrd
) with the floating point value that is printed out second, i.e. 0.0. Because the dynamically-linked ostream::operator<<(double val)
expects its argument in r2:r3
, 0 is printed out first.
我也可以解释第二个看起来很奇怪的浮动.这是打印第二个浮点数的位置:
I can explain the second weird-looking float too. Here's where the second float is printed:
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 作为双精度值.
See that r3
is set to r0
, the address of cout
. From above, r0 = 0x011040
. Thus, the register pair r2:r3
becomes 0x0001104000000000, which decodes to 1.478946186471156e-309 as a double.
所以问题在于您的桌面 GCC 的库使用 VFP/NEON 指令,而设备上的动态库不使用这些指令.如果您使用 -static
,您将获得 VFP/NEON 库,并且一切正常.
So the problem is that your desktop GCC's libraries uses VFP/NEON instructions, which are not used by the on-device dynamic libraries. If you use -static
, you get the VFP/NEON libraries, and everything works again.
我的建议只是找出设备和编译器库不同的原因,然后解决这个问题.
My suggestion would just be to figure out why the device and compiler libraries differ, and get that sorted out.
这篇关于arm cortex a9交叉编译奇怪的浮点行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
更多推荐
[db:关键词]
发布评论