私はいくつかのプロセス間通信をいじっていますが、関数を共有メモリにコピーして、そこからいずれかのプロセスから実行できるかどうかに興味があります。
何かのようなもの:
memcpy(shared_memory_address, &func, &func + sizeof(func));
関数のサイズを取得できないことはわかっていますが、それが頭に浮かびました。
私はいくつかのプロセス間通信をいじっていますが、関数を共有メモリにコピーして、そこからいずれかのプロセスから実行できるかどうかに興味があります。
何かのようなもの:
memcpy(shared_memory_address, &func, &func + sizeof(func));
関数のサイズを取得できないことはわかっていますが、それが頭に浮かびました。
それは楽しかった。
しかし、それはできるようです。私は決してこれをしませんが:
Windows 7 を実行している lenovo:T61p でコンパイル: g++ 4.3.4 を使用
一部のタイプのハードウェアでは、ハードウェア メモリ マップ ファイルで読み取り専用としてマークされている特定のメモリ領域 (プログラム領域) からのみコードを実行できるため (自己変更コードを防止するため)、これが防止されることに注意してください。
関数のタイプが非常に限られていることにも注意してください。
この例では、 func() はほとんど実行しないため、機能します。
ただし、次のいずれかを行うと、別のプロセスに移植できなくなります。
あるプロセスのアドレス空間は別のプロセスのアドレス空間と似ていないため、上記のいずれも機能しません (ハードウェアレベルで物理メモリにマップされるため)。
#include <vector>
#include <iostream>
#include <string.h>
int func(int x)
{
return x+1;
}
typedef int (*FUNC)(int);
int main()
{
std::vector<char> buffer(5000);
::memcpy(&buffer[0],reinterpret_cast<char*>(&func),5000);
FUNC func = reinterpret_cast<FUNC>(&buffer[0]);
int result = (*func)(5);
std::cout << result << std::endl;
}
理論的には、関数はメモリ内のどこかにあるバイト コードのシーケンスにすぎないため、関数のメモリ ブロックをコピーして呼び出す (ジャンプする) ことができます。C++ ではその可能性を抽象化していますが、お気づきのように、実際には関数のサイズを知ることはできません (関数へのポインターを取得することはできます)。
それでも、ライブラリがあります。たとえば、動的ライブラリから特定の関数をロードして実行するようにリモート実行可能ファイルに指示できます。参考文献については、ウィキペディアの記事を確認してください。
前回これを試したとき、関数内のバイト数の決定という障害に遭遇しました。タスクは、関数のアドレスを使用し、バイトをメモリにコピーすることです (コードが位置独立コード (PIC) としてコンパイルされている場合)。
よりプラットフォームに依存しない方法は、コンパイラのドキュメントを調べて#pragma
、ロード時にロードする関数のアドレスまたはセグメントを指定できる 、コンパイラ オプション、またはキーワードがあるかどうかを確認することです。
また、Embedded Systems グループを検索してください。これは一般的な手法です。フラッシュ メモリを RAM にプログラムするコードをロードし、RAM で関数を実行してから、システムをリセットします。
それが役立つことを願っています。
編集:
提案: アセンブリ言語ファイルまたはリンカへの指示 (ビルド スクリプト内) を使用して、データまたはコード セグメントを作成します。関数を別のコード ファイルに入れます。コンパイラとリンカーに、この関数を新しいコード セグメントにコンパイルするように指示します。セグメントの開始アドレスとサイズを取得するコンパイラ固有のステートメントがある場合があります。また、OS が指定されたアドレスにセグメントをロードできる場合もあります。
また、OS の助けを借りて、実行時にロードできる DLL または共有ライブラリも調べてください。
はい。同様の手法が、JavaVMなどのジャストインタイムコードジェネレーターで使用されます。実際、オペレーティングシステムのランタイムローダーとリンカーは、ダイナミックライブラリをプロセスにロードするときに、これを実行していると言っても過言ではありません。
ただし、オペレーティングシステムに実行可能メモリを要求する必要があります。また、ジャンプするコードは、メモリ内のどこにでも配置できるように記述する必要があります(位置に依存しません)。
そのようなことを試みると、実行可能コードを含むはずのないメモリからコードを実行する際に問題が発生する可能性があります。詳細については、このウィキペディアの記事を参照してください: http://en.wikipedia.org/wiki/Executable_space_protection
コード バイトを生成してプロセスに挿入する場合、それは ランタイム コード生成 (RTCG)と呼ばれます。いくつかの例を調べる ことができます。
最新のカーネルでは、非特権レベルからはこれが機能しないため、最初に正しいモードに入るかリングする必要があります。コードサイズを見つけるには、(もちろん)関数のバイトをカウントする必要があります。これは、最後のリターンコードまでのコードセグメントです。
Afaik グラフィックス ドライバーは、オンザフライでラスター演算用のコードを作成するときに RTCG を使用することがありました (問題によって異なります)。
Linux、Windows、またはより高度な組み込みオペレーティングシステムでは、これはまったく不可能であると合理的に想定できます。
しかし、そのような厄介な制限で操作していない場合は、関数の開始/終了を示すアセンブリ内のいくつかのガードバイトにパッチを適用し、それらを使用して共有メモリにデータをコピーして(もちろんアセンブリを使用して)公開することができます関心のあるプロセスへのプロシージャアドレスのリスト(アセンブリを使用したアクセス/実行も)。
もちろん、LinuxとWindowsが提供するダイナミックライブラリシステムである、複数のプロセスにコードのライブラリを提供するための明確に定義されたメカニズムがあります。おそらくあなたが望むほど柔軟ではありません。:-)