arm cortex a9 cross compilazione strana comportamento in virgola mobile

Sto provando a eseguire il porting di un’applicazione più grande da x86 a arm cortex a9, ma ricevo strani errori di segmentazione con funzioni in virgola mobile come modf quando cross-compilando l’applicazione, altre funzioni di libc ++ sembrano gestire i float in modo errato, ma non si bloccano (vedi sotto).

Così ho provato questo piccolo programma di test, che può causare anche l’errore. L’output del programma di test (vedi sotto) dovrebbe dimostrare il mio problema.

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

compilato sulla corteccia arm a9:

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

croce compilata

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

cross compilato con l’opzione linker ‘-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 

.

Per rispondere ad alcuni dei commenti seguenti:
– Il compilatore incrociato è configurato per little endian, così come il compilatore nativo sulla macchina tegra.
– Non credo che sia un problema di allineamento della memoria, ho avuto la mia parte di questi durante il porting to arm e questi dovrebbero inviare SIGBUS all’applicazione o accedere a syslog, vedere la documentazione per / proc / cpu / alignment.

La mia soluzione attuale è di copiare la toolchain crosscompiled e usarla con LD_LIBRARY_PATH … non bella, ma abbastanza buona per il momento.

Modificare:
Grazie per le tue risposte.
Nel frattempo ho scoperto che la distribuzione linux sul dispositivo tegra è stata compilata con ‘-mfloat-abi = softfp’ sebbene la documentazione affermasse che è richiesta una toolchain compilata con ‘-mfloat-abi = hard’.
Cambiare la toolchain ha portato il successo.

Sembra che la differenza tra hard e softfp possa essere vista usando ‘readelf -A’ su qualsiasi binario di sistema:
Se l’output contiene la riga: ‘Tag_ABI_VFP_args: registri VFP’ è compilato con ‘-mfloat-abi = hard’. Se manca questa linea, il file binario è molto probabilmente compilato con ‘-mfloat-abi = softfp’.
La riga ‘Tag_ABI_HardFP_use: SP e DP’ non indica il compilatore ‘-mfloat-abi = hard’.

Guardando l’output dell’assieme, possiamo vedere una discrepanza nei due file.

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> 

Questo sta passando un double in r2:r3 e 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> 

Questo passa un double in d0 (un registro VFP) e std::cout in r0 . Osservare qui che r2:r3 è caricato (da ldrd ) con il valore in virgola mobile che viene stampato secondo, ovvero 0.0. Poiché l’ ostream::operator<<(double val) collegato dynamicmente si aspetta il suo argomento in r2:r3 , 0 viene stampato per primo.

Posso spiegare anche il secondo aspetto strano. Ecco dove viene stampato il secondo float:

 8708: e1a03000 mov r3, r0 870c: e1a00003 mov r0, r3 8710: ed1b0b05 vldr d0, [fp, #-20] ; 0xffffffec 8714: ebffff9c bl 858c <_init+0x20> 

Vedi che r3 è impostato su r0 , l'indirizzo di cout . Dall'alto, r0 = 0x011040 . Pertanto, la coppia di registri r2:r3 diventa 0x0001104000000000, che decodifica in 1,478946186471156e-309 come una doppia.

Quindi il problema è che le librerie GCC del tuo desktop usano istruzioni VFP / NEON, che non sono usate dalle librerie dinamiche del dispositivo. Se si utilizza -static , si ottengono le librerie VFP / NEON e tutto funziona di nuovo.

Il mio suggerimento sarebbe solo quello di capire perché il dispositivo e le librerie del compilatore differiscono, e ottenerlo risolto.

La mia ipotesi : senza switch appropriati che indicano il supporto hardware vfp, il compilatore userà le librerie software per fare calcoli matematici in virgola mobile. Se si compila con il collegamento statico, queste librerie verranno incluse nel risultato binario: funziona. Se si utilizza la modalità di collegamento normale (dynamic) le librerie non vengono incluse – risultato: non funziona per qualche motivo. Le librerie sul tuo sistema Tegra sono in qualche modo incompatibili (probabilmente a causa della convenzione di chiamata) con ciò che il tuo crosscompiler sta producendo.