呼び出し規約

常に忘れるよ

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 だった。

タネ

http://d.hatena.ne.jp/turing_pattern/20080523/1211547863

宣言と実装で引数の順番が違う、ってのはまぁわかると思います。

関数を呼ぶ時にどこ通るかって話で、 x86 では整数の浮動小数もスタックなる場所を通るんだけど、 x86_64 では整数と浮動小数が違う場所を通る。だから順番を変えても正しく動いてしまう。一方 x86 は、順番通りに渡ってしまうので、 1 を float と解釈して、 2.0f を double と解釈して、 3.0 を int として解釈して…ってことが起きて、

irb(main):015:0> [3.0].pack('d').unpack('ii')
=> [0, 1074266112]

というような理由で件の数値が。

sevilwm-0.9.5

http://shinh.skr.jp/sevilwm/

id:mtkh さんに再起動時に引数保持するパッチをいただいたので。ていうか 0.9.3 とかも全然アナウンスしてないみたいだ。 ignore を腐らせてたのを mtkh さんに教えていただいて修正したのが 0.9.3 で、 click focus 時のリサイズ時にフォーカス変わっちゃう問題を修正していただいたのを取り込んだのが 0.9.4 みたいだ。非常に助かってます。ありがとうございます。

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