Что вызывает эти сбои после кросс-компиляции?

8

Я пытаюсь кросс-компилировать большую библиотеку (TensorFlow), используя gcc в Ubuntu. Я установил набор инструментов g ++ - arm-linux-gnueabihf и смог успешно собрать мой бинарный файл. Процесс, который я использую для сборки, описан здесь: https://github.com/petewarden4prs/tensorflow/tree/master/tensorflow/contrib/makefile#raspberry-pi

Первоначально я обнаружил ошибку, что pthreading был отключен («Включить многопоточность для использования std :: thread: операция не разрешена»), когда я попытался запустить полученный исполняемый файл на моем Pi 3. Я перекомпилировал с -pthread включенным в качестве опции компиляции, и теперь программа вылетает на первый взгляд случайным образом с ошибками сегментации. Запуская его в gdb, они часто связаны с вызовом free () с плохими указателями, а стеки вызовов кажутся испорченными, поэтому я предполагаю, что происходит некоторое несовпадение памяти.

У кого-нибудь есть предложения о том, что я могу попытаться отследить, что здесь происходит не так?

Вот еще некоторые подробности из моего Пи:

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? У меня тоже есть проект, который я хочу получить, но я получаю похожий дамп «Невозможно получить доступ к памяти…». Мы проследили его до несовместимости с 32-битной средой.
Дан V
2
В качестве обновления я отказался от кросс-компиляции, так как она кажется менее используемой, чем нативная компиляция, и было сложнее отлаживать подобные проблемы.
Пит Уорден

Ответы:

3

Самый простой способ кросс-компиляции в двоичном формате - это установка набора инструментов, используемого разработчиками Raspbian. Это можно найти здесь . Важно использовать этот набор инструментов, если вы хотите собрать ядро ​​и драйверы, поскольку объекты ядра требуют идеальной совместимости с ABI, но безупречная совместимость не повредит, если вы также создаете двоичные файлы пользовательского пространства.

Согласно документации , этот набор инструментов совместим с текущей Ubuntu, как 32-битной, так и 64-битной.

Дмитрий Григорьев
источник
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, чтобы обеспечить совместимость ABI вашего приложения с установленным stdc ++, они должны быть скомпилированы с одинаковыми SYNCфлагами.

На Распбиане:

$ 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
user1202136
источник
2

Кстати, это можно исправить, добавив -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. average8,9 innovative/bits/concurrency.h политика блокировки по умолчанию зависит от следующих определений:

#if (определено (__ GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) \
     && определено (__ GCC_HAVE_SYNC_COMPARE_AND_SWAP_4))

ABI общего указателя зависит от того, как эти флаги определены, поскольку он наследуется от базового класса, который использует аргумент шаблона по умолчанию для политики блокировки. Следовательно, изменение этих флагов изменяет компоновку (поскольку она меняет компоновку базового класса) объектов std :: shared_ptr <...> в стандартной библиотеке C ++.

В компиляторе, который идет с Pi, с помощью которого был построен Raspbian, они установлены следующим образом:

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 уже медленно строится на мощном сервере; должно занять невероятно много времени, чтобы построить на Пи!

Джереми Барнс
источник