このムービー(約38分)によると、同じローカル変数を持つ2つの関数がある場合、それらは同じスペースを使用します。したがって、次のプログラムは、を出力する必要があります5
。gcc
結果とともにコンパイルします-1218960859
。どうして?
プログラム:
#include <stdio.h>
void A()
{
int a;
printf("%i",a);
}
void B()
{
int a;
a = 5;
}
int main()
{
B();
A();
return 0;
}
要求に応じて、逆アセンブラからの出力は次のとおりです。
0804840c <A>:
804840c: 55 push ebp
804840d: 89 e5 mov ebp,esp
804840f: 83 ec 28 sub esp,0x28
8048412: 8b 45 f4 mov eax,DWORD PTR [ebp-0xc]
8048415: 89 44 24 04 mov DWORD PTR [esp+0x4],eax
8048419: c7 04 24 e8 84 04 08 mov DWORD PTR [esp],0x80484e8
8048420: e8 cb fe ff ff call 80482f0 <printf@plt>
8048425: c9 leave
8048426: c3 ret
08048427 <B>:
8048427: 55 push ebp
8048428: 89 e5 mov ebp,esp
804842a: 83 ec 10 sub esp,0x10
804842d: c7 45 fc 05 00 00 00 mov DWORD PTR [ebp-0x4],0x5
8048434: c9 leave
8048435: c3 ret
08048436 <main>:
8048436: 55 push ebp
8048437: 89 e5 mov ebp,esp
8048439: 83 e4 f0 and esp,0xfffffff0
804843c: e8 e6 ff ff ff call 8048427 <B>
8048441: e8 c6 ff ff ff call 804840c <A>
8048446: b8 00 00 00 00 mov eax,0x0
804844b: c9 leave
804844c: c3 ret
804844d: 66 90 xchg ax,ax
804844f: 90 nop
はい、はい、これは未定義の動作あなたが初期化されていない変数を使用しているので、1。
ただし、x86アーキテクチャ2では、この実験は機能するはずです。値はスタックから「消去」されません。また、で初期化されていないためB()
、スタックフレームが同一であれば、同じ値が存在するはずです。
の内部でint a
は使用されていないためvoid B()
、コンパイラはそのコードを最適化し、スタック上のその場所に5が書き込まれることはなかったと思います。追加してみてくださいprintf
中B()
にも-それだけで動作する可能性があります。
また、コンパイラフラグ(つまり最適化レベル)もこの実験に影響を与える可能性があります。-O0
gccに渡して、最適化を無効にしてみてください。
編集:私はあなたのコードをgcc -O0
(64ビット)でコンパイルしました、そして実際、プログラムはコールスタックに精通している人が期待するように5を出力します。実際、それはなくても機能しました-O0
。32ビットビルドは動作が異なる場合があります。
免責事項:Doが今までになく、これまでの「本物」のコードにこのようなものを使用!
1-これが公式に「UB」であるかどうか、または単に予測できないかどうかについて、以下で議論が行われています。
2-また、x64、およびおそらくコールスタックを使用する他のすべてのアーキテクチャ(少なくともMMUを備えたもの)
それが機能しなかった理由を見てみましょう。これは32ビットで最もよく見られるので、でコンパイルし-m32
ます。
$ gcc --version
gcc (GCC) 4.7.2 20120921 (Red Hat 4.7.2-2)
$ gcc -m32 -O0 test.c
(最適化を無効にして)でコンパイルしました。これを実行すると、ガベージが出力されます。
見て$ objdump -Mintel -d ./a.out
:
080483ec <A>:
80483ec: 55 push ebp
80483ed: 89 e5 mov ebp,esp
80483ef: 83 ec 28 sub esp,0x28
80483f2: 8b 45 f4 mov eax,DWORD PTR [ebp-0xc]
80483f5: 89 44 24 04 mov DWORD PTR [esp+0x4],eax
80483f9: c7 04 24 c4 84 04 08 mov DWORD PTR [esp],0x80484c4
8048400: e8 cb fe ff ff call 80482d0 <printf@plt>
8048405: c9 leave
8048406: c3 ret
08048407 <B>:
8048407: 55 push ebp
8048408: 89 e5 mov ebp,esp
804840a: 83 ec 10 sub esp,0x10
804840d: c7 45 fc 05 00 00 00 mov DWORD PTR [ebp-0x4],0x5
8048414: c9 leave
8048415: c3 ret
B
で、コンパイラが0x10バイトのスタックスペースを予約し、int a
変数[ebp-0x4]
を5に初期化したことがわかります。
ではA
ただし、コンパイラが置かint a
で[ebp-0xc]
。したがって、この場合、ローカル変数は同じ場所に配置されませんでした。追加することによりprintf()
、呼をA
、同様のスタックフレームを引き起こしますA
とB
同一である、および印刷します55
。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加