Apa yang menyebabkan crash ini setelah kompilasi silang?

8

Saya mencoba mengkompilasi silang pustaka besar (TensorFlow) menggunakan gcc di Ubuntu. Saya telah menginstal g ++ - arm-linux-gnueabihf toolchain, dan berhasil membangun biner saya. Proses yang saya gunakan untuk membangun didokumentasikan di sini: https://github.com/petewarden4prs/tensorflow/tree/master/tensorflow/contrib/makefile#raspberry-pi

Awalnya saya menemukan kesalahan bahwa pthreading dinonaktifkan ("Aktifkan multithreading untuk menggunakan std :: thread: Operasi tidak diizinkan") ketika saya mencoba menjalankan executable yang dihasilkan pada Pi 3. Saya mengkompilasi ulang dengan -pthread diaktifkan sebagai opsi kompilasi, dan sekarang program crash secara acak dengan kesalahan segmentasi. Menjalankannya di gdb, mereka sering tampak berhubungan dengan free () dipanggil dengan pointer buruk, dan tumpukan panggilan tampaknya rusak, jadi saya berasumsi ada beberapa ketidakcocokan memori yang terjadi.

Adakah yang punya saran tentang hal-hal yang bisa saya coba lacak apa yang salah di sini?

Berikut ini beberapa detail dari Pi saya:

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

Berikut adalah contoh sesi khas di 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?)
Pete Warden
sumber
1
Apakah kode Anda 32bit atau 64? Saya juga punya proyek saya ingin bekerja tetapi saya mendapatkan dump serupa "Tidak dapat mengakses memori ....." Kami menelusurinya ke inkompatibilitas 32bit Environment.
Dan V
2
Sama seperti pembaruan, saya akhirnya meninggalkan kompilasi silang, karena sepertinya kurang digunakan daripada kompilasi asli dan itu lebih sulit untuk men-debug masalah seperti ini.
Pete Warden

Jawaban:

3

Cara termudah untuk kompilasi silang yang kompatibel dengan biner adalah dengan menginstal toolchain yang digunakan oleh pengembang Raspbian. Itu dapat ditemukan di sini . Sangat penting untuk menggunakan rantai alat ini jika Anda ingin membangun kernel dan driver, karena objek kernel membutuhkan kompatibilitas ABI yang sempurna, tetapi memiliki kompatibilitas yang sempurna tidak akan merugikan jika Anda juga membangun biner userspace.

Menurut dokumentasi , rantai alat ini kompatibel dengan Ubuntu saat ini, baik 32-bit dan 64-bit.

Dmitry Grigoryev
sumber
3

Saya mendapat pure virtual method calledpengecualian saat kompilasi silang. @ JeremyBarnes jawaban tidak cukup untuk saya. Sebaliknya saya menggunakan:

-U__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 -U__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 -U__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8

Penjelasan :

Seperti yang ditunjukkan oleh @JeremyBarnes, untuk memastikan kompatibilitas ABI aplikasi Anda dengan stdc yang diinstal ++, keduanya perlu dikompilasi dengan SYNCflag yang sama .

Tentang Raspbian:

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

Tanpa perbaikan dockcross/linux-armv6dan 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

Dengan perbaikan dockcross/linux-armv6dan 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
pengguna1202136
sumber
2

FWIW, ini bisa diperbaiki dengan menambahkan -D__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 -D__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 -D__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8ke flag compiler.

Mengapa? Di /usr/include/c++/4.{8,9}/bits/concurrency.h, kebijakan kunci default bergantung pada definisi ini:

#jika (didefinisikan (__ GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) \
     && didefinisikan (__ GCC_HAVE_SYNC_COMPARE_AND_SWAP_4))

ABI dari sebuah pointer bersama tergantung pada bagaimana flag-flag ini didefinisikan, karena itu mewarisi dari kelas dasar yang menggunakan argumen templat default untuk kebijakan penguncian. Oleh karena itu, mengubah flag-flag ini mengubah tata letak (karena itu mengubah tata letak kelas dasar) dari std :: shared_ptr <...> objek dalam pustaka C ++ standar.

Dalam kompiler yang datang dengan Pi, dengan Raspbian yang dibangun, mereka ditetapkan sebagai berikut:

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

Ini masuk akal untuk Pi 1, tetapi sangat memalukan untuk Pi 3 yang bisa dengan senang hati menggunakan pointer atom bersama.

Di Ubuntu, mereka diatur seperti ini:

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

Bendera baris perintah di atas mengatur ulang mereka menjadi seperti semula pada Pi.

Kompilasi silang sepadan; Tensorflow sudah lambat dibangun di server yang gemuk; harus memakan waktu yang sangat lama untuk membangun Pi!

Jeremy Barnes
sumber