クロスコンパイル後にこれらのクラッシュを引き起こしているのは何ですか?


8

Ubuntuでgccを使用して大きなライブラリ(TensorFlow)をクロスコンパイルしようとしています。g ++-arm-linux-gnueabihfツールチェーンをインストールし、バイナリを正常にビルドできました。ビルドに使用しているプロセスはここに文書化されています:https : //github.com/petewarden4prs/tensorflow/tree/master/tensorflow/contrib/makefile#raspberry-pi

最初に、結果の実行可能ファイルをPi 3で実行しようとしたときに、pthreadingが無効になっているというエラー(「マルチスレッド化を有効にしてstd :: thread:操作は許可されていません」)に遭遇しました。コンパイルオプションとして-pthreadを有効にして再コンパイルし、現在、プログラムは一見ランダムにセグメンテーション違反でクラッシュします。それをgdbで実行すると、free()が不正なポインターで呼び出されていることに関連しているようで、呼び出しスタックが壊れているように見えるため、メモリの不一致が発生していると想定しています。

ここで何が問題になっているのかを追跡するために私が試すことができるものについて誰か提案がありますか?

これが私のPiの詳細です。

pi@raspberrypi ~ $ uname -a
Linux raspberrypi 4.1.19-v7+ #858 SMP Tue Mar 15 15:56:00 GMT 2016 armv7l GNU/Linux
pi@raspberrypi ~ $ file benchmark 
benchmark: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=0x5043384f5d0003f8074b07dfdd38cdc20315143f, not stripped

以下は、gdbの典型的なセッションの例です。

[New Thread 0x76cf5450 (LWP 6011)]
*** glibc detected *** /home/pi/benchmark: free(): invalid pointer: 0x018e2e89 ***

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x76cf5450 (LWP 6011)]
0x76f98e40 in std::string::c_str() const () from /usr/lib/arm-linux-gnueabihf/libstdc++.so.6
(gdb) thread apply all bt

Thread 2 (Thread 0x76cf5450 (LWP 6011)):
#0  0x76f98e40 in std::string::c_str() const () from /usr/lib/arm-linux-gnueabihf/libstdc++.so.6
#1  0x00bad996 in tensorflow::thread::ThreadPool::Impl::WorkerLoop() ()
#2  0x00bad5de in tensorflow::thread::ThreadPool::Impl::Impl(tensorflow::Env*, tensorflow::ThreadOptions const&, std::string const&, int)::{lambda()#1}::operator()() const ()
#3  0x00badec2 in std::_Function_handler<void (), tensorflow::thread::ThreadPool::Impl::Impl(tensorflow::Env*, tensorflow::ThreadOptions const&, std::string const&, int)::{lambda()#1}>::_M_invoke(std::_Any_data const&) ()
#4  0x0029aaf4 in std::function<void ()>::operator()() const ()
#5  0x00b53e1e in _ZNSt12_Bind_simpleIFSt8functionIFvvEEvEE9_M_invokeIJEEEvSt12_Index_tupleIJXspT_EEE ()
#6  0x00b53d90 in std::_Bind_simple<std::function<void ()> ()>::operator()() ()
#7  0x00b53d4a in std::thread::_Impl<std::_Bind_simple<std::function<void ()> ()> >::_M_run() ()
#8  0x76f91848 in ?? () from /usr/lib/arm-linux-gnueabihf/libstdc++.so.6
#9  0x76f91848 in ?? () from /usr/lib/arm-linux-gnueabihf/libstdc++.so.6
Backtrace stopped: previous frame identical to this frame (corrupt stack?)

Thread 1 (Thread 0x76ff6000 (LWP 6010)):
#0  0x76dfc61c in ?? () from /lib/arm-linux-gnueabihf/libc.so.6
#1  0x76fff048 in ?? () from /lib/ld-linux-armhf.so.3
Cannot access memory at address 0x158
#2  0x76fff048 in ?? () from /lib/ld-linux-armhf.so.3
Cannot access memory at address 0x158
Backtrace stopped: previous frame identical to this frame (corrupt stack?)

1
コードは32ビットですか、それとも64ですか?私も作業したいプロジェクトを持っていますが、同様のダンプ「Cannot access memory .....」を取得しました。32ビット環境の非互換性まで追跡しました。
Dan V

2
アップデートと同じように、ネイティブコンパイルほどよく使われていないようで、このような問題をデバッグするのが困難だったので、クロスコンパイルを放棄することになりました。
Pete Warden

回答:


3

バイナリ互換のクロスコンパイルを行う最も簡単な方法は、Raspbian開発者が使用するツールチェーンをインストールすることです。それは見つけることができるここに。カーネルオブジェクトは完全なABI互換性を必要とするため、カーネルとドライバーをビルドする場合は、このツールチェーンを使用することが不可欠ですが、ユーザースペースバイナリもビルドする場合、完全な互換性があっても問題はありません。

ドキュメントによると、このツールチェーンは、32ビットと64ビットの両方の現在のUbuntuと互換性があります。


3

pure virtual method calledクロスコンパイルすると例外が発生しました。@JeremyBarnesの答えは私にとってはうまくいきませんでした。代わりに私は使用しました:

-U__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 -U__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 -U__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8

説明

@JeremyBarnesが指摘したように、インストールされたstdc ++とアプリケーションのABI互換性を確保するには、両方を同じSYNCフラグでコンパイルする必要があります。

Raspbianの場合:

$ g++ -dM -E - < /dev/null | grep SYNC
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1

dockcross/linux-armv6およびの修正なしdockcross/linux-armv7

$ g++ -dM -E - < /dev/null | grep SYNC
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1

修正をオンにdockcross/linux-armv6してdockcross/linux-armv7

$ g++ -U__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 -U__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2  -E - < /dev/null | grep SYNC
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1

2

FWIW、これ-D__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 -D__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 -D__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8はコンパイラフラグに追加することで修正できます。

どうして?/usr/include/c++/4.{8,9}/bits/concurrency.hでは、デフォルトのロックポリシーは次の定義に依存します。

#if(defined(__ GCC_HAVE_SYNC_COMPARE_AND_SWAP_2)\
     &&定義済み(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4))

共有ポインターのABIは、これらのフラグがどのように定義されているかによって異なります。これは、ロックポリシーのデフォルトのテンプレート引数を使用する基本クラスから継承されるためです。したがって、これらのフラグを変更すると、標準C ++ライブラリのstd :: shared_ptr <...>オブジェクトのレイアウトが変更されます(基本クラスのレイアウトが変更されるため)。

Raspbianのビルドに使用されたPiに付属のコンパイラでは、次のように設定されています。

g ++ -dM -E-</ dev / null | grep SYNC
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1

これはPi 1にとっては賢明ですが、アトミック共有ポインターを非常に楽しく使用できるPi 3にとって大きな恥です。

Ubuntuでは、次のように設定されています。

arm-linux-gnueabihf-g ++ -dM -E-</ dev / null | grep SYNC
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1

上記のコマンドラインフラグは、デフォルトでPiの状態にリセットします。

クロスコンパイルはそれだけの価値があります。Tensorflowは、すでに強力なサーバー上に構築するのが遅いです。Piを構築するには、信じられないほど長い時間がかかります!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.