Arm cortex a9 cross compiles weird floating point behavior

I am trying to port a larger application from x86 to arm cortex a9, but I get weird segmentation errors with floating point functions, such as modf when cross compiling the application, other libC ++ functions do not seem to handle float correctly, but don 't crash ( see below).

So, I tried this small test program, which may also cause an error. The result of the test program (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; } 

hand compiled cortex a9:

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

compiled

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

compiled with the '-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:
- The cross-compiler is configured for a small endian, like its own compiler on a tegra machine.
- I do not think that this is a problem with memory alignment, my share in them is when transferring to hand, and they should send SIGBUS to the application or enter syslog, see the documentation for / proc / cpu / alignment.

My current workaround is to copy over a cross-compiled toolchain and use it with LD_LIBRARY_PATH ... not nice, but good enough for now.


in Edit:
Thank you for your responses. In the meantime, I found out that the linux distribution on the tegra device was compiled using "-mfloat-abi = softfp", although the documentation states that a toolbox compiled using "-mfloat-abi = hard" is required.
The change of tool chain brought success.

It seems that the difference between hard and softfp can be seen using "readelf -A" in any system binary:
If Output contains the string: "Tag_ABI_VFP_args: VFP registers", it is compiled with "-mfloat-abi = hard". If this line is missing, the binary is most likely compiled using '-mfloat-abi = softfp'.
The string "Tag_ABI_HardFP_use: SP and DP" does not indicate compilerflag '-mfloat-abi = hard'.

+7
source share
2 answers

Looking at the output of the assembly, we will 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 passes 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 double to d0 (VFP register) and std::cout to r0 . Note that r2:r3 loads (via ldrd ) with a floating point value that prints second, i.e. 0.0. Since the dynamically linked ostream::operator<<(double val) expects its argument in r2:r3 , 0 is output first.

I can explain the second weird floating point view. Here, 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 set to r0 , the address is cout . Above, r0 = 0x011040 . Thus, the pair of registers r2:r3 becomes 0x0001104000000000, which decodes to 1.478946186471156e-309 as double.

Thus, the problem is that your GCC computers on your computer use VFP / NEON instructions that are not used by the dynamic libraries on the device. If you use -static , you get the VFP / NEON libraries, and everything works again.

My suggestion would be to simply find out why the device and compiler libraries are different, and find out that they are sorted.

+4
source

My guess : without the right switches indicating vfp hardware support, the compiler will use software libraries to do floating point math. If you compile static binding, these libraries will be included in the binary result: it works. If you use the normal (dynamic) binding mode, the libraries do not turn on - the result: for some reason, it does not work. The libraries of your tegra system are somehow incompatible (probably due to a call) with what your cross-compiler produces.

0
source

All Articles