为什么gcc 4.x在调用方法时默认为linux上的堆栈保留8个字节?

nik*_*ame 7 linux assembly stack gcc

作为asm的初学者,我正在检查gcc -S生成的asm代码来学习.

为什么gcc 4.x在调用方法时默认为堆栈保留8个字节?

func18是空函数,没有返回没有参数,没有定义局部变量.我无法弄清楚为什么这里保留了8个字节(没有任何论坛/网站提及的原因,ppl似乎认为理所当然)它是否为%ebp推送?还是返回类型?!很多!

      .globl _func18
  _func18:
     pushl   %ebp 
     movl    %esp, %ebp 
     subl    $8, %esp 
     .text 
Run Code Online (Sandbox Code Playgroud)

mar*_*k4o 7

某些指令要求某些数据类型与16字节边界(特别是SSE数据类型__m128)对齐.为了满足这一要求,gcc确保堆栈最初是16字节对齐的,并以16字节的倍数分配堆栈空间.如果只需要按下4字节的返回地址和4字节的帧指针,则需要8个额外的字节来保持堆栈与16字节边界对齐.但是,如果gcc确定不需要额外的对齐(即没有使用花哨的数据类型并且没有调用外部函数),那么它可能会省略用于对齐堆栈的任何其他指令.确定这一点所需的分析可能需要执行某些优化过程.

另请参阅选项-mpreferred-stack-boundary = num的gcc文档.


nik*_*ame 0

正如理查德上面提到的,这都是因为优化,如下所示。但我仍然不知道为什么保留 8 个字节是优化的?!

原始c

void func18() {}
int main() {return 0;}
Run Code Online (Sandbox Code Playgroud)

编译时未指定优化标志

    .text                                                                                   
.globl _func18
_func18:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $8, %esp
    leave
    ret
.globl _main
_main:                                                                                      
    pushl   %ebp
    movl    %esp, %ebp
    subl    $8, %esp
    movl    $0, %eax
    leave
    ret
    .subsections_via_symbols
Run Code Online (Sandbox Code Playgroud)

使用 -Os 优化标志,不再保留堆栈

    .text
.globl _func18
_func18:
    pushl   %ebp
    movl    %esp, %ebp
    leave
    ret
.globl _main
_main:
    pushl   %ebp
    xorl    %eax, %eax
    movl    %esp, %ebp
    leave
    ret
    .subsections_via_symbols
Run Code Online (Sandbox Code Playgroud)

  • 把这个放在你的问题中,而不是单独的答案中 (2认同)