2011-06-24 3 views
2

私は関数ポインタが呼び出されるコードを書いています。私がしたいのは、この関数呼び出しをして何かを行い、同じ引数でanother関数呼び出しを呼び出すことです。私がターゲットとしている各アーキテクチャのアセンブリを書く必要なく、これを行うための方法があるのだろうかと思います。おそらく、いくつかのGCCのトリックがありますか?C - アーキテクチャに依存しない関数呼び出しの介入

例として、私は私の関数ポインタを呼び出すと、これはかなり簡単ですアセンブリで

foo (/*arguments*/) { 
    do_something... 
    bar(/*same arguments*/); 
} 

を起動します。少なくともx86では、私のスタックポインタが私のスタックフレームの先頭にリセットされていることを確認し、ファンクションバー(コールしない)にジャンプします。

EDIT:おそらく例が不明です。ユーザーはfunction barを呼び出すことを期待していますが、代わりに関数fooにリダイレクトしました(私は引数barがどのようなものか分かりません)。渡されたのと同じ引数でbarを呼び出す前に、fooで何かしたい。このようにして、私がfooでやっていることは、barと呼んでいると思うユーザーには分かりません。

+1

可変機能はオプションですか? –

+0

どのように役立つか分かりませんが、私は引数をva_listにラップできますが、送信する前にそれらをアンラップする必要があります。そうでなければ、別の引数がレイアウトされます。 – dschatz

+0

GCCはテールコールを行います。 'return bar(same args)'を書くと 'jmp'で終わります。より少ない引数があってもそれができると確信しています。したがって、あなたは 'bar()'を返すことができ、あなたのargsが邪魔されないことを信頼することができます。私は船積み製品のために頼りにしたいと思っているものではありません... –

答えて

1

libffiソースレベルの介入に必要なすべて(または少なくともほとんど)を行います。

別のオプションは、DynamoRIOまたはPinのような動的バイナリ計測ツールを使用することです。

+0

これらのソリューションは、すべて私が望むよりも重い重さに見えます。 DBIソリューションは、パフォーマンスヒットのために欲しくないと確信しています。また、私はシステムライブラリに依存することはできません。 – dschatz

+0

私はlibffiが静的にリンクできることを確信しています。そして、私はあなたが実際にどれほど多くの "体重"やパフォーマンスがヒットするかを試してみるべきだと思います。もちろん、自分の車輪を発明することもできます。 –

+0

DynamoRIOとPinの両方を使用していますが、このプロジェクトには適していません。 libffiには、自分の環境にはないシステムライブラリが含まれています(必要ないはずです)。 – dschatz

2

gccオプション-finstrument-functionsをご覧ください。

+0

残念ながら私はコンパイル時にインスツルメンテーションする関数にアクセスすることはできません。関数を別々に計測したいと思います。 – dschatz

1

2つの関数呼び出しを相互に事前バインドするルックアップとして使用されるグローバル関数ポインタ変数を作成できます。例えば、

typedef void (*bar_type)(int arg1, int arg2); 
bar_type function_ptr; //a global function pointer used for binding 

//create a bar_type function that is our "actual" function call 
void __bar(int arg1, int arg2) 
{ 
    //do something else 
} 

//create a bar_type function called "foo" that is bound to calling whatever 
//function is being pointed to by function_ptr 
void foo(int arg1, int arg2) 
{ 
    //do something 
    function_ptr(arg1, arg2); //"foo" now calls "__bar" 
} 

bar_type transform_func(bar_type func_call, bar_type int_call) 
{ 
    function_ptr = func_call; //set the global function ptr variable 
    return int_call; 
} 

//create your function pointer bar that will call "foo" before calling "__bar" 
bar_type bar = transform_func(__bar, foo); 

//later on in your code 
bar(3, 4); //this will call foo() which will then call __bar() internally 

また、このアプローチを使用すると、

のような
#define bar(arg1, arg2) (*(transform_func(__bar, foo)))(arg1, arg2); 

に見えるマクロとしてbarを定義することができ、ユーザのためにうまくいけば、これはあまりにも場しのぎではないことをマクロを作成することができます。..アセンブリで何ができるかによってパフォーマンスが大幅に低下しますが、グローバル関数ポインタを使用すると、関数呼び出しを再バインドすることができます。

+0

"bar_type"タイプがわからないため、これは機能しません。 Barは任意の数の引数を持つ任意の関数である可能性があります。私がタイプを知っていたら、これは実際には問題ではありません。なぜなら、あなたがしたように引数をコピーするだけだからです。 – dschatz

+0

さて、この解決策を聞いて申し訳ありませんが、ご理解いただきありがとうございます。 – Jason

2

gcc固有のものと同じように聞こえる___builtin_apply_argsです。これは渡された引数を取り込むintristicで、__builtin_applyを使用してこれらの引数を持つ別の関数を呼び出すことができます

+0

渡される引数の量がわからないので、これは機能しません。 __builtin_applyを見ると、サイズの値を渡す必要があります。 – dschatz

0

関数のようなマクロを使用して、関数ポインタへの通常の呼び出し? (はい、マクロについての標準的な免責事項、ESP関数のようなマクロが...適用されます。)

例えばのようなもの:

#define CALL_FUNC(fp,ARG1,ARG2) do {<do something>;fp(ARG1,ARG2);} while (0) 

そしてアプリケーションでは、どこのデリファレンス関数ポインタを置き換えますマクロと一緒に。

fooまたはbarが関数ポインタを通じて呼び出される関数なので、元の質問から私には分かりません。したがって、マクロを調整する必要があるかもしれませんが、一般的な方法は変わりません。

関連する問題