非常に特別な問題が発生しました。VMの場合、コードを命令関数からubyte配列にコピーしてから、この配列を実行する必要があります(この手法は、gccのインラインマクロvmと同様です)。基本的には、次のように機能します。
__gshared void * sp = null, sb = null; //stack pointer and stack base
__gshared void add() //the function is just there to access the instruction code
{
asm{db "INSTRUCTIONCODESTART";} //this is a key to know where the instruction code starts
//instruction code here (sample instruction add, pops 2 values from the stack and pushes its result)
sp += 4;
*cast(uint*)sp += *cast(uint*)(sp - 4);
asm{db "INSTRUCTIONCODEEND";} //this is a key to know where instruction code ends
}
Initメソッドでは、すべての命令コードが独自のバッファーを取得し、バッファーには、INSTRUCTIONCODESTARTキーとINSTRUCTIONCODEENDキーの間のすべてのバイトがあります。この配列をWindowsのVirtualProtect呼び出しで実行可能にします。
これまでのところ、すべてが期待どおりに機能しますが、関数呼び出しを命令として実行しようとすると、エラーが発生します。
__gshared void testcall(){}
__gshared void call()
{
asm{db "INSTRUCTIONCODESTART";} //this is a key to know where the instruction code starts
//instruction code here (just calls a D function)
testcall(); //this somehow throws an error
asm{db "INSTRUCTIONCODEEND";} //this is a key to know where instruction code ends
}
ところで、私は次のコードで命令をテストしました
void instructiontest()
{
uint dummy;
ubyte[] buf = getFunctionCode(&add) ~ 0xC3; //gets code of instruction, appends 0xC3 at it ("ret" instruction, for test purposes only to see if it returns to the D code without errors)
VirtualProtect(cast(void*)buf, buf.length, PAGE_EXECUTE_READWRITE, &dummy); //makes it executeable
dummy = cast(uint)&buf[0];
asm
{
call dummy[EBP];
}
print("instruction worked without errors!");
}
これまでのところ、すべての単純な命令(add、mul、sub、push0、push1、...)は機能しますが、関数呼び出しを使用して命令のコードを取得しようとすると、エラーがスローされます
私はどんな助けでも幸せでとても感謝しています。(ところで、スクリプト言語がDと通信できるようにするには、命令に関数呼び出しが必要です)