我仍在学习汇编和 C,但现在,我正在尝试了解编译器的工作原理。我这里有一个简单的代码:
int sub()
{
return 0xBEEF;
}
main()
{
int a=10;
sub();
}
现在我已经知道 CPU 是如何工作的,跳转到框架和子程序等。 我不明白的是程序在哪里“存储”它们的局部变量。在这种情况下是在主要框架中吗?
这是调试器的主框架:
0x080483f6 <+0>: push %ebp
0x080483f7 <+1>: mov %esp,%ebp
0x080483f9 <+3>: sub $0x10,%esp
=> 0x080483fc <+6>: movl $0xa,-0x4(%ebp)
0x08048403 <+13>: call 0x80483ec <sub>
0x08048408 <+18>: leave
0x08048409 <+19>: ret
我有“int a=10;”一个断点,这就是偏移量 6 具有该箭头的原因。 所以,main 的功能开始像其他人一样插入 ebp bla bla bla,然后我不明白这一点:
0x080483f9 <+3>: sub $0x10,%esp => 0x080483fc <+6>: movl $0xa,-0x4(%ebp)
为什么在esp中做sub?堆栈指针的偏移量为-0x4 的变量'a' 是否在堆栈中?
只是为了澄清这里的想法:D
提前致谢!
最佳答案
0x080483f9 <+3>: sub $0x10,%esp
你会在每个函数中找到这样的指令。它的目的是创建一个适当大小的栈帧,以便函数可以存储它的局部变量(记住栈是向后增长的!)。
在这种情况下,栈帧有点太大了。这是因为 gcc(从 2.96 开始)默认将堆栈帧填充到 16 字节边界,以解决 SSEx 指令,这些指令需要将打包的 128 位 vector 对齐到 16 字节。 (引用 here)。
=> 0x080483fc <+6>: movl $0xa,-0x4(%ebp)
此行将 a 初始化为正确的值 (0xa = 10d)。局部变量总是用相对于 ebp 的偏移量引用,这标志着堆栈帧的开始(因此包含在 ebp 和 esp 之间)。
关于c - 调试 C 程序(int 声明),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19210032/