7

大きなアプリケーションを 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;
}

腕の皮質 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 で使用することです...良くありませんが、当分の間は十分です。




編集:
回答ありがとうございます。
その間、ドキュメントには「-mfloat-abi=hard」でコンパイルされたツールチェーンが必要であると記載されていましたが、tegra デバイスの Linux ディストリビューションが「-mfloat-abi=softfp」でコンパイルされていることがわかりました。
ツールチェーンの変更が成功をもたらしました。

hard と softfp の違いは、任意のシステム バイナリで「readelf -A」を使用して確認できるよう
です。この行がない場合、バイナリは「-mfloat-abi=softfp」でコンパイルされている可能性があります。
'Tag_ABI_HardFP_use: SP and DP' という行は、コンパイラ フラグ '-mfloat-abi=hard' を示していません。

4

2 に答える 2

4

アセンブリの出力を見ると、2つのファイルに不一致があることがわかります。

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>

これは、、およびdoubleを渡します。r2:r3std::coutr0

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>

これにより、doublein d0(VFPレジスタ)とstd::coutinが渡されr0ます。ここで、2番目に出力される浮動小数点値(0.0)がr2:r3(によって)ロードされることを確認します。ldrd動的リンクostream::operator<<(double val)はその引数を期待しているためr2:r3、0が最初に出力されます。

2番目の奇妙に見えるフロートも説明できます。2番目のフロートが印刷される場所は次のとおりです。

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

のアドレスにr3設定されていることを確認してください。上から、。したがって、レジスタペアは0x0001104000000000になり、doubleとして1.478946186471156e-309にデコードされます。r0coutr0 = 0x011040r2:r3

したがって、問題は、デスクトップGCCのライブラリがVFP / NEON命令を使用していることです。これは、デバイス上のダイナミックライブラリでは使用されません。を使用する-staticと、VFP / NEONライブラリが取得され、すべてが再び機能します。

私の提案は、デバイスとコンパイラのライブラリが異なる理由を理解し、それを整理することです。

于 2012-10-10T13:28:21.070 に答える
0

私の推測: vfp ハードウェア サポートを示す適切なスイッチがなければ、コンパイラはソフトウェア ライブラリを使用してアーム上で浮動小数点演算を実行します。静的リンクを使用してコンパイルすると、これらのライブラリがバイナリに組み込まれます -- 結果: 動作します。通常の (動的) リンク モードを使用すると、ライブラリが含まれません。結果: 何らかの理由で機能しません。tegra システムのライブラリは、クロスコンパイラが生成するものと何らかの形で (おそらく呼び出し規約が原因で) 互換性がありません。

于 2012-10-10T12:09:18.487 に答える