手臂皮层a9交叉编译奇怪的浮点行为 [英] arm cortex a9 cross compiling strange floating point behaviour

查看:267
本文介绍了手臂皮层a9交叉编译奇怪的浮点行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

所以我尝试了这个小测试程序,它也会触发错误。
测试程序的输出结果(见下面)应该证明我的问题。

pre $ #include< iostream>
int main(int argc,char * argv [])
{
double x = 80;
double y = 0;
std :: cout<< x<< \t<< y<的std :: ENDL;
返回0;
}

在arm cortex a9编译:

  @ tegra $ g ++ -Wall test.cpp -o test_nativ 
@ tegra $ ./test_nativ
80 0

$ b

交叉编译
$ b $

  @ 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 
请参阅:http://pastebin.com/3kqHHLgQ

@ tegra $ objdump -S test_nativ
请参阅:http://pastebin.com/zK35KL4X



回答下面的一些评论:

- 交叉编译器设置为小端,就像本地编译器o一样在Tegra机器上。
- 我不相信它是一个内存对齐问题,当我移植到这些应用程序时,这些应该发送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 < code $:b
$ b $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ b 86f0:f241 0044 movw r0,#4164; 0x1044
86f4:f2c0 0001 movt r0,#1
86f8:f7ff ef5c blx 85b4< _init + 0x20>

在<$中传递 double r0 中的c $ c> r2:r3 和 std :: cout / p>

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>

在<$ c中传递 double $ c $ d> c code>(一个VFP寄存器)和 std :: cout 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>

看到 r3 被设置为 r0 cout 的地址。从上面, r0 = 0x011040 。因此,寄存器对 r2:r3 变成0x0001104000000000,它以double的形式解码为1.478946186471156e-309。

所以问题在于你的桌面GCC的库使用VFP / NEON指令,而这些指令并没有被设备上的动态库所使用。如果你使用 -static ,你可以得到VFP / NEON库,一切都可以正常运行。



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


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;
}

compiled on arm cortex a9:

@tegra$ g++ -Wall test.cpp -o test_nativ
@tegra$ ./test_nativ 
80      0

cross compiled

@x86$ arm-cortex_a9-linux-gnueabi-g++ test.cpp  -o test_cc
@tegra$ ./test_cc
0       1.47895e-309

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.com/3kqHHLgQ

@tegra$ objdump -S test_nativ
see: http://pastebin.com/zK35KL4X

.

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.

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.




Edit:
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.

In 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>

This is passing a double in r2:r3, and std::cout in r0.

In 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>

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>

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.

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.

这篇关于手臂皮层a9交叉编译奇怪的浮点行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