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

.........(更多代码但与问题无关)

我想问的问题是为什么在第 3 步中堆栈指针(esp)的值减少了 24(0x18)。

4

2 回答 2

3

它为堆栈上的六个 4 字节整数腾出空间。这些的确切用法取决于编译器和体系结构,但这些肯定包括一个 for abret.

顺便说一句,当我在装有 gcc 4.2.1 的 MacBook Pro(x86、64 位、SnowLeopard)上尝试此代码时,它为8 个4 字节整数腾出了空间。除了上述之外,这些还包括一个用于eax在调用add()and之前存储 的值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 个字节(两个未使用的整数)。(我不太确定那里发生了什么——也许它更喜欢在 16 字节边界上对齐?)

您的编译器可能以不同的方式对齐事物(并且可能还使用其他一些调用约定和/或优化)。

于 2012-07-24T05:52:25.407 回答
0

在将控制权转移到函数调用之前,编译器会存储函数的返回地址、函数中使用的临时变量以及传递给函数的参数。所有这些都存储在堆栈帧中,因此堆栈指针递减。我不确定为什么它会减少sp0x18可能您在 64 位机器上,因此 3(两个临时 + 一个返回地址)* 8 字节(64 位)::= 0x18)

于 2012-07-24T07:08:13.477 回答