2

私はこれを持っています...奇妙な問題と私は必死に解決策を探しています。

この例があります:(32ビットシステム用に作成)

#include <stdio.h>

//unsigned foo(unsigned arg_a, unsigned arg_b) {
unsigned foo(unsigned arg_a, ...) {
        unsigned *temp = (unsigned *)((unsigned)&arg_a + 4);
        return *temp + arg_a;
}

int main(void) {
        int i = foo(0xbe00, 0x00af);
        printf("We got a %x\n", i);
        return 0;
}

関数fooには2つの引数があります。目標は、arg_aのアドレスに基づいてarg_bのアドレスを「推測」することです。これは、呼び出し元(main)がarg_aとarg_bをスタックにプッシュするという仮定に基づいています(したがって、(int)&arg_b-(int)&arg_a == 4)。

コンパイラーと最適化レベルに応じて、出力は次のように異なります。

 gcc -g -Wall -O0 test.c
 ./a.out 
We got a beaf
 gcc -g -Wall -O1 test.c
 ./a.out 
We got a beaf
 gcc -g -Wall -O2 test.c
 ./a.out 
We got a 80542b0
 gcc -g -Wall -O3 test.c
 ./a.out 
We got a 80542b0
 clang -g -Wall -O0 test.c
 ./a.out 
We got a 8054281
 clang -g -Wall -O1 test.c
 ./a.out 
We got a 805423f
 clang -g -Wall -O2 test.c
 ./a.out 
We got a b768d9d6
 clang -g -Wall -O3 test.c
 ./a.out 
We got a b76899d6

(この例は非常に不安定で、たとえばfooの中にprintfを入れると、gccは常に「Wegotabeaf」を出力します。Clang..ではありません。)

上記の例は、明確にするための私の方法です。

私の本当の質問(および私の目標)は次のとおりです。arg_aの元のアドレス、つまり、foo関数内からCLANGを使用して、呼び出し元(メイン)がスタックに0xbe00をプッシュしたアドレスを抽出するにはどうすればよいですか?(gccはオプションではありませんが、それでも興味深いです)

お時間をいただきありがとうございます!

編集:質問がより意味をなすようにfooを可変個引数にしました...

4

3 に答える 3

4

要するに、そうしないでください。

あなたがしているのは未定義の振る舞いです。のアドレスが必要な場合はarg_b、を記述し&arg_bます。でポインタトリックを使用して取得しようとするとarg_a、Cのエイリアシングルールのために機能しません。コンパイラーは、特定のポインターが相互にエイリアスしないと想定しているため、オプティマイザーは、それを行うと真ではなくなった想定を行います。その結果、コードが正しく機能しません。

于 2012-10-04T18:11:34.393 に答える
0

私はこれがあなたのために働くことはないと思います。

まず、gccがコンパイラーである場合、標準Cライブラリーをプルしてみませんか?それをしたくない場合は、標準の実装からstdarg.hだけを取得するのはどうでしょうか。

私が見ているstdarg.hのバージョン(Windowsではgcc 4.4.0に付属)は、基本的にコンパイラービルトインを呼び出すマクロの集まりです-コンパイラーに適切なものがあれば、それは簡単なはずです、標準ライブラリの残りの部分を使用しなくても(私はその混乱全体を引き込むことに抵抗があることを理解できます)。

それでも問題が解決しない場合は、作成している関数に可変個引数のマークを付けて、コンパイラのドキュメントでスタックの構築方法を確認してください。プラットフォームによっては、アセンブラのスニペットを作成する必要があるかもしれませんが、関数を可変個引数として宣言することにより、コンパイラに予測可能な方法でスタックを構築させることができます。

コンパイラが関数への可変引数をサポートしていない場合は、他のオプションを再検討することをお勧めします。

于 2012-10-04T18:50:51.123 に答える
0

あなたがしていることは未定義の振る舞いをもたらします。

...(から)オプションの引数にアクセスする適切な方法はva_list、からva_start()、、、va_arg()およびva_end()マクロを使用すること<stdarg.h>です。

これらのマクロの使用例は数多くあり、オンラインで簡単に見つけることができます。

ここでは推測作業は許可されていません。

于 2012-10-05T05:03:17.973 に答える