簡體   English   中英

手臂皮質a9交叉編譯奇怪的浮點行為

[英]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設置為r0cout的地址。 從上面看, 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM