gcc – 堆栈分配,为什么额外的空间?

我正在玩一点,以便更好地掌握调用约定以及如何处理堆栈,但我无法弄清楚为什么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;
}

…我们希望在堆栈中分配至少35个字节,因为我们输入main来为a腾出空间.假设一个32位实现,通常会向上舍入到下一个4的倍数(在这种情况下为36),以保持堆栈的32位对齐.我们不希望看到为返回值分配任何空间. argc和argv将在堆栈中,但是在main进入之前它们已经在堆栈中,因此main不需要做任何事情来为它们分配空间.

在上面的例子中,在为a分配空间后,a将典型地从[esp-36]开始,argv将在[esp-44]并且argc将在[esp-48](或者这两个可能被反转 – 取决于参数是从左到右还是从右到左推动.如果您想知道为什么我跳过[esp-40],那将是返回地址.

编辑:这是进入函数的堆栈图,并在设置堆栈框架后:

编辑2:根据您更新的问题,您所拥有的内容略微迂回,但并不是特别难以理解.在进入main时,它不仅为main的本地变量分配空间,而且还为你传递给main的函数分配空间.

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

https://stackoverflow.com/questions/9862017/stack-allocation-why-the-extra-space

本站文章除注明转载外,均为本站原创或编译
转载请明显位置注明出处:gcc – 堆栈分配,为什么额外的空间?