アプリケーションバイナリインターフェイス (ABI) は、コンパイルされたコードを他のコンパイル済みのコードと組み合わせられるように、そのコードが従う規則の集まりです。組み合わせとは、プログラムとそれが呼び出すライブラリ、C と手書きのアセンブリ、あるコンパイラーの出力と別のコンパイラーの出力などです。C 規格はこうした詳細を各プラットフォームに委ねており、x86-64 と x86 のプラットフォームは少数の ABI に落ち着きました。ABI ごとにこのサイトのページがあり、その ABI を使うすべてのプラットフォームを挙げています。

ABI が決めること

データレイアウト
各型のサイズとアラインメント、したがって構造体がどうパディングされるかです。long は Linux では 8 バイト、Windows では 4 バイトなので、1 つの構造体宣言が 2 つの異なるレイアウトを表すことがあります。
呼び出し規約
引数と結果をどのレジスターまたはスタックスロットで渡すか、呼び出された関数がどのレジスターを変更せずに返さなければならないか、呼び出し時にスタックをどうアラインするか、printf のような可変長引数関数が自分の引数をどう見つけるかです。
スタックフレームとアンワインド
デバッガー、プロファイラー、例外ハンドラーが、ある関数からその呼び出し元へどうたどるかです。
システムコール
どの命令でカーネルに入るか、システムコール番号とその引数をどこに置くかです。
オブジェクトファイルとリンク
ファイル形式 (ELF、PE/COFF または Mach-O)、再配置、シンボル名をどう装飾するか、コードがスレッドローカル変数にどうアクセスするかです。
C++
名前修飾 (name mangling)、仮想関数テーブルのレイアウト、this の渡し方、例外がスタックをどうアンワインドするかです。

ELF システムでは、System V ABI のプロセッサー補足 (psABI) がこのほとんどを定めています。x86-64 psABI は型のサイズから ELF の再配置やアンワインドテーブルまでを扱い、Linux のシステムコールについての参考情報の章もあります。Microsoft は Windows 向けの規約を文書化しており、Apple は macOS が x86-64 psABI と異なる点を文書化しています。

同じ C コードを見ると違いがわかります。リスト 1 は、2 つの小さな関数を 3 つの ABI 向けにコンパイルしたものです。

同じ 2 つの関数を System V x86-64、Microsoft x64、System V i386 向けにコンパイルしたもの

every-abi.c

/* Two functions, compiled for every ABI: where do the arguments
   arrive, and where does the result go? */
long diff(long a, long b)
{
	return a - b;
}

double axpy(double a, double x, double y)
{
	return a * x + y;
}

GCC 14.2.0 (Debian 14.2.0-19) x86_64-linux-gnu

AT&T 構文 gcc-14 -O2 -fno-asynchronous-unwind-tables -S every-abi.c

diff:
        movq    %rdi, %rax
        subq    %rsi, %rax
        ret

axpy:
        mulsd   %xmm1, %xmm0
        addsd   %xmm2, %xmm0
        ret

Intel 構文 gcc-14 -O2 -fno-asynchronous-unwind-tables -masm=intel -S every-abi.c

diff:
        mov     rax, rdi
        sub     rax, rsi
        ret

axpy:
        mulsd   xmm0, xmm1
        addsd   xmm0, xmm2
        ret

Clang 23.1.2 x86_64-pc-windows-msvc

AT&T 構文 clang --target=x86_64-pc-windows-msvc -O2 -fno-asynchronous-unwind-tables -S every-abi.c

diff:
        movl    %ecx, %eax
        subl    %edx, %eax
        retq

axpy:
        mulsd   %xmm1, %xmm0
        addsd   %xmm2, %xmm0
        retq

Intel 構文 clang --target=x86_64-pc-windows-msvc -O2 -fno-asynchronous-unwind-tables -masm=intel -S every-abi.c

diff:
        mov     eax, ecx
        sub     eax, edx
        ret

