Os arquivos de objeto (C) são criados com diferentes compiladores compatíveis com binários?

11

Eu entendo que os compiladores C ++ não são compatíveis entre si. No entanto, não consegui encontrar nada sobre esse tópico em particular para C. Eu sei que o padrão C deixa muito espaço para os compiladores implementarem as coisas da maneira que acharem melhor: por exemplo, o tamanho e o alinhamento da maioria dos tipos de dados (todos?) São definidos pela implementação, exceto por algumas garantias mínimas. Portanto, dois compiladores (ou duas versões do mesmo compilador) podem discordar em vários detalhes.

Estou correto ao pensar que não há garantia de que dois arquivos de objetos compilados com diferentes compiladores realmente sejam vinculados corretamente? Por exemplo, o tamanho dos ponteiros pode ser 32 bits em um arquivo de objeto e 64 bits no outro. Mas, se é assim, por que as bibliotecas C às vezes são distribuídas na forma pré-compilada? Existe uma expectativa de que usarei o mesmo compilador que eles usaram (por exemplo, gcc) ou algum padrão de fato sendo usado para garantir a compatibilidade binária? E como outros idiomas com uma interface de idioma estrangeiro garantem que as coisas estejam alinhadas corretamente ao vincular com arquivos de objeto C?

Doval
fonte
Tanto quanto me lembro, os arquivos de objeto C devem ser compatíveis entre si, desde que sejam compilados para a mesma plataforma. Um arquivo de objeto é apenas um arquivo que contém código binário carregável com alguma tabela de símbolos que pode ser usada para acessar cada símbolo dentro do módulo.
Giorgio
2
libs podem ser feitas compatível, eu não acho que obj são garantidos para ser
catraca aberração
@Giorgo Por "mesma plataforma", você quer dizer arquitetura de CPU ou arquitetura de CPU + SO?
Doval
@ratchetfreak Fiquei com a impressão de que uma lib é na maior parte apenas uma concatenação de vários arquivos de objeto. Isso está errado?
Doval
Eu não esperaria que os objetos fossem compatíveis entre diferentes compiladores.
old_timer

Respostas:

10

A resposta geral é não, compiladores da linguagem C não são compatíveis entre si. O padrão da linguagem C não define nenhum tipo de interoperabilidade binária, e a maioria dos criadores de compiladores nem sequer tentam.

Eu preciso qualificar isso. Os objetos emitidos por um compilador C precisam ser vinculados às bibliotecas de tempo de execução para produzir uma biblioteca executável ou uma biblioteca vinculável em tempo de execução. Embora as funções visíveis fornecidas pela biblioteca de tempo de execução C devam ser compatíveis, também haverá funções não visíveis exclusivas da implementação e que impedem a interoperabilidade.

Essa falta de compatibilidade também se estende a diferentes versões do mesmo compilador. Em geral, os programas e bibliotecas compilados com versões mais antigas e mais recentes de um compilador não podem ser vinculados, e os compilados com o MSVC não podem ser vinculados aos compilados pelo GCC.

Há uma exceção específica e muito útil. Toda plataforma fornece uma ABI de vinculação dinâmica (Application Binary Interface) e qualquer programa em qualquer idioma que possa estar em conformidade com essa ABI é compatível. Portanto, geralmente é possível criar uma DLL (no Windows) com o MSVC (ou outra coisa) e chamá-la de um programa compilado por uma versão diferente do MSVC ou pelo GCC e vice-versa.

Existem duas outras ABIs no Windows: assemblies COM e .NET e abrangem uma ampla variedade de idiomas. Portanto, a interoperabilidade é definitivamente possível, mas compatíveis eles não são.


O grau de incompatibilidade pode ser facilmente visto comparando os mapas do vinculador. Para uso GNU ld -M, para uso MSVC link /map. Estude os dois arquivos gerados. Ambos terão nomes neles que você reconhece, como printf e main, embora (dependendo das opções) os nomes provavelmente sejam mutilados de várias maneiras. Eles também terão nomes completamente diferentes, muitos dos quais você não reconhecerá. Para que os arquivos de objetos produzidos por diferentes compiladores sejam compatíveis, eles precisam concordar com todos esses nomes e nunca concordam. Nem mesmo versões diferentes do mesmo compilador sempre podem fazer isso.

david.pfx
fonte
Essa resposta parece contradizer a de Bart ; parece que apenas bibliotecas compartilhadas são compatíveis. Você poderia explicar por que as funções não visíveis e específicas da implementação da biblioteca de tempo de execução C impedem a interoperabilidade? Você também diz que "os objetos emitidos por um compilador C precisam ser vinculados às bibliotecas de tempo de execução para produzir uma biblioteca executável ou uma biblioteca vinculável de tempo de execução" - e as bibliotecas estáticas?
Doval
Como Bart disse, apenas bibliotecas com uma ABI são compatíveis. Bibliotecas compartilhadas (no Unix) são um tipo de ABI, existem outras. Escreva HelloWorld.c, compile-o com MSVC e gcc, compare os mapas e verá como eles são diferentes. 'Bibliotecas de tempo de execução' significa as funções essenciais de suporte referenciadas automaticamente em todas as compilações de C / C ++, que podem ser vinculadas estática ou dinamicamente. Leia o mapa ou o código-fonte CRT para vê-los.
David.pfx 14/04
Não sei o que significa comparar os mapas, por isso vou ser um pouco mais específico: é seguro assumir na prática que todos os compiladores para uma dada arquitetura de CPU E combinação de SO são compatíveis? Por exemplo, eu tenho o main.c, que eu compilo com gcc e mylibrary.c, que eu compilar com clang, ambos visando o Linux x64. Assumindo um sistema operacional razoavelmente convencional (Linux, Mac, Windows), é seguro assumir que funcionaria independentemente do que os dois compiladores são?
Doval
1
Altamente improvável, verifique o mapa de links clang. Veja editar.
David.pfx
17

O que você está procurando é chamado ABI (Application Binary Interface).

A linguagem C não define uma ABI, portanto, nesse sentido, não há realmente garantia de que os arquivos C compilados com diferentes compiladores funcionem entre si.

Por outro lado, na maioria das plataformas, o sistema operacional define uma ABI para interface com ele e todos os compiladores direcionados à família de SO e processador também usam a mesma ABI para interface com componentes que não são do sistema operacional. Portanto, na prática, objetos C criados por diferentes compiladores podem trabalhar entre si.

Bart van Ingen Schenau
fonte
Isso faz sentido. Eu acho que as bibliotecas compartilhadas seguem a ABI do SO também?
Doval
3
@Doval Bibliotecas especialmente compartilhadas, elas precisam ser solicitadas pelo mundo exterior.
toasted_flakes