ABIとは何か?APIとの違いや重要性をわかりやすく解説
ソフトウェア開発においてよく耳にする ABI(Application Binary Interface:アプリケーション・バイナリ・インターフェース)。
この記事では、ABIとは何か、APIとの違い、そして実際のシステムでどのように影響するのかをわかりやすく解説します。
✅ ABIとは?
ABIとは、バイナリレベル(機械語レベル)でプログラム同士がどのように連携するかを定義したインターフェースです。具体的には以下のような内容を含みます。
- 関数呼び出しの方法(引数の渡し方、戻り値の取り扱い)
- 構造体やデータ型のメモリ配置
- 使用するレジスタの規則
- システムコールのインターフェース
🔄 APIとの違い
| 項目 | API | ABI | 
|---|---|---|
| レベル | ソースコードレベル | バイナリ(実行形式)レベル | 
| 利用対象 | 開発者がコードを書くときに使用 | 実行時にプログラムとライブラリが連携 | 
| 互換性の影響 | コンパイル時 | 実行時に互換性が必要 | 
⚠️ なぜABIが重要なのか?
ソフトウェアを動かす上で、ABIの互換性は非常に重要です。たとえば、Linuxのglibc(Cライブラリ)を新しいバージョンに置き換えた際にABIが壊れていた場合、多くのアプリケーションが実行時にクラッシュしたり、予期せぬ挙動を示す可能性があります。
また、ディストリビューション間でバイナリパッケージを配布する際にも、ABIの安定性は互換性を保つための鍵になります。
🧪 実例:glibcのABI破壊
過去にはglibcの更新によってABIの一部が変更され、一部のバイナリが動作しなくなるといった問題を経験した人もいるでしょう。このような事例では、パッケージ管理システムが依存関係を正確に把握していなければ、システム全体の動作に影響を及ぼします。
👨💻 開発者が意識すべきこと
- 共有ライブラリ(.so)の変更時はABI互換性に注意
- 構造体のサイズや順序を変更する際は注意
- 公開ライブラリでは意図しないABIの変更を防ぐため、ABIチェックツールを活用する
確認方法
abipkgdiffは、2つのRPMパッケージの中に含まれるELFバイナリ(共有ライブラリや実行ファイルなど)を解析し、ABIの互換性に違いがあるかを自動でチェックするコマンドラインツールです。
abipkgdiff --d1 glibc-old/glibc-debuginfo-2.28-151.el8.x86_64.rpm --d2 glibc-2.4/glibc-debuginfo-2.4-3.x86_64.rpm glibc-old/glibc-2.28-151.el8.x86_64.rpm glibc-2.4/glibc-2.4-3.x86_64.rpm 上記のようにglibcのあるバージョンを例にコマンドを実行すると、内部に含まれる.soファイルやシンボルの変更を検出し、追加・削除・変更された関数や構造体などを表示します。
出力例(一部):
================ changes of 'libc-2.28.so'===============
  Functions changes summary: 133 Removed (84 filtered out), 43 Changed (350 filtered out), 0 Added (2 filtered out) functions
  Variables changes summary: 2 Removed (3 filtered out), 2 Changed (18 filtered out), 0 Added (2 filtered out) variables
  Function symbols changes summary: 24 Removed (4 filtered out), 0 Added function symbols not referenced by debug info
  Variable symbols changes summary: 0 Removed, 0 Added variable symbol not referenced by debug info
  133 Removed functions:
    [D] 'function int __asprintf_chk(char**, int, const char*, ...)'    {__asprintf_chk@@GLIBC_2.8}
    [D] 'function int __clock_getcpuclockid(pid_t, clockid_t*)'    {clock_getcpuclockid@GLIBC_2.2.5, aliases clock_getcpuclockid@@GLIBC_2.17}
    [D] 'function int __clock_getres(clockid_t, timespec*)'    {clock_getres@GLIBC_2.2.5, aliases clock_getres@@GLIBC_2.17}
    ...
  43 functions with some indirect sub-type change:
    [C] 'function size_t _IO_default_xsgetn(FILE*, void*, size_t)' at genops.c:416:1 has some indirect sub-type changes:
      parameter 1 of type 'FILE*' has sub-type changes:
        in pointed to type 'typedef FILE' at libio.h:337:1:
          typedef name changed from FILE to _IO_FILE at libio.h:337:1
          underlying type 'struct _IO_FILE' at struct_FILE.h:49:1 changed:
            type size hasn't changed
            3 data member changes (3 filtered):
              type of '_IO_marker* _markers' changed:
...
  2 Removed variables:
    [D] 'const char* const _sys_errlist_internal[135]'    {sys_errlist@@GLIBC_2.12, aliases sys_errlist@GLIBC_2.2.5, sys_errlist@GLIBC_2.3, sys_errlist@GLIBC_2.4, _sys_errlist@GLIBC_2.3, _sys_errlist@GLIBC_2.4, _sys_errlist@@GLIBC_2.12, _sys_errlist@GLIBC_2.2.5}
    [D] 'const int _sys_nerr_internal'    {_sys_nerr@@GLIBC_2.12, aliases sys_nerr@@GLIBC_2.12}
...
================ changes of 'libSegFault.so'===============
  Functions changes summary: 0 Removed, 0 Changed, 0 Added function
  Variables changes summary: 0 Removed, 0 Changed, 1 Added variable
  Function symbols changes summary: 0 Removed, 2 Added function symbols not referenced by debug info
  Variable symbols changes summary: 0 Removed, 0 Added variable symbol not referenced by debug info
  1 Added variable:
    [A] 'const char __invoke_dynamic_linker__[28]'    {__invoke_dynamic_linker__}
  2 Added function symbols not referenced by debug info:
    [A] _fini
    [A] _init
...
  ✅ まとめ
ABIは、実行可能なプログラム同士が安全かつ安定して連携するために不可欠な存在です。APIと違い、開発者の目には見えにくい部分ですが、システムの信頼性や移植性に大きな影響を与えます。ライブラリの設計や更新時には、ABIの維持・管理を意識することが重要です。

 
  
  
  
  

コメント