2012-03-21 14 views
8

オブジェクトモジュール内の静的スコープ で関数をオーバーライドする方法はありますか?オブジェクトモジュール(gcc、ld、x86、objcopy)の静的関数を無効にすることはできますか?

私はこのような何かを始める場合は、グローバル・シンボル「foo」という持つモジュール は、ローカル・シンボル「バズ」

[[email protected] ~]$ cat foo.c 
#include <stdio.h> 
static void baz(void) 
{ 
    printf("baz\n"); 
} 

static void bar(void) 
{ 
    printf("bar\n"); 
    baz(); 
} 

void foo(void) 
{ 
    printf("foo\n"); 
    bar(); 
} 

[[email protected] ~]$ gcc -g -c foo.c 
[[email protected] ~]$ objdump -x foo.o | egrep 'foo|bar|baz' 
foo.o:  file format elf32-i386 
foo.o 
00000000 l df *ABS* 00000000 foo.c 
00000000 l  F .text 00000014 baz 
00000014 l  F .text 00000019 bar 
0000002d g  F .text 00000019 foo 

それが1つを持って呼び出す「バー、」 ローカルシンボルを呼び出す関数でありますグローバル、 "foo"と2人のローカル "bar"と "baz"。

私にできること 、私はバーやバズを行使し、いくつかのユニットテストを書きたいとしよう:

[[email protected] ~]$ cat barbaz 
bar 
baz 
[[email protected] ~]$ objcopy --globalize-symbols=barbaz foo.o foo2.o 
[[email protected] ~]$ objdump -x foo2.o | egrep 'foo|bar|baz' 
foo2.o:  file format elf32-i386 
foo2.o 
00000000 l df *ABS* 00000000 foo.c 
00000000 g  F .text 00000014 baz 
00000014 g  F .text 00000019 bar 
0000002d g  F .text 00000019 foo 
[[email protected] ~]$ 

そして今、バー、バズは、モジュールの外部 からグローバルシンボルとアクセスできます。ここまでは順調ですね。

しかし、自分自身の機能を "baz"の の上に置きたいのであれば、 "bar"は私の介入された "baz"を呼びますか?

これを行う方法はありますか?

--wrapオプションは

[[email protected] ~]$ cat ibaz.c 
#include <stdio.h> 
extern void foo(); 
extern void bar(); 

void __wrap_baz() 
{ 
    printf("wrapped baz\n"); 
} 
int main(int argc, char *argv[]) 
{ 
    foo(); 
    baz(); 
} 

[[email protected] ~]$ gcc -o ibaz ibaz.c foo2.o -Xlinker --wrap -Xlinker baz 
[[email protected] ~]$ ./ibaz 
foo 
bar 
baz 
wrapped baz 
[[email protected] ~]$ 

メイン()ラップしまったから呼び出さバズ...それを行うには思えませんが、 バーはまだローカルバズないラップバズを呼び出します。

バーをラップしたbazに電話する方法はありますか?

関数呼び出しのアドレスを使ってオブジェクトコードを変更する必要がある場合でも、自動化された方法で行うことができれば、十分に良いかもしれませんが、少なくともi386とx86_64。

- スティーブ

+0

私はまだ弱い記号を使用していませんが、元のモジュールの弱化しているような音が新しく交換されます。 – x539

+0

彼がそのようなことをしようとすると、彼はソースにアクセスできないコード –

+0

私はソースコードにアクセスできますが、通常の単体テスト方法でソースを変更したくないです。実際には、これはLinuxカーネルモジュールをテストするためのものです。アップストリームでは、カーネルではないものを扱うだけでソースに変更を加えるのが大好きで、パッチの互換性のために、ソースを不必要に混乱させたくありません。 – smcameron

答えて

3

staticは、関数や変数がファイルにローカルなCコンパイラへの約束ですので、それはそれなしで同じ結果を得ることができる場合、コンパイラは、そのコードを削除して自由です。

これは、関数呼び出しをインライン展開している可能性があります。これは、変数を定数で置き換えることを意味します。コードが常にfalseのifステートメント内にある場合、その関数はコンパイルされた結果に存在しないことさえあります。

これはすべて、その関数に確実にリダイレクトすることができないことを意味します。

新しい-ltoオプションを使用してコンパイルすると、コンパイラがプロジェクト全体のコードをすべて並べ替え、削除、またはインライン化することができるため、さらに悪化します。

+0

私はコンパイルによってインライン展開します-fno-inlineを指定します。私が関心を持っている関数は、コンパイラによって完全に削除されているわけではありません(そうでなければ、私はすでに自分自身を削除してしまいました)。私は対処できないコーナーケースがあるかもしれませんが、それは問題ありません。私は典型的なケースにもっと興味があります。私はこの目的を達成するためにコールサイトでマシンコードを機械的に変更することに反対しているわけではなく、単にそれを行う方法を理解する必要があります。 – smcameron

1

私はイアン・ランス・テイラー(金の著者、LDの代替リンカ)からのメールを受け取った:

は、オブジェクトモジュール内の静的スコープ で機能を無効にする方法はありますか? (私はx86_64とi386 linuxにあります)

いいえ、ありません。特に、コンパイラはstatic 関数をインラインで呼び出すことがあり、また、別の 呼び出し規約を使用するように関数を書き換えることもあります(GCCはこれらの最適化を両方とも行います)。したがって、コードが にコンパイルされた後に、 という静的関数をオーバーライドする信頼できる方法はありません。

インライン展開は-fno-inlineで扱うことができますが、呼び出し規約を変更するのはおそらく多すぎます。あなたがマシンコードを変更すると大丈夫です場合、あなたは何の問題修正、ソースコードを持っていないはず https://groups.google.com/forum/?fromgroups#!topic/dynamorio-users/xt8JTXBCZ74

0

:言われて、DynamoRIOの連中はそれを行うことができると主張するが、私はそれを確認していないことを

実際のソースからユニットテストソースを機械的に生成するスクリプトを作成します。 Perlはこれを非常にうまく行います。

関連する問題