¿Qué está causando estos bloqueos después de la compilación cruzada?

8

Estoy tratando de compilar una biblioteca grande (TensorFlow) usando gcc en Ubuntu. Instalé la cadena de herramientas g ++ - arm-linux-gnueabihf, y pude construir con éxito mi binario. El proceso que estoy usando para construir está documentado aquí: https://github.com/petewarden4prs/tensorflow/tree/master/tensorflow/contrib/makefile#raspberry-pi

Inicialmente recibí un error de que pthreading estaba deshabilitado ("Habilitar subprocesos múltiples para usar std :: thread: Operación no permitida") cuando intenté ejecutar el ejecutable resultante en mi Pi 3. Recompilé con -pthread habilitado como una opción de compilación, y ahora el programa se bloquea aparentemente al azar con fallas de segmentación. Al ejecutarlo en gdb, a menudo parecen estar relacionados con free () que se llama con punteros incorrectos, y las pilas de llamadas parecen corruptas, por lo que supongo que está ocurriendo una falta de coincidencia de memoria.

¿Alguien tiene sugerencias sobre cosas que puedo tratar de rastrear qué está pasando aquí?

Aquí hay algunos detalles más de mi 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

Aquí hay un ejemplo de una sesión típica en 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
fuente
1
¿Su código es de 32 bits o 64? Yo también tengo un proyecto que quiero que funcione, pero obtengo un volcado similar "No se puede acceder a la memoria ....." Lo rastreamos hasta 32 bits de incompatibilidad con el entorno.
Dan V
2
Solo como una actualización, terminé abandonando la compilación cruzada, ya que parece menos utilizada que la compilación nativa y fue más difícil depurar problemas como este.
Pete Warden

Respuestas:

3

La forma más fácil de una compilación cruzada compatible con binarios es instalar la cadena de herramientas utilizada por los desarrolladores de Raspbian. Se puede encontrar aquí . Es esencial usar esta cadena de herramientas si desea construir el kernel y los controladores, ya que los objetos del kernel requieren una compatibilidad ABI perfecta, pero tener compatibilidad perfecta no afectará si también está creando binarios de espacio de usuario.

Según la documentación , esta cadena de herramientas es compatible con Ubuntu actual, tanto de 32 bits como de 64 bits.

Dmitry Grigoryev
fuente
3

Estaba obteniendo una pure virtual method calledexcepción al realizar la compilación cruzada. La respuesta de @ JeremyBarnes no funcionó para mí. En su lugar, usé:

-U__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 -U__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 -U__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8

Explicación :

Como señaló @JeremyBarnes, para garantizar la compatibilidad ABI de su aplicación con el stdc ++ instalado, ambos deben compilarse con los mismos SYNCindicadores.

En Raspbian:

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

Sin la corrección dockcross/linux-armv6y 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

Con la corrección activada dockcross/linux-armv6y 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
usuario1202136
fuente
2

FWIW, esto se puede solucionar agregando -D__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 -D__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 -D__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8a los indicadores del compilador.

¿Por qué? En /usr/include/c++/4.{8,9}/bits/concurrency.h, la política de bloqueo predeterminada depende de estas definiciones:

#if (definido (__ GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) \
     && definido (__ GCC_HAVE_SYNC_COMPARE_AND_SWAP_4))

El ABI de un puntero compartido depende de cómo se definan estos indicadores, ya que hereda de una clase base que utiliza un argumento de plantilla predeterminado para la política de bloqueo. Por lo tanto, cambiar estos indicadores cambia el diseño (porque cambia el diseño de la clase base) de los objetos std :: shared_ptr <...> en la biblioteca estándar de C ++.

En el compilador que viene con el Pi, con el que se construyó Raspbian, se configuran de la siguiente manera:

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

Esto es sensato para el Pi 1, pero es una gran pena para el Pi 3, que puede usar felizmente punteros atómicos compartidos.

En Ubuntu, se configuran así:

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

Los indicadores de la línea de comando de arriba los restablecen a su estado predeterminado en el Pi.

La compilación cruzada vale la pena; Tensorflow ya es lento para construir en un servidor robusto; ¡Debe tomar un tiempo increíblemente largo para construir en el Pi!

Jeremy Barnes
fuente