読者です 読者をやめる 読者になる 読者になる

呼び出し規約

常に忘れるよ

x86

EAX, ECX, EDX は破壊して良し。逆に言うと EBX, EDI, ESI は保存すること。

引数はスタックで後ろから順に。

浮動小数返す時は FPU のスタックトップを使う。渡す時は普通にスタック上で。

linuxシステムコールは EAX, EBX, ECX, EDX に突っ込む。 int 0x80 か sysenter で入る。

x86_64

RAX, RCX, RDX, RSI, RDI, R8-11 は破壊可。 RBX, R12-15 は callee で保存。 SSE レジスタは破壊していい。

引数は RDI, RSI, RDX, RCX, R8, R9 で残りはスタック。

RDI と RSI が破壊可になってるんだなぁという。

浮動小数は SSE レジスタでやりとり。 xmm0 で返して、引数は後ろから順に xmm0, 1, ...

linuxシステムコールも似た呼び出し規約っぽい。 RAX にシステムコール番号をつっこんで、引数は関数呼び出しと同じ。呼び出す時は int 0x80 じゃなくて syscall を使う。なんかシステムコール番号は 32bit と 64bit で違うので注意。

あと int 0x80 で呼ぶと 32bit のルールに従うぽい。 sysenter はなんか SEGV するんだが。

あと重要なのは AX や AL と違って、 EAX に書き込むと RAX の上位がクリアできるってことかな。おかげで命令長短くなったり。

参考になった: http://www.milw0rm.com/papers/110

大きなオブジェクトとかは…まぁとりあえずいいや。

いやなコード

/* float.c */
void f(float f, double d, int i) {
    printf("%f\n", f + d + i);
}

/* float_main.c */
void f(int i, float f, double d);

int main() {
    f(1, 2, 3);
}

を用意して両方一緒にコンパイルx86_64 だと結果は 6.0 だけど、 x86 だと 1074266112.0 だった。

なにかあれば下記メールアドレスへ。
shinichiro.hamaji _at_ gmail.com
shinichiro.h