5

アドレスを知っているだけでCの関数を呼び出す必要があり、プロトタイプに関する情報はありません(C関数ポインターにキャストできません)。

この関数に関する情報は、アドレスです。

また、渡したいパラメーター (void ポインターのおかげで) と引数配列のサイズ (void ポインターを介してアクセス) も知っています。

また、C の呼び出し規約も尊重したいと思います。x86 バージョンの場合、私はそれを行う方法をほとんど知っています (スタックにスペースを割り当て、そのスペースにパラメーターをコピーし、最後に関数を呼び出します)。

問題は、パラメーターがレジスターを介して渡される x64 規則 (現時点では Linux のもの) にあります。レジスタを適切に埋めるための各パラメーターのサイズはわかりません。パラメーター配列のサイズしかわかりません。

また、gccに依存したくないので、標準ではないようでかなり暗い__builtin_applyを使用できません。

マルチコンパイラをサポートし、興味深いことを学ぶために、独自のコードを書きたいと思っています。

基本的に、__builtin_apply と同じプロトタイプとして書きたい関数は次のとおりです。

void *call_ptr(void (*fun)(), void *params, size_t size);

また、コードを C (asm inline のおかげで) または純粋な x64 asm で記述したいと考えています。

それで、これを適切に、そして呼び出し規約に関して行う方法はありますか? それとも、呼び出された関数のプロトタイプを正確に知らなければ、x64 規約ではこれは不可能ですか?

4

2 に答える 2

2

特に Linux の x64 呼び出し規約では、これはまったく機能しません。

その理由は、非常に複雑な呼び出し規約にあります。

いくつかの例:

void funcA(float64 x);
void funcB(int64 x);

これら 2 つのケースでは、値 "x" が関数に異なる方法で渡されます。これは、浮動小数点と整数が異なるレジスタで関数に渡されるためです。

void funcC(float64 x,int64 y);
void funcD(int64 y,float64 x);

これら 2 つのケースでは、引数 "x" と "y" の順序が異なります。ただし、それらは同じ方法で関数に渡されます (どちらの関数も "x" に同じレジスタを使用し、"y" に同じレジスタを使用します)。

結論: 目的の関数を作成するには、各引数の引数の型を含む文字列をアセンブラー関数に渡す必要があります。引数の数/サイズは間違いなく十分ではありません。ただし、Linux でのみ動作する必要がある限り、それは間違いなく可能です。

于 2013-08-27T06:06:39.557 に答える