1. ホーム
  2. compiler-construction

[解決済み] アプリケーション・バイナリ・インターフェース(ABI)とは何ですか?

2022-03-15 12:03:37

質問

ABIとは何か、明確に理解したことがありません。Wikipediaの記事は勘弁してください。もし理解できていたら、ここでこんな長文を投稿していないはずです。

これは、さまざまなインターフェースに対する私の考え方です。

テレビのリモコンは、ユーザーとテレビをつなぐインターフェイスです。それ自体は存在するが、それ自身は役に立たない(何の機能も提供しない)。リモコンの各ボタンの機能は、すべてテレビに実装されているのです。

<ブロッククオート

インターフェースです。 の間のレイヤーです。 functionalityconsumer その機能の インターフェースはそれ自体で は何もしない。ただ、背後にある機能を呼び出すだけです。

さて、ユーザーが誰であるかによって、さまざまなタイプのインターフェースがあります。

コマンドラインインターフェース(CLI) コマンドは既存のエンティティです。 消費者はユーザーであり、機能性はその背後にあるものです。

functionality: 私のソフトウェアの機能で このインターフェイスを記述する目的。

existing entities: コマンド

consumer: ユーザー

グラフィカル・ユーザー・インターフェース(GUI) ウィンドウやボタンなど、既存の また、消費者はユーザーであり、機能性はその背後にあるものです。

functionality: このインターフェイスを記述している問題を解決する、私のソフトウェアの機能です。

existing entities: ウィンドウ、ボタンなど。

consumer: ユーザー

