

アプリケーションバイナリインターフェース(ABI)とは、ソフトウェアによって公開されるインターフェースであり、プロセス内マシンコードへのアクセス用に定義されています。多くの場合、公開するソフトウェアはライブラリであり、利用する側はプログラムです。
ABIは比較的低い抽象度レベルにあります。インターフェースの互換性は、ターゲットハードウェアとソフトウェアビルドツールチェーンに依存します。一方、アプリケーションプログラミングインターフェース(API)は、ソースコードへのアクセスを定義します。ソースコードは比較的高レベルで、ハードウェアに依存せず、人間が読みやすい形式です。APIはコンパイル前のソースコードレベルでインターフェースを定義するのに対し、ABIはコンパイル済みコードへのインターフェースを定義します。
APIの互換性は、一般的にシステム設計やツールチェーンにおいて重要な考慮事項です。しかし、プログラマーは、複数の言語でプログラムを作成する場合や、同じ言語に対して複数のコンパイラを使用する場合に、 ABIを直接扱う必要が生じる場合があります。
完全なABIがあれば、そのABIをサポートするプログラムは、そのABIを提供する複数のオペレーティングシステム上で、変更を加えることなく実行できます。ターゲットシステムは、必要なライブラリ(ABIを実装するもの)をすべて提供する必要があり、その他にも前提条件がある場合があります。
ABIが対象とするインターフェースの側面には以下が含まれます。
setjmp/ longjmp)ABIの例としては、廃止されたIntel Binary Compatibility Standard (iBCS) [ 3 ]、多くのUnix系システムで使用されているさまざまな命令セットアーキテクチャ (ISA) 用のSystem V Release 4 ABI、およびさまざまなISA用のMicrosoft Windows ABI [ 4 ]などがあります。
組み込みオペレーティングシステムで使用される組み込みABI(EABI)は、組み込みソフトウェアプログラムのファイル形式、データ型、レジスタの使用方法、スタックフレームの構成、関数パラメータの受け渡しなどの側面を規定します。
EABIをサポートする各コンパイラおよびアセンブラは、他の同様のコンパイラおよびアセンブラによって生成されたコードと互換性のあるオブジェクトコードを生成します。これにより、開発者はあるコンパイラによって生成されたライブラリと、別のコンパイラによって生成されたオブジェクトコードをリンクさせることができます。
通常、EABI は、ターゲット組み込みシステムの限られたリソースでのパフォーマンスを最適化するように設計されています。そのため、EABI では、デスクトップオペレーティングシステムでよく見られるカーネルとユーザー空間間の抽象化を省略する場合があります。たとえば、動的リンクを回避して実行可能ファイルを小さくし、ロードを高速化したり、固定レジスタの使用によりスタックとカーネル呼び出しをよりコンパクトにしたり、特権モードでアプリケーションを実行したりすることで、デバイス ドライバを呼び出すという間接的な操作なしにカスタム ハードウェア操作に直接アクセスしたりすることができます。[ 5 ] EABI の選択はパフォーマンスに影響を与える可能性があります。[ 6 ] [ 7 ]
広く使われている EABI にはPowerPC [ 5 ] 、Arm [ 8 ]、MIPS EABI [ 9 ]などがあります。Cライブラリなどの特定のソフトウェア実装では、より具体的な ABI を形成するために追加の制限が課される場合があります。たとえば、ARM 用の GNU OABI と EABI があり、どちらも ARM EABI のサブセットです。[ 10 ]もう 1 つの区別点は、ハードウェア浮動小数点などのオプション機能が存在するかどうかです。たとえば、GCC と LLVM ではarmv7-unknown-linux-musleabi、どちらもmuslarmv7-unknown-linux-musleabihf C ライブラリを使用した GNU EABI を参照していますが、後者はハードウェア浮動小数点を使用するため、呼び出し規約が若干異なります。[ 11 ]
各プログラミング言語は、それぞれ異なる機能セットとデータ型を使用する場合があります。ある機能に対応する既存のABIが存在しない場合、多くの場合、言語は既存のABIを拡張する形で独自のABIを定義する必要があります。
C プログラミング言語の公式 Web サイトでは、C は外国語関数インターフェース(FFI: 異なるプログラミング言語間の関数呼び出し)における共通語であると説明されています。 [ 12 ]多くの言語は、Rust や C++ のように、C ABI に基づいて FFI を定義しています。[ 13 ]これは、Unix 系と Windows の両方を含む、現在のほとんどすべてのオペレーティングシステムが、合意された C ABI を提供しているためです。これらのシステム自体は主に C API を提供しており、その API は機能するために C ABI に依存しているため、C ABI は広く普及しています。[ 14 ] (さらに、C は他の言語と比較して、ABI 規則に要求するものが比較的少なく、データ構造のレイアウトと呼び出し規約の定義のみを必要とします。) [ 15 ]extern "C"
しかしながら、Cはもともとこの役割を果たすように設計されたものではなく、ABIはFFIとしての多くの欠点が指摘され、批判を受けてきた。
移植可能な C++ ABI は存在しません。同じオペレーティングシステム上でも、異なるコンパイラ (またはコンパイラと標準ライブラリの実装の組み合わせ) は異なる ABI を使用する可能性があります。[ 13 ]ほとんどの C++ ABI は C ABI の拡張であり、不足している名前マングリング(関数オーバーロードに必要) と例外処理の詳細を補完します。現代のシステムでは、主に 2 つのスキームが見られます。Microsoft の Visual C++ スキームと Itanium スキームです。[ 1 ]
ABI ドキュメントは識別子を名前に変換するルールを定義していますが、標準ライブラリの ABI サーフェス全体を定義するものではなく、特定の標準ライブラリの実装に委ねられています (以下の「ライブラリ ABI」のセクションを参照)。結果として、各実装は独自の ABI を持ちます。同じアーキテクチャとオペレーティングシステムであっても、互換性のない ABI を持つ標準ライブラリにリンクすると、2 つのオブジェクト ファイルの ABI が異なってしまいます。[ 13 ] 2015 年に、GCC/libstdc++ は の実装を改訂しstd::string、ABI の変更につながりました。新しいライブラリは両方の ABI をサポートしていますが、ユーザーは古い ABI と新しい ABI のどちらかを選択する必要がありました。これは、プログラムがリンクできるプリコンパイル済みライブラリを決定するためです。[ 17 ]同様に、Visual C++ は、異なるバージョンのコンパイラ (異なるバージョンのランタイム ライブラリを対象とする) によって生成されたコードをリンクする場合の互換性を保証していません。[ 18 ]
上記のように、「ABI」ドキュメントは、APIがアセンブリ言語レベルで具体的な形式に変換される方法を記述しています。ライブラリの場合、「ABI」という用語は、ABIの変換によって得られる具体的なインターフェースを指します。[ 19 ] 例えば、関数の型シグネチャを直接的または間接的に変更すると(例えば、関数で使用される構造体の定義を変更するなど)、多くの場合、ABIが互換性を失うほど変更され、「ABIブレーク」が発生します。[ 20 ] [ 21 ]
オペレーティングシステムにはプログラマが使用するライブラリが多数含まれているため、その ABI にはライブラリの ABI も含まれます。たとえば、Linux Standard Base仕様には、特定のライブラリのシンボル テーブルに何を含めるべきか、それらがどの API に対応しているか、SysV ABI を使用する必要があるかなどの詳細が含まれています。[ 22 ]このような区別はコンパイラやその他のコード ジェネレータにとって重要です。GCC と LLVM の場合、各オプションには ターゲット トリプルと呼ばれる名前が付けられています。(標準ライブラリの実装の選択も ABI に影響します。たとえば、ARMv7 GNU EABI 用の musl とuClibc、および x64 Windows 用の libstdc++ とMicrosoft Visual C++はそれぞれ異なるトリプルを持っています。)[ 11 ]
厳密に言えば、旧ARM ABIと新ARM ABIはどちらもARM EABI仕様のサブセットですが、日常的な使用では、ここで説明する新しいものを「EABI」、古いものを「OABI」または「old-ABI」と呼びます。