Rubyからマシン語を直接呼ぶ

Ruby1.9のDLで。

require 'DL'

str = "\xb8\xff\x7f\x00\x00\xc3" # mov eax, 0x7fff : ret
i = [str].pack("P").unpack("l!")[0]
cfunc = DL::CFunc.new(i, DL::TYPE_INT)

p cfunc.call([]) #=> 32767

文字列としてバイナリを直接生成して、そのポインタをDLに渡して呼び出せば、マシン語のコードを呼ぶことができる。
WindowsにはDEPというデータ領域実行保護機能があるが、とりあえずXPのSP2以降はシステムしか保護されていないので動く。Linuxとかの場合はなんかフラグをいじったりする必要があるらしいがよくわからない。

こういうプログラムが動くかどうかはRubyの実装に強く依存する。たとえばStringオブジェクトの文字列が独自領域に取られてGCの際にコンパクションされたりするとアドレスが変わるので怪しいことになる。つまりこのような改善提案が受け入れられるとはじめは動くがGCが走るとアドレスを取得しなおさない限りコケることになる。→http://www.is.titech.ac.jp/~sassa/lab/papers-written/08M37090-oota.pdf

なんしかバイナリ直接生成で呼び出すことができるのなら、Rubyインラインアセンブラが作れる可能性が出てくる。Rubyで書けば外部にアセンブラコンパイラもいらない。といっても別に目新しいものではなくて、ytljitとかが既にある。→https://github.com/miura1729/ytljit/wiki/

これで何かをしようと言う話ではなくて、できるかな?と思ってやってみたらできた。という話。でした。