ABIひさしぶりにプログラミングの話題でも。DLdlモジュールというのは(僕は知らなかったのだが)RubyからCのコードを直接呼ぶためのしくみで、引数をpackとunpackを使ってlongの配列にしておくと、なぜか関数の型に関わらず正しい結果がかえって来るという魔法のライブラリである。sin(π/2)が1.0にならなかったら、バグだよね。}まず、RubyのArray(ary)をCのArray(stack[])に変換する。CALLCASEマクロで量産している。\それをrubyのfloatオブジェクトに変換して返す。いうことをしているのだと分かる。実装の詳細を見るためにDLSTACK_PROTO1DECL_FUNC_CDECLDLSTACK_ARGS1のマクロ定義も見ていこう。(あ、今回は引数1つなので##nは1になる。CALL_CASEマクロをもう一度みると納得できると思います。cfunc->ptr;となる。*/つまり、x86_64では...を特別扱いするから、これでうまくいくんだよ。\はf(stack[0]);という普通の関数呼び出しになる。NO_CLASSという引数のタイプがあるよ。order.超訳レジスタが足りなくなったらスタックを使って引数を渡すよ。何個SSEレジスタを使ったか隠し引数で入れるよ。ここではprintf()的なまっとうな可変長引数の事を語っているだけであって、呼び出し元と呼び出し先で関数の型が適合しない場合については何も語っていない。...)という型だと思ってcallしている。実際に何が起こるかを示すためにテストプログラムを書いてみた。返ってくるはずが0が返ってきてしまいました。retqfuncでは素直にxmm0を引数だと思って二倍しています。eaxに0を入れて関数コールしています。これが起きていることのすべてです。呼び出し側がrdiに引数を詰んでいるのに、呼び出され側はxmm0を呼んでいるのですから正しい答えが返るはずがありません。いうわけで、これはdlモジュール制作者のABIの誤読ですね。Cの規格的には呼び出し元と呼び出し先で関数型が適合しない場合は未定義。dlモジュール作者は規格を元に考えたのではなく1)全CPUアーキテクチャでlongで無理矢理callしても安心と考えた。割り切ったのどちらかだと思いますが、イマドキx86_64は普通ですからねぇ。x86_64対応は出来ないでしょう。doubleを使わないようにしておくと将来幸せになれるかもしれないというお話でした。この問題がx86_64だけで発生するのかを、つらつらと考えてみたのだが、やはり歴史的な理由だろう。関数の型の適合性とか安易に書いた気がする。Cの規格を読み直す気がおきない。戻り値の型は厳密一致が必要だけど、引数は型がshortとintみたいに十分近ければOKみたいなノリだったと思う。ffiDLは長い間メンテされていなくて、yuguiさんはじめコミッタの方々は代替を探しています。編集]実のところ、dlを使いたいという要求はまったくなくて、たんにtest-allが通らないのが悔しいので深追いしてみただけなのでした。代替案を提示されても、あんまり御利益がなかったり。編集]x86-64のABIはきちんと決まっているよね。仕様をみる限り、できるだけレジスタ渡しにしておけばスタックの消費も少ないし、速いよ、というのと、浮動小数点レジスタがない可能性があるx86-32と違って、初めから浮動小数点を渡す専用レジスタがあるんだからそれを使おう、という考えなのではないかと。作るフェイズではライブラリエクスポートされるかどうかの知識はまったくないので、普通に呼んだら同じ事が起きるのではないかと。編集]ちょうど今日、DLの実装が割とごっそり(libffiを利用するように)入れ替わったらしいので、再度test-allしてみると、x86_64でなにか進展があるかもしれません。skin:cuteblogリサーチ無料アクセス。