x86 のコードのほぼすべてを 4 つの ABI がカバーしています。Linux、macOS、BSD 系向けの System V x86-64、Windows と UEFI 向けの Microsoft x64、そしてそれらの 32 ビット版である System V i386 と 32 ビット Windows の規約です。32 ビット Windows の規約のうち、表ではデフォルトの __cdecl を示しています。どのプラットフォームがどれを使うかは概要にあります。どの表でも、列はその ABI のページにリンクしています。

引数

表 1 と表 2 は手で入力したものではありません。小さな例の各関数が N 番目の引数を返すようにし、ビルド時に ABI ごとに、引数がどこから来るかを関数の最初の命令から読み取っています。スタックスロットは、関数に入った時点、つまりスタックポインターが戻りアドレスを指しているときのスタックポインターからの相対位置で示します。

最初の 8 個の int 引数が渡される場所 (GCC と Clang の出力から測定)
引数System V x86-64Microsoft x64System V i386Windows x86
1RDIRCXESP+4ESP+4
2RSIRDXESP+8ESP+8
3RDXR8ESP+12ESP+12
4RCXR9ESP+16ESP+16
5R8RSP+40ESP+20ESP+20
6R9RSP+48ESP+24ESP+24
7RSP+8RSP+56ESP+28ESP+28
8RSP+16RSP+64ESP+32ESP+32
最初の 10 個の double 引数が渡される場所 (同じ方法で測定)
引数System V x86-64Microsoft x64System V i386Windows x86
1XMM0XMM0ESP+4ESP+4
2XMM1XMM1ESP+12ESP+12
3XMM2XMM2ESP+20ESP+20
4XMM3XMM3ESP+28ESP+28
5XMM4RSP+40ESP+36ESP+36
6XMM5RSP+48ESP+44ESP+44
7XMM6RSP+56ESP+52ESP+52
8XMM7RSP+64ESP+60ESP+60
9RSP+8RSP+72ESP+68ESP+68
10RSP+16RSP+80ESP+76ESP+76

2 つの 64 ビット ABI の違いはレジスターだけではありません。System V は独立した 2 つの並びを持ちます。整数は 6 つの汎用レジスターのうち次のものを、浮動小数点値は 8 つのベクトルレジスターのうち次のものを、引数の順序に関係なく使います。Microsoft は最初の 4 つの位置それぞれに 1 つのスロットを割り当てます。2 番目の引数は、整数なら RDX に、double なら XMM1 に入ります。また Microsoft のスタック引数は、呼び出し元が確保するシャドウスペース (shadow space) の分だけ、32 バイト上から始まります。32 ビット x86 ではすべての引数がスタックにあり、double は 2 スロットを占めます。

2 番目の引数。一度は int の後の double、もう一度は double の後の int です。System V では、その種類の最初のレジスターである XMM0 または EDI で渡されます。Microsoft x64 では、2 番目のスロットである XMM1 または EDX で渡されます。

mixed-slots.c

/* Mixed arguments: System V fills integer and vector registers from
   separate sequences, Microsoft x64 gives each position one slot. */
double second_double(int a, double b)
{
	return b;
}

int second_int(double a, int b)
{
	return b;
}

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

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

second_double:
        ret

second_int:
        movl    %edi, %eax
        ret

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

second_double:
        ret

second_int:
        mov     eax, edi
        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 mixed-slots.c

second_double:
        movaps  %xmm1, %xmm0
        retq

second_int:
        movl    %edx, %eax
        retq

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

second_double:
        movaps  xmm0, xmm1
        ret

second_int:
        mov     eax, edx
        ret

戻り値

結果が返される場所
値System V x86-64Microsoft x64System V i386Windows x86
整数とポインターRAXRAXEAXEAX
64 ビット整数RAXRAXEDX:EAXEDX:EAX
float、doubleXMM0XMM0ST0ST0
long doubleST0double として XMM0 (MSVC)、メモリ (MinGW-w64)ST0ST0
16 バイトまでの構造体クラスに応じて RAX、RDX、XMM0、XMM11、2、4 または 8 バイトなら RAX、それ以外はメモリLinux はメモリ、FreeBSD と OpenBSD は 1、2、4 または 8 バイトなら EAX、EDX1、2、4 または 8 バイトなら EAX、EDX、それ以外はメモリ
より大きな構造体メモリメモリメモリメモリ
メモリのアドレスRDI、RAX で返すRCX、RAX で返すスタック上、呼び出し先がポップスタック上、呼び出し元に任せる

呼び出し先保存レジスター

呼び出し先保存レジスターは、関数から戻るときに、呼び出されたときと同じ値になっていなければなりません。関数はそのレジスターを使うなら、保存して復元します。ほかのレジスターはすべてスクラッチ (scratch) で、どの呼び出しでも変更される可能性があります。

