著作一覧 |
SWinをRuby-1.9.1-RC1で動かそうとしていろいろやっていたが、すぐさまSEGVする。で、パッチを作ったりしたのだが、良く良く雪見酒さんの日記を読んだら、7月の時点でわかっていた問題だったようだ。
dlの方法は、次々defineしていくという方法でびっくりするような、あともう少しでCで書くDSLという雰囲気。
で、別の方法について考えてみると、これの応用かなぁとか。つまり、引数としてではなく、自動変数に設定した値を引数として与えるという方法。
#include実行するとint x(int r, int p, int q, int a, int b, int c, int d) { printf("%d, %d, %d, %d\n", a, b, c, d); return 0; } int main(int argc, char* argv[]) { int i; int a[] = { 0, 1, 2, 3, 4 }; int (*fnc)(int[]); fnc = (int (*)(int[]))x; fnc(a); for (i = 0; i < sizeof(a)/sizeof(a[0]); i++) { a[i] += 10; } fnc(a); return 0; }
c:\test\farproc>acall 0, 1, 2, 3 10, 11, 12, 13
一回スタック調整用の関数を呼び出し、そこでスタックから戻りアドレスを取り出して、次に引数に与えた本来呼び出すべき関数のアドレスを取り出して、そこへ戻りアドレスを設定して、本来呼び出すべき関数のアドレスへジャンプとか。
試してみる。
#include#include int __stdcall y(int a, int b, int c, int d) { printf("%d, %d, %d, %d\n", a, b, c, d); fflush(stdout); return 0; } __declspec(naked) int x(void* v) { _asm { pop ebx // return pop eax // fn* push ebx jmp eax } } int ccaller(void* fnc, int cnt, void* args) { void* p = _alloca(cnt * sizeof(int)); memcpy(p, args, sizeof(int) * cnt); return x(fnc); } int main(int argc, char* argv[]) { int i; int a[] = { 0, 1, 2, 3, 4, 5 }; ccaller(y, 4, a); for (i = 0; i < sizeof(a)/sizeof(a[0]); i++) { a[i] += 10; } ccaller(y, 4, a); return 0; }
さて、うまく動いているようだが。
c:\test>cl bcall.c Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86 Copyright (C) Microsoft Corp 1984-1998. All rights reserved. bcall.c Microsoft (R) Incremental Linker Version 6.00.8447 Copyright (C) Microsoft Corp 1992-1998. All rights reserved. /out:bcall.exe bcall.obj c:\test>bcall 0, 1, 2, 3 10, 11, 12, 13
問題は__declspec(naked)
でフレームを作らないようにしているわけだが、他の処理系で使えるのかなぁ。逆に作らせるようにして、espで調整するというのもありだろうが、最適化フラグいじったとたんになくなったりするかも知れないのが問題。
ジェズイットを見習え |