web-dev-qa-db-ja.com

(C)異なるコンパイラで作成されたオブジェクトファイルはバイナリ互換ですか?

C++コンパイラは互いに互換性がないことを理解しています。ただし、特にCについては、このトピックについて何も見つけることができませんでした。 C標準は、コンパイラーが適切に実装できるものを実装する余地をたくさん残していることを知っています。たとえば、ほとんどの(すべての?)データ型のサイズと配置は、いくつかの最小限の保証のために実装定義で保存されます。したがって、2つのコンパイラー(または同じコンパイラーの2つのバージョン)は、多くの詳細について意見の相違を生じる可能性があります。

異なるコンパイラでコンパイルされた2つのオブジェクトファイルが実際に適切にリンクする保証はないと私は思っていますか?たとえば、ポインタのサイズは、1つのオブジェクトファイルでは32ビット、もう1つのオブジェクトファイルでは64ビットにすることができます。しかし、もしそうなら、なぜCライブラリがプリコンパイルされた形式で配布されることがあるのでしょうか?彼らが使ったのと同じコンパイラ(gccなど)を使用することを期待していますか、またはバイナリ互換性を確保するためにいくつかのデファクト標準を使用していますか?そして、C言語のオブジェクトファイルとリンクするときに、Foreign Language Interfaceを備えた他の言語がどのように正しく整列するのでしょうか

11
Doval

一般的な答えは「いいえ」です。C言語コンパイラは互いに互換性がありません。 C言語標準は、いかなる種類のバイナリ相互運用性も定義しておらず、ほとんどのコンパイラー作成者は試みていません。

それを修飾する必要があります。 Cコンパイラによって生成されたオブジェクトは、実行可能ライブラリとリンクして、実行可能ライブラリまたは実行時リンク可能ライブラリを生成する必要があります。 Cランタイムライブラリによって提供される可視関数は互換性があるはずですが、実装に固有であり、相互運用性を妨げる非可視関数もあります。

この互換性の欠如は、同じコンパイラの異なるバージョンにも適用されます。一般に、古いバージョンと新しいバージョンのコンパイラでコンパイルされたプログラムとライブラリはリンクできません。また、MSVCでコンパイルされたプログラムとライブラリは、GCCでコンパイルされたものとリンクできません。

特定の非常に役立つ例外があります。すべてのプラットフォームは、ダイナミックリンクABI(アプリケーションバイナリインターフェース)と、そのABIに準拠できる任意の言語のプログラムを提供します。したがって、一般的にDLL(Windowsの場合))をMSVC(または他の何か)でビルドし、別のバージョンのMSVCまたはGCCでコンパイルされたプログラムから呼び出すことができます。

Windowsには他に2つのABIがあります。COMアセンブリと.NETアセンブリであり、それらは幅広い言語にまたがっています。したがって、相互運用性は確実に可能ですが、互換性はありません。


非互換性の程度は、リンカーマップを比較することで簡単に確認できます。 GNUの場合はld -Mを使用し、MSVCの場合はlink /mapを使用します。生成された2つのファイルを確認します。どちらにも、printfやmainなど、認識できる名前があります。 (オプションによって異なります)名前はさまざまな方法で変更される可能性があります。また、完全に異なる名前が付けられ、その多くは認識されません。異なるコンパイラーによって生成されたオブジェクトファイルに互換性を持たせるには、同じコンパイラの異なるバージョンでさえ、常にそれを行うことができるわけではありません。

10
david.pfx

あなたが探しているものは、ABI(Application Binary Interface)と呼ばれます。

C言語はABIを定義していないため、その意味で、異なるコンパイラーでコンパイルされたCファイルが互いに動作するという保証はありません。

一方、ほとんどのプラットフォームでは、OSがそれとのインターフェース用にABIを定義し、そのOSとプロセッサフ​​ァミリをターゲットとするすべてのコンパイラも、OS以外のコンポーネントとのインターフェース用に同じABIを使用します。そのため、実際には、異なるコンパイラーによって作成されたCオブジェクトは、相互に動作できます。