Pregunta

Tengo una aplicación C ++ multiplataforma que se divide en varias bibliotecas compartidas y carga funcionalidades adicionales de las bibliotecas compartidas de complementos. Se supone que las bibliotecas de complementos son independientes y funcionan por sí mismas, sin conocimiento o dependencia de la aplicación que realiza la llamada.

Uno de los complementos contiene código copiado de la aplicación principal, por lo que contiene nombres de símbolos que están duplicados a los del motor. (Sí, sé que generalmente es un no-no, pero en el momento en que se escribió el complemento, el motor era un binario monolítico y no podía compartir bibliotecas). En Windows, todo funciona bien. En Linux recibíamos segfaults. Al observar el seguimiento de la pila del error, estaba ocurriendo en el complemento al llamar a funciones en el nombre de clase duplicado. Parecía ser el resultado de que el motor y el complemento tenían versiones ligeramente diferentes del código compartido (algunas funciones de clase se comentaron en el complemento). Era como si el complemento obtuviera sus símbolos de tiempo de ejecución vinculados al motor en lugar de al suyo. & Quot; arreglamos & Quot; el problema cambiando los parámetros de dlopen para que sean dlopen(pFilepath, RTLD_LAZY | RTLD_LOCAL).

Pero cuando reescribimos el motor para dividirlo en bibliotecas compartidas (con el propósito eventual de reutilizar en los complementos), obtenemos nuevamente el error de segfault. Y mirando el rastro de la pila, sale del motor - & Gt; plugin - > motor.

¿Hay alguna manera de especificar que el enlazador de tiempo de ejecución no asigne símbolos del complemento al motor (especialmente si están definidos en el complemento)?

¡Gracias! Matt


Editado 2009-12-3

Primero intenté envolver el código del complemento en su propio espacio de nombres. Eso no funcionó porque está estáticamente vinculado a una biblioteca que también está vinculada al motor. Las versiones de la biblioteca estática son diferentes, ¡así que por defecto!

Luego cambié la compilación del motor y sus bibliotecas se vincularán estáticamente. Y cuando lo ejecuto, ya no tengo el problema. Por lo tanto, parece que fue el resultado de exportar los símbolos de la biblioteca compartida y luego reubicarlos dinámicamente en el complemento cuando se abrió. Pero cuando todo el código del motor está en un solo ejecutable, no exporta sus símbolos (por lo que no intenta reubicar los símbolos del complemento en el motor).

Todavía tengo un problema, ya que hay una versión paralela del programa (usando Open-MPI) y que todavía tiene la segfault. Parece que todavía está exportando los símbolos del motor y reubicando los complementos. Eso podría tener que ver con cómo Open-MPI ejecuta la aplicación.

¿Hay algún indicador de enlace que pueda usarse en la biblioteca compartida del complemento que le diga que no reubique dinámicamente los símbolos en tiempo de ejecución? ¿O para ocultar sus símbolos para que no se reubiquen? Intenté -s (& Quot; Omitir toda la información de símbolos & Quot;) pero aparentemente eso no cambió los símbolos dinámicos (marcados con nm -D <plugin>).

¿Fue útil?

Solución

Creo que he encontrado la solución, el indicador de enlace -Bsymbolic. Esencialmente, este indicador agrega un indicador en la biblioteca compartida para indicarle al vinculador de tiempo de ejecución que primero intente resolver los nombres de los símbolos. El motor pudo ejecutarse con el complemento perfectamente en todos los casos (exe monolítico, exe w / libs compartidas, plugin w / y sin envolver el espacio de nombres) cuando el complemento se vinculó con esa bandera.

Parece haber algunos detractores con advertencias sobre <=>:
http://www.technovelty.org/code/c/bsymbolic.html
http://software.intel.com/en-us/articles/performance-tools-for-software-developers-bsymbolic-can-cause-dangerous-side-effects/

Pero teniendo en cuenta sus advertencias y cuál es la intención del complemento, creo que es la opción correcta para mí. Al menos por ahora.

Otros consejos

Estoy de acuerdo con Glen: realmente no va a resolver esto a menos que modifique los nombres de clase, posiblemente a través de espacios de nombres. Incluso 36 archivos probablemente tomarán menos tiempo para modificarse que tratar de arreglarlo de manera confiable sin cambiar los nombres de los símbolos.

Comience por identificar todas las clases cuyos nombres deben modificarse. Su enlazador probablemente ya los enumere para usted. Luego cambiaría los nombres de ambos conjuntos de clases (de Foo a Engine :: Foo y Plugin :: Foo, por ejemplo) al menos temporalmente. De esa manera, puede hacer que el compilador encuentre todas las referencias a las clases problemáticas. Elimine el origen del complemento hasta que el complemento se compile con referencias a los nuevos nombres correctos de clase de complemento. Una vez hecho esto, cambie las clases Engine :: a sus antiguos nombres (a menos que también desee modificar permanentemente la fuente del motor, lo que parece que no). El complemento ahora debe compilarse y vincularse a las clases correctas con nombres únicos.

Simplemente envolvería TODO el código del complemento con un espacio de nombre PluginX. Eso seguramente lo salvará de estos errores. Es una muy buena, importante, práctica de todos modos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top