gpt4 book ai didi

斯坦福教程和 GCC 之间的冲突

转载 作者:太空狗 更新时间:2023-10-29 16:15:34 24 4
gpt4 key购买 nike

根据 this电影(大约 38 分钟),如果我有两个具有相同局部变量的函数,它们将使用相同的空间。所以下面的程序应该打印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()使用,因此编译器优化了该代码out,并且从未将 5 写入堆栈中的该位置。也尝试在 B() 中添加 printf - 它可能会起作用。

此外,编译器标志 - 即优化级别 - 也可能会影响此实验。尝试通过将 -O0 传递给 gcc 来禁用优化。

编辑: 我刚刚用 gcc -O0(64 位)编译了您的代码,事实上,程序打印了 5,因为熟悉调用堆栈的人会预计。事实上,即使没有 -O0,它也能正常工作。 32 位版本的行为可能有所不同。

免责声明:永远不要永远在“真实”代码中使用这样的东西!

1 - 正在进行辩论below关于这是正式的“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 字节的堆栈空间,并在 [ebp-0x4] 处初始化了我们的 int a 变量> 到 5。

然而,在 A 中,编译器将 int a 放在 [ebp-0xc] 中。所以在这种情况下,我们的局部变量没有在同一个地方结束!通过在 A 中添加 printf() 调用也会导致 AB 的堆栈帧是相同,并打印 55

关于斯坦福教程和 GCC 之间的冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19559133/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com