各 ABI の呼び出し先保存レジスター
System V x86-64Microsoft x64System V i386Windows x86
汎用RBX、RBP、R12 から R15RBX、RBP、RDI、RSI、R12 から R15EBX、ESI、EDI、EBPEBX、ESI、EDI、EBP
ベクトルなしXMM6 から XMM15 の下位 128 ビットなしなし
APX (R16 から R31)なしR30、R3132 ビットモードにはない32 ビットモードにはない
制御状態x87 制御ワード、MXCSR の制御ビット同じ同じ文書化されていない

最初の 2 列の違いは、ABI をまたいで呼び出すときのコストになります。System V のコードから呼び出された Windows の関数が上書きしてよいレジスターに、呼び出し元が保持を期待するものはありません。しかし Windows のコードから呼び出された System V の関数は、RSI、RDI、XMM6 から XMM15 を上書きすることがあり、呼び出し元はそれらが元のまま戻ることを期待しています。それらを保存するコードは Microsoft x64 のページにあります。

構造体、浮動小数点、ベクトル

構造体、浮動小数点値、ベクトルの渡し方
引数System V x86-64Microsoft x64System V i386Windows x86
16 バイトまでの構造体eightbyte ごとに分類: 最大 2 つのレジスター (整数またはベクトル)1、2、4 または 8 バイトならレジスター、それ以外は参照渡しスタック上に値渡しスタック上に値渡し
より大きな構造体スタック上に値渡しコピーへの参照渡しスタック上に値渡しスタック上に値渡し
float、doubleXMM0 から XMM7 のうち次のものXMM0 から XMM3 のうち自分のスロットスタック上スタック上
long doubleスタック上、16 バイトdouble (MSVC)、参照渡し (MinGW-w64)スタック上、12 バイトdouble (MSVC)、スタック上 (MinGW-w64)
__m128XMM レジスター参照渡し最初の 3 つは XMM0 から XMM2XMM レジスター
__m256、__m512名前付き引数で CPU にあれば YMM または ZMM レジスター参照渡し最初の 3 つは YMM0 から YMM2、または ZMM0 から ZMM2__vectorcall では値渡し
SSE の __m128 のような 16 バイトのベクトル。Microsoft x64 以外ではどこでも XMM0 と XMM1 で渡されます。Microsoft x64 は両方を参照で、RCX と RDX で渡します。i386 向けの GCC には -msse2 を与えています。それがない場合のコンパイル対象である i686 には XMM レジスターがないためです。

vector-args.c

/* A 16-byte vector, like SSE's __m128, as argument and result. */
typedef float v4sf __attribute__((vector_size(16)));

v4sf vadd(v4sf a, v4sf b)
{
	return a + b;
}

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

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

vadd:
        addps   %xmm1, %xmm0
        ret

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

vadd:
        addps   xmm0, xmm1
        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 vector-args.c

vadd:
        movaps  (%rcx), %xmm0
        addps   (%rdx), %xmm0
        retq

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

vadd:
        movaps  xmm0, xmmword ptr [rcx]
        addps   xmm0, xmmword ptr [rdx]
        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 -msse2 -S vector-args.c

vadd:
        addps   %xmm1, %xmm0
        ret

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

vadd:
        addps   xmm0, xmm1
        ret

Clang 23.1.2 i686-pc-windows-msvc

AT&T 構文 clang --target=i686-pc-windows-msvc -march=pentium4 -mtune=generic -O2 -fno-asynchronous-unwind-tables -S vector-args.c

_vadd:
        addps   %xmm1, %xmm0
        retl

Intel 構文 clang --target=i686-pc-windows-msvc -march=pentium4 -mtune=generic -O2 -fno-asynchronous-unwind-tables -masm=intel -S vector-args.c

_vadd:
        addps   xmm0, xmm1
        ret

スタック

呼び出し時のスタック
System V x86-64Microsoft x64System V i386Windows x86
呼び出し時のアラインメント16 バイト16 バイト16 バイト4 バイト
呼び出し元が用意する領域なし32 バイトのシャドウスペースなしなし
スタックポインターより下の領域128 バイトのレッドゾーン (red zone)なしなしなし
スタック引数を取り除く側呼び出し元呼び出し元呼び出し元__cdecl では呼び出し元、それ以外は呼び出し先
可変長引数の呼び出し使ったベクトルレジスターの数を AL で示す浮動小数点値をそのスロットの汎用レジスターにも置く追加の処理なし__cdecl のみ

各 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: x64 calling convention: コミット f70d88cd5da7、2026-09-24
  4. Microsoft Learn: Overview of x64 ABI conventions: コミット f70d88cd5da7、2026-09-24
  5. Microsoft Learn: Argument passing and naming conventions: コミット f70d88cd5da7、2026-09-24
  6. Microsoft Learn: __stdcall: コミット f70d88cd5da7、2026-09-24