[英]ARM Cortex-A8: different assembly output from cross compiler when using simple floating-point multiplication
[英]arm cortex a9 cross compiling strange floating point behaviour
我試圖將一個更大的應用程序從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;
}
編譯在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'鏈接器選項進行交叉編譯。
@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
。
要回答以下一些評論:
- 交叉編譯器是為小端設置的,就像tegra機器上的本機編譯器一樣。
- 我不相信它的內存對齊問題,在移植到arm時有我的共享,這些應該將SIGBUS發送到應用程序或登錄到syslog,請參閱/ proc / cpu / alignment的文檔。
我目前的解決方法是復制交叉編譯的工具鏈並將其與LD_LIBRARY_PATH一起使用......不是很好,但暫時還不錯。
編輯:
謝謝您的回答。
與此同時,我發現tegra設備上的linux發行版是使用'-mfloat-abi = softfp'編譯的,盡管文檔說明,需要使用'-mfloat-abi = hard'編譯的工具鏈。
改變工具鏈帶來了成功。
似乎在任何系統二進制文件上使用'readelf -A'可以看出hard和softfp之間的區別:
如果輸出包含行:'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>
這是在r2:r3
傳遞一個double
,在r0
傳遞std::cout
。
在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。
我也可以解釋第二個奇怪的浮動。 這是打印第二個浮點數的位置:
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為double。
所以問題是您的桌面GCC庫使用VFP / NEON指令,這些指令不會被設備上的動態庫使用。 如果使用-static
,則會獲得VFP / NEON庫,一切都可以正常工作。
我的建議只是弄清楚為什么設備和編譯器庫不同,並將其整理出來。
我的猜測 :如果沒有正確的開關指示vfp硬件支持,編譯器將使用軟件庫在手臂上進行浮點數學運算。 如果使用靜態鏈接進行編譯,這些庫將包含在二進制文件中 - 結果:它可以工作。 如果使用普通(動態)鏈接模式,則不會包含庫 - 結果:由於某種原因它不起作用。 tegra系統上的庫與您的交叉編譯器生成的內容在某種程度上是不兼容的(可能是由於調用約定)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.