Phase 3: C連携 / ABI

このフェーズでは、Cとアセンブリの境界を扱います。実務では「コンパイラ出力を読める」「呼び出し規約を守れる」ことが必須です。

SysV AMD64 ABI(Linux)要点

項目ルール
整数引数rdi, rsi, rdx, rcx, r8, r9 の順
戻り値rax(必要に応じて rdx
callee保存rbx, rbp, r12-r15 を関数内で破壊しない
stack整列関数呼び出し時に16byte整列

Cとアセンブリの往復確認

Cコードをアセンブリへ変換して読む

gcc -O0 -g -S sample.c -o sample.s
less sample.s

オブジェクト逆アセンブルで対応を見る

gcc -O0 -g sample.c -o sample
objdump -d -M intel sample | less

最適化差分の観察

gcc -O0 -S sample.c -o o0.s
gcc -O2 -S sample.c -o o2.s
diff -u o0.s o2.s | less

inline asm(最小)

int add_inline(int a, int b) {
  int out;
  __asm__ volatile (
    "addl %[b], %[a]"
    : [a] "=r" (out)
    : "0" (a), [b] "r" (b)
    : "cc"
  );
  return out;
}

volatile、出力制約、破壊リスト(clobber)を必ず明示します。

演習(実務寄り)

  1. 関数の引数がどのレジスタに載るかを逆アセンブルで確認する
  2. callee保存レジスタを壊した時の不具合を再現する
  3. -O0-O2 の差分で最適化意図を説明する
  4. inline asm で誤ったclobber指定を行い、再現して修正する