2

これに出くわしたとき、私はCのいくつかの概念を経験していました。

int add (int a, int b)
{
return a+b;
}

int main()
{
int a,b;
a = 3;
b = 4;
int ret = add(a,b);
printf("Result: %u\n", ret);
exit(0);
}

そのために生成されたアセンブラコードは次のとおりです。

<main>:

1: push ebp

2: mov ebp, esp

3: sub esp, 0x18

4: mov eax, 0x0

.........(もう少しコードがありますが、質問には関係ありません)

私が聞きたい質問は、スタックポインタ(esp)の3番目のステップの値が24(0x18)減少した理由です。

4

2 に答える 2

3

スタック上に 6 つの 4 バイト整数用のスペースを確保しています。これらの正確な使用法は、コンパイラとアーキテクチャによって異なりますが、これらにはa、 、b、およびret.

ちなみに、gcc 4.2.1 を搭載した MacBook Pro (x86、64 ビット、SnowLeopard) でこのコードを試すと、8 つの 4 バイト int 用のスペースが確保されます。上記に加えて、これらには、およびeaxの呼び出しの前にの値を格納するためのものがあります。これは、それぞれの結果が返されるためです (明らかに "cdecl" 呼び出し規約による)。私のマシンのレイアウトは次のようになります。add()printf()

-32:  unused
-28:  unused
-24:  unused
-20:  stores eax prior to each function call
-16:  ret
-12:  b
 -8:  a
 -4:  unused (potentially return value for main())
 ----------------
  0:  original base pointer

私の推測では、-4 の最初の未使用スロットは、 の潜在的な戻り値用main()です。に置き換えることで、これをある程度確認しましexit()return -1;。その場合、戻り値の複製コピーのために、スタックの -4 と -8 に 2 つの int を割り当てました。(これは私のコンパイラのやり方のようでadd()、戻り値も複製されています。)

他の 3 つの未使用スロットについては、コンパイラが (少なくとも) 8 バイト境界に揃えようとしていると思います。ただし、スタックの先頭にさらに 8 バイト (2 つの未使用の整数) を追加した理由は説明できません。(実際に何が起こっているのかよくわかりません -- 16 バイト境界に合わせたほうがよいのでしょうか?)

あなたのコンパイラはおそらく物事を異なって整列させています(そして潜在的に他の呼び出し規約や最適化を使用しています)。

于 2012-07-24T05:52:25.407 に答える
0

コンパイラは、制御を関数呼び出しに移す前に、関数の戻りアドレス、関数で使用される一時変数、および関数に渡されるパラメーターを格納します。これらはすべてスタック フレームに格納されるため、スタック ポインタはデクリメントされます。なぜ減少spする0x18のかわかりません(おそらく64ビットマシンを使用しているため、3(2つの一時+ 1つの戻りアドレス)* 8バイト(64ビット)::= 0x18)

于 2012-07-24T07:08:13.477 に答える