assembly - "sub $16, %rsp"指令的用途是什么?

标签 assembly gcc x86-64 calling-convention

让我们采用以下基本 C 函数及其生成的有意未优化的程序集:

int main() {
    int i = 4;
    return 3;
}

它生成以下(未优化的)程序集,这对我来说都很有意义:

main:
        pushq   %rbp
        movq    %rsp, %rbp
        movl    $4, -4(%rbp)
        movl    $3, %eax
        popq    %rbp
        ret

但是,当我添加一个函数调用时,有两条指令我不太明白:

void call() {};
int main() {
    int i = 4;
    call();
    return 3;
}
main:
        pushq   %rbp
        movq    %rsp, %rbp
        subq    $16, %rsp     <-- why is it subtracting 16?
        movl    $4, -4(%rbp)
        movl    $0, %eax      <-- why is it first clearing the %eax register?
        call    call
        movl    $3, %eax
        leave
        ret

如果堆栈帧需要 16 字节对齐,subq $16, %rsp 如何帮助实现这一点?最初的 pushq %rbp 指令不是已经将它偏移了 8 而现在是 +24 了吗?或者上述两行的要点是什么?

最佳答案

第一个变体将局部变量存储在红色区域,堆栈指针下方的 128 字节区域未被 signal 更改。处理程序。第二个变体不能使用红色区域,因为 callq 指令写入(原始)红色区域,破坏存储在那里的局部变量。 (当然,被调用的函数也可以写入原始的红色区域。)

%eax 设置为零,因为函数定义没有声明原型(prototype),所以编译器必须假定它是一个可变参数函数。 %eax(实际上是%al)用于optimize the implementation of variadic functions .

关于assembly - "sub $16, %rsp"指令的用途是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63867840/

相关文章:

assembly - 为什么要向标准输出设备写入这么多字节?

ubuntu - 在 Ubuntu 14.04 中编译 GCC 3.4.6 时出错

c++ - GCC c++11 使用大量带有 STL 位集 <UINT_MAX> 的 RAM

windows - 什么导致页面错误?

linux - 如何在汇编语言中使用 errno 打印错误信息

c - 为什么 C 编译器在 RET 指令后生成 NOP?

assembly - GNU 作为 : how to load a . bss/.data 符号到寄存器?

assembly - 在屏幕上移动对象的最佳方式是什么?

c - 我想知道,为什么执行后得到 "Attempt to execute non-instruction at 0x00400138"?

c++ - gcc - 如何使用地址 sanitizer