axpy:
        mulsd   xmm0, xmm1
        addsd   xmm0, xmm2
        ret

GCC 14.2.0 (Debian 14.2.0-19) i386-linux-gnu

AT&T 構文 gcc-14 -m32 -march=i686 -mtune=generic -O2 -fno-asynchronous-unwind-tables -S every-abi.c

diff:
        movl    4(%esp), %eax
        subl    8(%esp), %eax
        ret

axpy:
        fldl    4(%esp)
        fmull   12(%esp)
        faddl   20(%esp)
        ret

Intel 構文 gcc-14 -m32 -march=i686 -mtune=generic -O2 -fno-asynchronous-unwind-tables -masm=intel -S every-abi.c

diff:
        mov     eax, DWORD PTR 4[esp]
        sub     eax, DWORD PTR 8[esp]
        ret

axpy:
        fld     QWORD PTR 4[esp]
        fmul    QWORD PTR 12[esp]
        fadd    QWORD PTR 20[esp]
        ret

System V x86-64 では、diff の 2 つの long 引数は RDI と RSI で渡され、結果は RAX で返ります。Microsoft x64 はこれらを RCX と RDX で渡し、そこでは long が 32 ビットしかないため、コードは ECX、EDX、EAX を操作します。32 ビットの i386 ABI は両方をスタックで渡し、戻りアドレスのすぐ上に置きます。axpy の 3 つの double 引数は、どちらの 64 ビット ABI でも XMM0 から XMM2 で渡され、結果は XMM0 で返ります。i386 はこれらもスタックで渡し、結果は x87 のレジスタースタックの ST0 で返します。

これらのページのリストはすべて、実際のコンパイラーの出力です。使ったのは Clang 23.1.2、GCC 14.2.0 (Debian 14.2.0-19) と MinGW-w64 GCC 14.2.0 (Debian 14.2.0-19+27+b1) で、それぞれ正確なバージョンに固定し、出力を生成したコマンドとともに示しています。AT&T と Intel のボタンですべてのリストの構文が切り替わり、その選択は記憶されます。サイトのテストは各リストを再びコンパイルし、出力が変わっていれば失敗します。

どのプラットフォームがどの ABI を使うか

プラットフォームとその ABI。データモデルは long とポインターの幅を表します。名前の説明は表 2 にあります。
プラットフォームABIデータモデルページ
Linux、Android、FreeBSD、NetBSD、OpenBSD、DragonFly BSD、illumos と Solaris、HaikuSystem V x86-64 psABILP64System V x86-64
Intel プロセッサーの macOSx86-64 psABI (Apple が文書化した相違点あり)LP64System V x86-64: macOS
Linux x3232 ビットポインターの x86-64 psABIILP32System V x86-64: x32
MSVC、clang-cl、MinGW-w64 を使う Windows、MSYS2 の UCRT64 環境と CLANG64 環境Microsoft x64LLP64Microsoft x64
x64 の UEFI ファームウェアMicrosoft x64MSVC または Clang の UEFI ターゲットでは LLP64Microsoft x64
Cygwin、MSYS2 の MSYS 環境Microsoft x64 呼び出し規約LP64Microsoft x64
32 ビットの Linux、BSD 系、AndroidSystem V i386 psABIILP32System V i386
MSVC、clang-cl、MinGW-w64 を使う 32 ビット Windowscdecl、stdcall、fastcall、thiscall、vectorcallILP32Windows x86

