9

オブジェクトモジュール内の静的スコープで関数をオーバーライドする方法はありますか?

このようなものから始めると、グローバルシンボル「foo」を持つモジュールは、ローカルシンボル「bar」を呼び出す関数であり、ローカルシンボル「baz」を呼び出します。

[scameron@localhost ~]$ 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();
}

[scameron@localhost ~]$ gcc -g -c foo.c
[scameron@localhost ~]$ 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」があります。

バーとバズを実行する単体テストを作成したいとします。次のことができます。

[scameron@localhost ~]$ cat barbaz
bar
baz
[scameron@localhost ~]$ objcopy --globalize-symbols=barbaz foo.o foo2.o
[scameron@localhost ~]$ 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
[scameron@localhost ~]$ 

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

しかし、「baz」の上に自分の関数を挿入し、「bar」に挿入した「baz」と呼ばせる場合はどうなりますか?

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

--wrapオプションはそれを行わないようです...

[scameron@localhost ~]$ 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();
}

[scameron@localhost ~]$ gcc -o ibaz ibaz.c foo2.o -Xlinker --wrap -Xlinker baz
[scameron@localhost ~]$ ./ibaz
foo
bar
baz
wrapped baz
[scameron@localhost ~]$

main()から呼び出されたbazはラップされましたが、barはラップされたbazではなくローカルbazを呼び出します。

バーにラップされたバズを呼び出させる方法はありますか?

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

-スティーブ

4

3 に答える 3

4

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

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

つまり、呼び出しをその関数に確実にリダイレクトすることはできません。

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

于 2012-03-21T16:55:36.163 に答える
2

Ian Lance Taylor (ld の代替リンカである gold の作成者) からメールを受け取りました。

オブジェクト モジュール内で静的スコープを持つ関数をオーバーライドする方法はありますか? (私は x86_64 および i386 Linux を使用しています)

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

インライン化は -fno-inline で処理できると思いますが、呼び出し規約を変更するのはおそらく多すぎます。

そうは言っても、DynamoRIO の連中はそれができると主張していますが、私はそれを確認していません: https://groups.google.com/forum/?fromgroups#!topic/dynamorio-users/xt8JTXBCZ74

于 2012-03-22T14:05:50.187 に答える
0

マシンコードの変更に問題がない場合は、ソースコードの変更に問題はありません。

実際のソースから単体テストソースを機械的に生成するスクリプトを記述します。Perlはこれを非常にうまく行っています。

于 2012-03-26T19:02:30.987 に答える