19

仮想マシンはどのようにしてネイティブ マシン コードをオンザフライで生成し、実行するのでしょうか?

発行したいネイティブ マシン オペコードが何かを把握できると仮定すると、実際にそれを実行するにはどうすればよいでしょうか。

ニーモニック命令をバイナリコードにマッピングし、それを char* ポインターに詰め込み、関数としてキャストして実行するのと同じくらいハックですか?

それとも、一時的な共有ライブラリ (.dll や .so など) を生成し、次のような標準関数を使用してメモリにロードしますLoadLibraryか?

4

7 に答える 7

8

プログラムカウンターが実行したいコードを指すようにするだけです。データはデータまたはコードであることに注意してください。x86 では、プログラム カウンターは EIP レジスタです。EIP の IP 部分は、命令ポインターを表します。JMP 命令は、アドレスにジャンプするために呼び出されます。ジャンプ後、EIP にはこのアドレスが含まれます。

ニーモニック命令をバイナリコードにマッピングし、それを char* ポインターに詰め込み、関数としてキャストして実行するのと同じくらいハックですか?

はい。これは 1 つの方法です。結果のコードは、Cの関数へのポインターにキャストされます。

于 2008-09-05T08:15:05.247 に答える
6

ニーモニック命令をバイナリコードにマッピングし、それを char* ポインターに詰め込み、関数としてキャストして実行するのと同じくらいハックですか?

はい、C または C++ (または同様のもの) でそれを行っていた場合、それはまさにあなたが行うことです。

ハックに見えますが、これは実際には言語設計の成果物です。使用する実際のアルゴリズムは非常に単純です。使用する命令を決定し、それらをメモリ内のバッファーにロードし、そのバッファーの先頭にジャンプします。

ただし、これを実際に実行しようとする場合は、C プログラムに戻ったときに、呼び出し規則が正しいことを確認してください。コードを生成したい場合は、その側面を処理してくれるライブラリを探すと思います。Nanojit は最近ニュースになっています。あなたはそれを見ることができます。

于 2008-09-16T00:42:11.200 に答える
4

うん。char* を作成して実行するだけです。ただし、いくつかの詳細に注意する必要があります。char* はメモリの実行可能セクションにある必要があり、適切に配置されている必要があります。

nanojit に加えて、さまざまなプログラム表現を関数ポインターにコンパイルできる別のライブラリーである LLVM をチェックアウトすることもできます。インターフェースはきれいで、生成されたコードは効率的です。

于 2008-09-18T10:43:17.477 に答える
1

私の知る限り、コードを最適化するためにいくつかのヒューリスティックを実行する必要があるため(つまり、時間の経過とともにインライン化する)、メモリ内のすべてをコンパイルしますが、Shared Source Common Language Infrastructure 2.0ローター リリースを見ることができます。コードベース全体は、Jitter と GC を除いて .NET と同じです。

于 2008-09-05T08:14:54.543 に答える
1

DLL の生成について: そのために必要な追加の I/O、リンク、および DLL 形式の生成の複雑さにより、DLL 形式がさらに複雑になり、何よりもパフォーマンスが低下します。さらに、最終的には、ロードされたコードへの関数ポインターを呼び出すので... また、JIT コンパイルは一度に 1 つのメソッドで実行できます。それを行う場合は、多数の小さな DLL を生成することになります。

「実行可能セクション」の要件については、POSIX システムで mprotect() を呼び出すと、パーミッションを修正できます (Win32 にも同様の API があります)。そうしないと遅すぎるため、メソッドごとに1回ではなく、大きなメモリセグメントに対してこれを行う必要があります。

通常の x86 では問題に気付かないでしょうが、PAE を搭載した x86 または 64 ビット AMD64/Intel 64 ビット マシンでは、segfault が発生します。

于 2009-01-15T00:32:48.927 に答える
1

ニーモニック命令をバイナリコードにマッピングし、それを char* ポインターに詰め込み、関数としてキャストして実行するのと同じくらいハックですか?

はい、うまくいきます。

Windows でこれを行うには、割り当てられたブロックに PAGE_EXECUTE_READWRITE を設定する必要があります。

void (*MyFunc)() = (void (*)()) VirtualAlloc(NULL, sizeofblock,  MEM_COMMIT, PAGE_EXECUTE_READWRITE);

//Now fill up the block with executable code and issue-

MyFunc();
于 2010-07-01T18:29:59.590 に答える
1

Rotor 2.0 だけでなく、OpenJDKのHotSpot 仮想マシンも確認できます。

于 2008-09-16T00:23:58.497 に答える