1

次の短いCプログラム:

void foo(int a, int b) {
        printf("a = %p b = %p\n", &a, &b);
}

main() {
        foo(1, 2);
}

さて、gdb を使用してこのプログラムを表示しました。私は出力として得ました:

a = 0x7fff5fbff9ac b = 0x7fff5fbff9a8

出力後に実行を停止しました(foo()内)。0x7fff5fbff9ac を調べたところ、内容は次のとおりでした。

1....正解

次に 0x7fff5fbff9a8 とコンテンツ:

2...正しい

ここで、関数の戻りアドレスを表示し、(a + 4 バイト) を調べたい:

x/g 0x7fff5fbff9b1 (8 バイト!! アドレス、したがって "g" (巨大な単語))

その内容は次のとおりです。

(gdb) x/g 0x7fff5fbff9b1
0x7fff5fbff9b1: 0xd700007fff5fbff9

しかし、これはメインからのリターン ADR ではありません。私のせいはどこですか?

4

3 に答える 3

3

あなたの質問にはたくさんの誤った仮定があります。

整数引数は、リターンアドレスのすぐ上のスタックで渡されると想定しています(デフォルトの呼び出し規約では、多くの--すべてではない--x86 ABIにあるため)。この場合、呼び出しの直後に、スタックは次のようになります。

// stack frame of main( )
// ...
value of b
value of a
return address <--- stack pointer

しかし、あなたの仮定は正しくありません。コードを64ビットの実行可能ファイルにコンパイルしました(印刷するポインターのサイズから明らかです)。OS X ABIによると、64ビットのIntel実行可能ファイルでは、最初のいくつかの整数引数はスタックではなくレジスタに渡されます。したがって、呼び出しの直後、スタックは実際には次のようになります。

// stack frame of main( )
// ...
return address <--- stack pointer

aとのアドレスを取得するためb、呼び出し前のある時点でスタックに書き込まれますprintf( )(コンパイラが本当にprintf( )賢く、有効なポインタを使用しないため、実際に有効なポインタを渡す必要がないことを認識している場合を除きます)。値は指摘されていますが、最適化が進むにつれてそれはかなり悪いでしょう)、しかしあなたはそれらが差出人住所に対してどこにあるのか本当にわかりません。実際、64ビットABIはレッドゾーンを提供するため、それらがスタックポインターの上にあるか下にあるかさえわかりません。したがって、aとbのアドレスを出力すると、スタックは次のようになります。

// stack frame of main( )
// ...
return address                     |
// ...                             |
// a and b are somewhere down here | <-- stack pointer points somewhere in here
// ...                             |

一般に、C言語標準では、スタックレイアウトについては何も述べられておらず、スタックが必要であるとさえ言われていません。この種の情報は、Cコードから移植可能な方法で取得することはできません。

于 2010-12-09T00:34:57.057 に答える
1

あなたが間違っているのは、与えられたプラットフォーム上のスタックフレームのレイアウトについて、たくさんの間違ったランダムな仮定をしていることです。a + 4おそらく差出人住所を保持している「バイト」の場所について、どこでその奇妙な考えを思いついたのですか?

本当にこれを実行したい場合は、プラットフォームのドキュメントを入手して(またはリバースエンジニアリングを実行して)、差出人住所がどこにどのように正確に保存されているかを確認してください。ランダムな推測を行ってから、ランダムな推測で結果が得られない理由を他の人に尋ねるのは、何らかの理由で期待する結果を正確に実現する方法ではありません。

于 2010-12-09T00:39:44.600 に答える
1

まず、&a + 4is0x7FFF5FBFF9B0であるため、自分がいると考えている場所から 1 バイト オフセットを見ていることになります。

次に、保存されたフレーム ポインタはaとリターン アドレスの間にあり、これが表示されている値です。

于 2010-12-09T00:19:37.463 に答える