いくつかの行には説明が必要です。

  • UEFI ファームウェアは、そのサービスを Microsoft x64 規約で呼び出します。リファレンス実装である EDK II は、GCC や Clang で x64 向けにビルドするとき、すべてのインターフェイス関数に GCC と Clang の ms_abi 属性を付けます。また Clang の x86_64-unknown-uefi ターゲットは、Microsoft のレジスターと型のサイズでコンパイルします。
  • Cygwin と、Cygwin の上に構築された MSYS2 の MSYS 環境は、Windows の呼び出し規約を保ちつつ Linux の LP64 モデルを使うため、long は 64 ビットです。UCRT64 や CLANG64 など MSYS2 のほかの環境は、Microsoft の C ランタイムと Windows のデータモデルを使います。
  • Intel プロセッサーの macOS は、Apple が文書化した少数の相違点を除いて x86-64 psABI に従います。相違点は System V のページに挙げています。Apple は macOS Catalina 以降、32 ビットの Intel コードをサポートしていないため、表には macOS の 32 ビットの行がありません。

データモデル

x86 と x86-64 プラットフォームのデータモデル: 整数型とポインターのビット幅
モデルintlonglong longポインター採用先
LP6432646464System V x86-64、Cygwin、MSYS2 の MSYS 環境
LLP6432326464Microsoft x64
ILP3232326432Linux x32 とすべての 32 ビット x86 プラットフォーム

LP64 と LLP64 の名前は、64 ビットの型を並べたものです。long とポインター、または long long とポインターです。ILP32 は 32 ビットの型、つまり int、long、ポインターを並べています。long long はどこでも 64 ビットです。ポインターを整数に保持するコードは、long ではなく、どのプラットフォームでも収まる intptr_t または uintptr_t を使うべきです。long は 64 ビット Windows では収まりません。

C の型のサイズ

表 3 と表 4 は、C の基本型のサイズとアラインメントを、各プラットフォームのコンパイラーから見たとおりに示します。これらの表のどのプラットフォームでも _Bool と char は 1 バイト、short は 2 バイト、int と float は 4 バイトで、char は符号付きです。表ではこれらの型を省いています。

64 ビットプラットフォームでの C の型のサイズ (バイト)。アラインメントがサイズより小さい場合は、スラッシュの後に示します。
型System V x86-64AndroidLinux x32WindowsMinGW-w64Cygwin, MSYS2
データモデルLP64LP64ILP32LLP64LLP64LP64
long884448
long long888888
__int128161616161616
void *884888
double888888
long double16161681616
long double の形式x87 80-bitbinary128x87 80-bitbinary64x87 80-bitx87 80-bit
wchar_t444222
va_list24 / 824 / 816 / 4888
各列のプラットフォームとコンパイラー
System V x86-64
Linux, FreeBSD, NetBSD, OpenBSD, DragonFly BSD, illumos and Solaris, Haiku, macOS。x86_64-linux-gnu 向けの GCC 14.2.0 (Debian 14.2.0-19); x86_64-linux-gnu、x86_64-unknown-freebsd14、x86_64-unknown-netbsd10、x86_64-unknown-openbsd7、x86_64-unknown-dragonfly、x86_64-pc-solaris2.11、x86_64-unknown-haiku と x86_64-apple-macos11 向けの Clang 23.1.2 で測定しました。
Android
Android on x86-64。x86_64-linux-android 向けの Clang 23.1.2 で測定しました。
Linux x32
Linux x32。x86_64-linux-gnux32 向けの GCC 14.2.0 (Debian 14.2.0-19); x86_64-linux-gnux32 向けの Clang 23.1.2 で測定しました。
Windows
Windows with MSVC or clang-cl, UEFI。x86_64-pc-windows-msvc と x86_64-unknown-uefi 向けの Clang 23.1.2 で測定しました。
MinGW-w64
Windows with MinGW-w64 GCC or Clang。x86_64-w64-mingw32 向けの MinGW-w64 GCC 14.2.0 (Debian 14.2.0-19+27+b1); x86_64-w64-windows-gnu 向けの Clang 23.1.2 で測定しました。
Cygwin, MSYS2
Cygwin and the MSYS2 msys environment。x86_64-pc-cygwin と x86_64-pc-msys 向けの Clang 23.1.2 で測定しました。
32 ビットプラットフォームでの C の型のサイズ (バイト)。表記は表 3 と同じです。
型System V i386AndroidWindowsMinGW-w64
データモデルILP32ILP32ILP32ILP32
long4444
long long8 / 48 / 488
__int128––––
void *4444
double8 / 48 / 488
long double12 / 48 / 4812 / 4
long double の形式x87 80-bitbinary64binary64x87 80-bit
wchar_t4422
va_list4444
各列のプラットフォームとコンパイラー
System V i386
Linux and FreeBSD on i386。i386-linux-gnu 向けの GCC 14.2.0 (Debian 14.2.0-19); i686-linux-gnu と i686-unknown-freebsd14 向けの Clang 23.1.2 で測定しました。
Android
Android on x86。i686-linux-android 向けの Clang 23.1.2 で測定しました。
Windows
Windows with MSVC or clang-cl。i686-pc-windows-msvc 向けの Clang 23.1.2 で測定しました。
MinGW-w64
Windows with MinGW-w64 GCC or Clang。i686-w64-mingw32 向けの MinGW-w64 GCC 14.2.0 (Debian 14.2.0-19+27+b1); i686-w64-windows-gnu 向けの Clang 23.1.2 で測定しました。