アプリケーションプログラミングインターフェース(API) 関数(正確には インターフェイスは(インターフェイスベースのプログラミングでは)より正確です。 既存のエンティティであり、ここでの消費者はユーザーではない別のプログラムであり、再び 機能はこのレイヤーの後ろにあります。

functionality: を解決する私のソフトウェアの機能です。 の問題に対して、このインターフェイスを記述しています。

existing entities: 関数、インターフェース(関数の配列)です。

consumer: 別のプログラム/アプリケーションです。

アプリケーションバイナリインターフェース(ABI) ここからが私の問題の始まりです。

functionality: ???

existing entities: ???

consumer: ???

  • 私はこれまでさまざまな言語でソフトウェアを書き、さまざまな種類のインターフェイス(CLI、GUI、API)を提供してきましたが、ABIを提供したことがあるかどうかはわかりません。

ウィキペディアによると

ABIは、以下のような詳細をカバーしています。

  • データ型、サイズ、アライメント。
  • 関数の引数の取り方を制御する呼び出し規約。 を渡し、戻り値を取得する。
  • システムコール番号と、アプリケーションがどのようにシステムコールを行うか。 をオペレーティングシステムに送信します。

その他のABIは、以下のような詳細を標準化しています。

  • C++の名前のマングリング。
  • 例外の伝搬、および
  • 同じプラットフォーム上のコンパイラ間の呼び出し規則であり、かつ は、クロスプラットフォームの互換性を必要としません。
  • 誰がこの詳細を必要としますか?OSなんて言わないでくださいよ。私はアセンブリプログラミングを知っています。リンク&ロードの仕組みも知っている。内部で何が起こっているかも知っている。

  • なぜC++のネームマングリングが入ったのでしょうか?バイナリーレベルの話じゃないのか?なぜ言語が入ってくるのか?

とにかく、ダウンロードした [PDF】System V Application Binary Interface 第4.1版 (1997-03-18) を読んで、その内容を確認しました。まあ、ほとんどは意味不明でしたけど。

  • なぜ、4章と5章の2つの章があるのでしょうか? エルフ ファイル形式ですか?実は、この仕様書の中で重要なのは、この2章だけなのです。残りの章は、プロセッサー固有のものです。いずれにせよ、まったく別の話なのですが。ELFファイルフォーマットの仕様がどうのこうのというのは勘弁してください。 ABIです。である資格はないのです。 インターフェイス によると、定義によると

  • こんな低レベルの話をしているのだから、かなり具体的な内容でなければならないのでしょう。しかし、私はそれがどのように"命令セットアーキテクチャ(ISA)"固有のものであるのかよく分からないのですが?

  • Microsoft WindowsのABIはどこで手に入りますか?

というわけで、以上が気になる主なクエリです。

どのように解決するのですか?

ABIを理解するには、APIと比較するのがわかりやすいでしょう。

皆さんはAPIという概念に既に馴染みがあると思います。 例えば、あるライブラリやOSの機能を使いたい場合、APIに対してプログラミングをすることになります。 APIはデータ型/構造体、定数、関数などで構成されており、あなたのコードでその外部コンポーネントの機能にアクセスするために使用することができます。

ABIもこれとよく似ています。 API のコンパイル版(または機械語レベルの API)と考えてください。 ソースコードを書くとき、APIを通じてライブラリにアクセスします。 コードがコンパイルされると、アプリケーションはABIを通じてライブラリ内のバイナリデータにアクセスします。 ABIは、コンパイルされたアプリケーションが外部ライブラリにアクセスするために使用する構造とメソッドを定義します(APIが行ったのと同じように)、ただし下位のレベルで。 APIは、関数に引数を渡す順序を定義します。 ABIでは、次のような仕組みを定義します。 どのように これらの引数が渡される(レジスター、スタックなど)。 APIは、どの関数がライブラリの一部となるかを定義します。 ABIは、ライブラリのコードをライブラリファイル内にどのように格納するかを定義し、ライブラリを使用するすべてのプログラムが必要な関数を探して実行できるようにします。

ABIは、外部ライブラリを使用するアプリケーションに関して重要です。 ライブラリはコードやその他のリソースでいっぱいですが、プログラムはライブラリファイルの中から必要なものを探し出す方法を知っていなければなりません。 ABIは、ライブラリのコンテンツがファイル内にどのように格納されるかを定義し、プログラムはABIを使用してファイル内を検索し、必要なものを見つけます。 システム内のすべてのものが同じABIに準拠していれば、どのプログラムも、誰が作ったかに関係なく、どのライブラリ・ファイルでも動作させることができるのです。 Linux と Windows は異なる ABI を使っているので、Windows プログラムは Linux 用にコンパイルされたライブラリにアクセスする方法を知らないでしょう。

ABIの変更はやむを得ない場合もあります。 このような場合、そのライブラリを使用するプログラムは、新しいバージョンのライブラリを使用するように再コンパイルされない限り、動作しなくなります。 ABIが変更されてもAPIが変更されない場合、新旧のライブラリのバージョンを「ソース互換性」と呼ぶことがあります。 これは、一方のライブラリバージョン用にコンパイルされたプログラムは他方のライブラリバージョンでは動作しないが、一方のために書かれたソースコードは再コンパイルすれば他方のために動作することを意味する。

このため、開発者はABIを安定させようとする傾向があります(混乱を最小限に抑えるため)。 ABIを安定させるとは、関数のインターフェイス(戻り値の型と数、引数の型と順序)、データ型やデータ構造の定義、定義された定数などを変更しないことです。 新しい関数やデータ型を追加することは可能ですが、既存のものはそのままでなければなりません。 例えば、ライブラリが32ビット整数で関数のオフセットを示していた場合、64ビット整数に変更すると、そのライブラリを使用する既にコンパイル済みのコードは、そのフィールド(またはそれに続くもの)に正しくアクセスできなくなります。 データ構造のメンバへのアクセスはコンパイル時にメモリアドレスとオフセットに変換されますが、データ構造が変更されると、これらのオフセットはコードが期待するものを指さないことになり、結果はせいぜい予測不能になります。

ABIは、非常に低レベルのシステム設計作業をしない限り、必ずしも明示的に提供するものではありません。 例えば、C言語のアプリケーションとPascalのアプリケーションは、コンパイル後に同じABIを使用することができるため、言語固有のものではありません。

編集する SysV ABIドキュメントのELFファイルフォーマットに関する章についてのご質問ですが、SysV ABIドキュメントのELFファイルフォーマットに関する章は、以下の通りです。 この情報が含まれている理由は、ELFフォーマットがオペレーティングシステムとアプリケーションの間のインターフェイスを定義しているからです。 例えば、バイナリの最初のセクションは、特定のメモリオフセットにある特定の情報を含むELFヘッダであることが期待されます。 このようにして、アプリケーションはそれ自身に関する重要な情報をオペレーティングシステムに伝達するのです。 もし、ELF以外のバイナリ形式(a.outやPEなど)でプログラムをビルドした場合、ELF形式のアプリケーションを期待するOSは、バイナリファイルを解釈することも、アプリケーションを実行することもできないでしょう。 これは、再コンパイルするか、あるバイナリ形式から別の形式に変換できる何らかのエミュレーション層で実行しない限り、WindowsアプリケーションをLinuxマシンで直接実行できない(またはその逆)大きな理由の1つです。

IIRCでは、現在Windowsは ポータブル実行ファイル (または、PE)形式です。 PEフォーマットについては、Wikipediaのquot;external links"のセクションにリンクがあります。

また、C++の名前の間違いについてのご指摘について。 ライブラリファイルの中で関数を探す場合、その関数は通常、名前で検索されます。 C++では関数名をオーバーロードすることができるため、名前だけでは関数を特定することができません。 C++コンパイラは、内部的にこの問題に対処するための独自の方法を持っています。 ネームマングリング . ABIは、異なる言語やコンパイラで作られたプログラムが必要なものを見つけられるように、関数名をエンコードする標準的な方法を定義することができます。 例えば extern "c" は、他のソフトウェアが理解できる標準的な名前の記録方法を使用するようにコンパイラに指示していることになります。