¿Los archivos de objetos (C) creados con diferentes compiladores son compatibles con binarios?

11

Entiendo que los compiladores de C ++ no son compatibles entre sí. Sin embargo, no pude encontrar nada sobre este tema para C en particular. Sé que el estándar C deja mucho espacio para que los compiladores implementen lo que quieran: por ejemplo, el tamaño y la alineación de la mayoría de los tipos de datos (¿todos?) Está definido por la implementación, salvo algunas garantías mínimas. Por lo tanto, dos compiladores (o dos versiones del mismo compilador) pueden estar en desacuerdo sobre numerosos detalles.

¿Estoy en lo cierto al pensar que no hay garantía de que dos archivos de objetos compilados con compiladores diferentes realmente se vinculen correctamente? Por ejemplo, el tamaño de los punteros podría ser de 32 bits en un archivo de objeto y de 64 bits en el otro. Pero si es así, ¿por qué las bibliotecas C a veces se distribuyen en forma precompilada? ¿Existe la expectativa de que usaré el mismo compilador que usaron (por ejemplo, gcc), o algún estándar de facto que se use para garantizar la compatibilidad binaria? ¿Y cómo otros lenguajes con una interfaz de idioma extranjero aseguran que las cosas se alineen correctamente cuando se vinculan con archivos de objetos C?

Doval
fuente
Hasta donde puedo recordar, los archivos de objetos C deberían ser compatibles entre sí siempre que se compilen para la misma plataforma. Un archivo de objeto es solo un archivo que contiene código binario cargable con alguna tabla de símbolos que se puede utilizar para acceder a cada símbolo dentro del módulo.
Giorgio
2
las librerías se pueden hacer compatibles, no creo que se garantice que los obj sean
fanático del trinquete
@Giorgo Por "misma plataforma", ¿quiere decir arquitectura de CPU o arquitectura de CPU + SO?
Doval
@ratchetfreak Tenía la impresión de que una lib es en su mayor parte solo una concatenación de múltiples archivos de objetos. ¿Es eso incorrecto?
Doval
No esperaría que los objetos fueran compatibles en diferentes compiladores.
old_timer

Respuestas:

10

La respuesta general es no, los compiladores del lenguaje C no son compatibles entre sí. El estándar del lenguaje C no define ningún tipo de interoperabilidad binaria, y la mayoría de los escritores de compiladores ni siquiera lo intentan.

Necesito calificar eso. Los objetos emitidos por un compilador de C deben estar vinculados con bibliotecas de tiempo de ejecución para producir una biblioteca ejecutable o enlazable en tiempo de ejecución. Aunque las funciones visibles proporcionadas por la biblioteca de tiempo de ejecución C deberían ser compatibles, también habrá funciones no visibles que son exclusivas de la implementación y evitan la interoperabilidad.

Esta falta de compatibilidad también se extiende a diferentes versiones del mismo compilador. En general, los programas y bibliotecas compilados con versiones anteriores y nuevas de un compilador no pueden vincularse entre sí, y los compilados con MSVC no pueden vincularse con los compilados por GCC.

Hay una excepción específica y muy útil. Cada plataforma proporciona un enlace dinámico ABI (Application Binary Interface) y cualquier programa en cualquier idioma que pueda cumplir con ese ABI es compatible. Por lo tanto, generalmente es posible construir un archivo DLL (en Windows) con MSVC (o algo más) y llamarlo desde un programa compilado por una versión diferente de MSVC o por GCC y viceversa.

Hay otros dos ABI en Windows: ensamblados COM y .NET, y abarcan una amplia gama de idiomas. Entonces, la interoperabilidad es definitivamente posible, pero compatibles no lo son.


El grado de incompatibilidad se puede ver fácilmente comparando los mapas del enlazador. Para uso de GNU ld -M, para uso de MSVC link /map. Estudie los dos archivos generados. Ambos tendrán nombres que reconocerá, como printf y main, aunque (dependiendo de las opciones) es probable que los nombres se maltraten de varias maneras. También tendrán nombres que son completamente diferentes, muchos de los cuales no reconocerá. Para que los archivos de objetos producidos por diferentes compiladores sean compatibles, deben acordar todos esos nombres, y nunca lo hacen. Ni siquiera las diferentes versiones del mismo compilador siempre pueden hacer eso.

david.pfx
fuente
Esta respuesta parece contradecir la de Bart ; Parece que solo las bibliotecas compartidas son compatibles. ¿Podría explicar por qué las funciones específicas de implementación no visibles de la biblioteca de tiempo de ejecución C impiden la interoperabilidad? También dice "los objetos emitidos por un compilador de C tienen que estar vinculados con bibliotecas de tiempo de ejecución para producir una biblioteca ejecutable o una biblioteca enlazable de tiempo de ejecución". ¿Qué pasa con las bibliotecas estáticas?
Doval
Como dijo Bart, solo las bibliotecas con un ABI son compatibles. Las bibliotecas compartidas (en Unix) son un tipo de ABI, hay otras. Escriba HelloWorld.c, compílelo con MSVC y gcc, compare los mapas y verá cuán diferentes son. 'Bibliotecas de tiempo de ejecución' significa las funciones de soporte esenciales a las que se hace referencia automáticamente en cada compilación C / C ++, que pueden estar vinculadas estática o dinámicamente. Lea el mapa o el código fuente CRT para verlos.
david.pfx
No sé qué significa comparar los mapas, así que seré un poco más específico: ¿es seguro asumir en la práctica que todos los compiladores para una arquitectura de CPU y combinación de SO son compatibles? Por ejemplo, tengo main.c, que compilo con gcc y mylibrary.c que compilo con clang, ambos dirigidos a Linux x64. Suponiendo un sistema operativo razonablemente convencional (Linux, Mac, Windows), ¿es seguro asumir que funcionaría independientemente de cuáles sean los dos compiladores?
Doval
1
Altamente improbable, verifique el mapa de enlaces clang Ver editar.
david.pfx
17

Lo que está buscando se llama ABI (Application Binary Interface).

El lenguaje C no define un ABI, por lo que, en ese sentido, no hay garantía de que los archivos C compilados con diferentes compiladores funcionen entre sí.

Por otro lado, en la mayoría de las plataformas, el sistema operativo define un ABI para interactuar con él y todos los compiladores destinados a ese sistema operativo y la familia de procesadores también usan ese mismo ABI para interactuar con componentes que no son del sistema operativo. Entonces, en la práctica, los objetos C creados por diferentes compiladores pueden funcionar entre sí.

Bart van Ingen Schenau
fuente
Eso tiene sentido. Supongo que las bibliotecas compartidas también siguen el ABI del sistema operativo.
Doval
3
@Doval Bibliotecas especialmente compartidas, deben poder ser llamadas por el mundo exterior.
toasted_flakes