関数を呼び出すプラグインを持つ複雑なプログラムに取り組んでいますが、これらの関数のメソッドは起動時に選択され、関数ポインターを使用して割り当てられます。
関数ポインターを渡すのではなく、適切な関数を呼び出すために、メインの実行可能ファイルに効率的なラッパー関数をいくつか用意したいと思います。
これはプラグイン インターフェイス用であるため、呼び出し規約は、__cdecl
または__stdcall
ビルド ターゲットに応じて (マクロを使用して) 定義され、関数は として宣言されextern "C"
ます。
基本的に、プラグインが必要に応じてロードできるように、実行可能ファイルで SYMBOL を宣言できるようにしたいと考えています。複雑な科学的問題を解決するために必要なさまざまなタスクについて、これらのタスクの結果を取得するソリューションまたはメソッドの範囲はさまざまですが、これらはプラグイン自体に保存されるため、新しいメソッドを簡単に追加できます (再コンパイルする必要はありません)。アプリケーション全体) これにより、新しいメソッドを簡単に共有できます。基本コードを持っている人なら誰でも、経験を必要としないプラグインを自分で追加できるからです。
私が考え出したどの方法でも、この概念を使用するか、プラグインをロードするときに関数マップをプラグインに渡す必要がありますが、その関数マップの詳細は、ロードされる構成とプラグインに依存するため、実際にはしません問題になるプラグインのロードが完了するまで、それが何であるかを知ってください。したがって、私の解決策は、マップをグローバル変数のセットとしてメインの実行可能ファイルに保存し、ラッパー関数からアクセスできるようにすることです。
ただし、関数には呼び出し後と戻る前にスタックを操作する呼び出し規則があるため、これは単純ではありません。これはラッパーでは無視する必要があります。また、 intel x386 の関数呼び出しでjmp
はなく、intel x386 ASM の無条件ジャンプを実行する必要があります。 call
ASM と制御は、ジャンプ先の関数から、ラッパーではなく呼び出し元のコードに戻る必要があります。ただし、コンパイラ/プラットフォーム/プロセッサとは無関係にこれを行うには、C/C++ コードが必要です。
以下は、私のアイデアをテストし、私がやりたいことを示すために収集するためにスローする基本的な概念の例です。
C++ コード (Microsoft Visual C++ 2010 (固有))
#include <iostream>
void * pFunc;
int doit(int,int);
int wrapper(int, int);
int main() {
pFunc = (void*)doit;
std::cout << "Wrapper(2,3): " << wrapper(2,3) << std::endl;
std::cout << "doit(2,3): " << doit(2,3) << std::endl;
return 0; }
int doit(int a,int b) { return a*b; }
__declspec(naked) int wrapper(int, int) { __asm jmp pFunc }
コードは正常に動作することがテストされており、両方の呼び出しで 6 が出力されます
ラッパーと doit の ASM 出力
PUBLIC ?wrapper@@YAHHH@Z ; wrapper
; Function compile flags: /Odtp
; COMDAT ?wrapper@@YAHHH@Z
_TEXT SEGMENT
___formal$ = 8 ; size = 4
___formal$ = 12 ; size = 4
?wrapper@@YAHHH@Z PROC ; wrapper, COMDAT
; File c:\users\glen fletcher\documents\visual studio 2010\projects\test_wrapper\test_wrapper.cpp
; Line 15
jmp DWORD PTR ?pFunc@@3PAXA ; pFunc
?wrapper@@YAHHH@Z ENDP ; wrapper
_TEXT ENDS
PUBLIC ?doit@@YAHHH@Z ; doit
; Function compile flags: /Ogtp
; COMDAT ?doit@@YAHHH@Z
_TEXT SEGMENT
_a$ = 8 ; size = 4
_b$ = 12 ; size = 4
?doit@@YAHHH@Z PROC ; doit, COMDAT
; Line 14
push ebp
mov ebp, esp
mov eax, DWORD PTR _a$[ebp]
imul eax, DWORD PTR _b$[ebp]
pop ebp
ret 0
?doit@@YAHHH@Z ENDP ; doit
; Function compile flags: /Ogtp
_TEXT ENDS
ラッパー用非ラッパー ASM
PUBLIC wrapper
_1$ = 8
_2$ = 12
_TEXT SEGMENT
wrapper PROC
push ebp
mov ebp, esp
mov eax, DWORD PTR _2$[ebp]
push eax
mov ecx, DWORD PTR _1$[ebp]
push ecx
call DWORD PTR pFunc
add esp, 8
pop ebp
ret 0
wrapper ENDP
_TEXT ENDS
クロスプラットフォームおよびクロスコンパイラの方法で生成された元のコードを取得するにはどうすればよいですか?? コンパイラによって生成されたエピローグおよびプロローグ コードを使用する C/C++ 関数の標準とは対照的に、注: プロセッサに関する仮定を行いたくないため、別の ASM ファイルを実行できず、コンパイラにコードを生成させたい無条件ジャンプ文だけで。
goto
pFunc はラベルではなく変数であるため機能しませgoto
ん。とにかく関数間で機能するかどうかさえわかりません。