代码之家  ›  专栏  ›  技术社区  ›  Kladskull

为什么eax在“离开”之前被清除?

  •  0
  • Kladskull  · 技术社区  · 4 年前

    我使用 compiler explorer .为什么eax总是在堆栈弹出rbp之前设置为零?退出前清除寄存器是否符合标准?

    main:
            push    rbp
            mov     rbp, rsp
            mov     DWORD PTR [rbp-4], 1
            mov     DWORD PTR [rbp-8], 1
            add     DWORD PTR [rbp-4], 1
            mov     eax, DWORD PTR [rbp-4]
            mov     DWORD PTR [rbp-8], eax
            mov     eax, 0 <--------------------------?
            pop     rbp
            ret
    

    作为参考,我使用的是x86-64 gcc 12.1

    0 回复  |  直到 4 年前
        1
  •  1
  •   Peter Cordes    4 年前

    不,这不是标准的。您不“清除”寄存器本身,您总是将它们设置为某个值。有时该值为0。

    在C++和C99中 return 0; 在的底部 main() .EAX是所有主流x86调用约定中的返回值寄存器,包括x86-64 System V。零EAX实现了 返回0; ,如果不调用该函数就不会出现 main 。

    (或者,如果您的来源包括 返回0; 当然你忘记在你的问题中包括这一点,甚至忘记将其作为Godbolt链接的一部分进行链接;使用“共享”按钮可以创建短链接,或者更好地创建完整链接。)


    在C++中,从非- void 不带的函数 return 语句是未定义的行为。隐式在主计数结束时返回0,因此重命名它将使其成为要到达的执行路径的UB,即要调用的函数。

    在C中,只有当调用者 使用 一个函数的返回值,由于C历史:它以前存在过一段时间 无效的 添加了,因此出现了具有如下声明的函数的历史代码 foo(int x) 使用隐式int返回值,但实际上它们没有返回任何内容,调用方也没有读取返回值。

    无论如何,重命名 int main() 到 int foo() 如果不添加return语句,您的函数将在C++中出现未定义的行为,并且启用了优化,GCC将不会为其发出任何指令,甚至不会发出 ret 。

    (它当然也会打印警告,至少带有 -Wall .你绝对应该启用 -墙 在处理编译器输出时,编译器认为值得警告的事情往往与奇怪的asm有关。在Godbolt上,在asm输出窗格的左下角查找任何红色,显示警告的数量。点击它打开一个新的窗格。)