数値は、各型の sizeof と _Alignof を各プラットフォームのコンパイラーでコンパイルし、その結果をアセンブリから読み取ったものです。各列は、その表の下に挙げたすべてのターゲットで測定しており、結果が食い違うとサイトのビルドが失敗します。

long double
プラットフォーム間で最も違いが大きい型です。System V の ABI、MinGW-w64、Cygwin は x87 の 80 ビット形式を使い、x86-64 では 16 バイトに、32 ビット x86 では 4 バイトにアラインされた 12 バイトに格納します。x86-64 の Android は代わりに 128 ビットの IEEE 形式を使い、MSVC、UEFI、32 ビット x86 の Android では long double は double と同じです。
32 ビット x86 での double と long long
System V はこれらを 4 バイトに、Windows は 8 バイトにアラインするため、int と double からなる構造体は 32 ビット Linux では 12 バイト、32 ビット Windows では 16 バイトになります。
wchar_t
System V のプラットフォームでは 4 バイト、Windows と Cygwin では 2 バイトです。
va_list
Windows と 32 ビット x86 ではポインターですが、System V x86-64 では 24 バイトの構造体 (x32 では 16 バイト) です。可変長引数関数の引数が、渡されたときのレジスターにまだ残っている場合があるためです。
__int128
x32 を含め、ここで挙げたすべての 64 ビットプラットフォームで使え、32 ビットのプラットフォームではどれでも使えません。Windows では Clang の型です。MSVC 独自の整数型は 64 ビットまでです。

ABI ごとのページ

ABI ごとに 1 ページあり、その ABI を使うすべてのプラットフォームを挙げています。

ABI を比較するページ:

出典

  1. System V Application Binary Interface, AMD64 Architecture Processor Supplement, version 1.0: コミット e1ce098331da、2025-03-12
  2. System V Application Binary Interface, Intel386 Architecture Processor Supplement, version 1.2: コミット 20ec676cd56d、2025-08-24
  3. Microsoft Learn: Overview of x64 ABI conventions: コミット f70d88cd5da7、2026-09-24
  4. Microsoft Learn: Data type ranges: コミット f70d88cd5da7、2026-09-24
  5. Microsoft Learn: Argument passing and naming conventions: コミット f70d88cd5da7、2026-09-24
  6. Apple Developer: Writing 64-bit Intel code for Apple Platforms: 2026-09-25 の公開版
  7. Cygwin User's Guide: Building applications for 64 bit Cygwin: 2026-09-25 の公開版
  8. MSYS2 documentation: Environments: コミット 9879735eb93f、2026-05-14
  9. EDK II: BaseTools/Conf/tools_def.template: コミット 2970e5699ba6、2026-08-12
  10. Clang 23.1.2: clang/lib/CodeGen/Targets/X86.cpp: コミット 85ac56026243、2026-09-20