gcc - 栈分配,为什么要多出空间?

标签 gcc assembly x86 stack memory-alignment

我玩了一会儿,以更好地掌握调用约定和堆栈的处理方式,但我无法弄清楚为什么 main 在设置堆栈时分配了三个额外的双字(在 <main+0> 处)。它既不是 8 字节也不是 16 字节对齐,所以据我所知,这不是原因。正如我所见, main 需要 12 个字节来表示 func 和返回值的两个参数。

我错过了什么?

该程序是在 x86 架构上使用“gcc -ggdb”编译的 C 代码。

编辑:我从 gcc 中删除了 -O0 标志,它对输出没有影响。

(gdb) disas main
Dump of assembler code for function main:
    0x080483d1 <+0>:    sub    esp,0x18
    0x080483d4 <+3>:    mov    DWORD PTR [esp+0x4],0x7
    0x080483dc <+11>:   mov    DWORD PTR [esp],0x3
    0x080483e3 <+18>:   call   0x80483b4 <func>
    0x080483e8 <+23>:   mov    DWORD PTR [esp+0x14],eax
    0x080483ec <+27>:   add    esp,0x18
    0x080483ef <+30>:   ret    
End of assembler dump.

编辑:当然我应该发布 C 代码:
int func(int a, int b) {
    int c = 9;
    return a + b + c;
}

void main() {
    int x;
    x = func(3, 7);
}

平台是 Arch Linux i686。

最佳答案

当您进入函数时,函数的参数(包括但不限于 main )已经在堆栈中。您在函数内部分配的空间用于局部变量。对于具有简单返回类型的函数,例如 int ,返回值通常在寄存器中( eax ,在 x86 上使用典型的 32 位编译器)。

例如,如果 main是这样的:

int main(int argc, char **argv) { 
   char a[35];

   return 0;
}

...当我们进入 main 为 a 腾出空间时,我们希望看到堆栈上至少分配了 35 个字节。 .假设是 32 位实现,通常会向上取整为 4 的下一个倍数(在本例中为 36)以保持堆栈的 32 位对齐。我们不希望看到为返回值分配的任何空间。 argcargv将在堆栈上,但它们在 main 之前已经在堆栈上已输入,所以 main不需要做任何事情来为他们分配空间。

在上述情况下,在为 a 分配空间后, a通常从 [esp-36] 开始, argv将在 [esp-44]argc将在 [esp-48] (或者这两个可能会颠倒——取决于参数是从左到右还是从右到左)。如果你想知道我为什么跳过 [esp-40] ,那将是返回地址。

编辑:这是函数入口处和设置堆栈框架后的堆栈图:

enter image description here

编辑 2:根据您更新的问题,您所拥有的有点迂回,但并不是特别难以理解。进入 main ,它不仅为 main 的局部变量分配空间,还有你传递给你从 main 调用的函数的参数.

这至少占了分配的一些额外空间(尽管不一定是全部)。

关于gcc - 栈分配,为什么要多出空间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9862017/

相关文章:

io - 0x80 端口地址连接到什么?

Python distutils 没有使用正确版本的 gcc

c - 为什么在 gcc 上接受 const 限定变量作为初始值设定项?

android - 我如何执行 Dalvik 操作码

c - 无法在漏洞利用期间注入(inject)有效的指令指针

winapi - 如何在不使用高级汇编程序的情况下显示 "Hello, world!"?

c++ - 有什么方法可以让 g++ 只发出与我的文件有关的警告?

c++ - 奇怪的 C++ 链接错误

assembly - 如何正确使用 ADDIS 和 ADDI 将 32 位常量直接求和到寄存器?

assembly - 如何在 x86 ASM 中自动移动 64 位值?