当我遇到这个时,我正在经历一些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
.........(更多代码但与问题无关)
我想问的问题是为什么在第3步中堆栈指针(esp)的值减少了24(0x18)。
答案 0 :(得分:3)
它在堆栈上为六个4字节的整数腾出空间。这些的确切用法取决于编译器和体系结构,但这些肯定包括a
,b
和ret
各一个。
顺便提一下,当我在MacBook Pro(x86,64位,SnowLeopard)上使用gcc 4.2.1尝试此代码时,它为 8 4字节整数提供了空间。除上述内容外,还包括用于在调用eax
和add()
之前存储printf()
的值的内容,因为每个内容的结果都会在其中返回(显然是由于“cdecl”调用约定)。我机器上的布局如下所示:
-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分配了两个整数,用于返回值的副本。 (这似乎是我编译器的方式,因为add()
也复制了返回值。)
对于其他3个未使用的插槽,我的猜测是我的编译器试图在8字节边界上对齐(至少)。这并不能解释为什么它会在堆栈的顶部添加另外8个字节(两个未使用的int)。 (我不确定那里发生了什么 - 也许它更喜欢在16字节边界上对齐?)
您的编译器可能以不同的方式对齐事物(并且可能使用其他一些调用约定和/或优化)。
答案 1 :(得分:0)
编译器存储函数的返回地址,函数中使用的临时函数以及在将控件传递给函数调用之前传递给函数的参数。所有这些都存储在堆栈帧中,因此堆栈指针递减。我不确定为什么它会sp
递减0x18
(可能你是64位机器因此3(两个临时+一个返回地址)* 8字节(64位):: = 0x18)