为什么在使用返回值时将 0 移到堆栈中?

Max*_*kov 5 c assembly clang calling-convention disassembly

我正在试验反汇编clang简单 C 程序的二进制文件(用 编译-O0),我对生成的某个指令感到困惑。

这是两个main带有标准参数的空函数,其中一个返回值,另一个不返回:

// return_void.c
void main(int argc, char** argv)
{
}

// return_0.c
int main(int argc, char** argv)
{
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

现在,当我拆卸它们的组件时,它们看起来相当不同,但有一行我不明白:

return_void.bin:
(__TEXT,__text) section
_main:
0000000000000000    pushq   %rbp
0000000000000001    movq    %rsp, %rbp
0000000000000004    movl    %edi, -0x4(%rbp)
0000000000000007    movq    %rsi, -0x10(%rbp)
000000000000000b    popq    %rbp
000000000000000c    retq

return_0.bin:
(__TEXT,__text) section
_main:
0000000100000f80    pushq   %rbp                
0000000100000f81    movq    %rsp, %rbp          
0000000100000f84    xorl    %eax, %eax          # We return with EAX, so we clean it to return 0
0000000100000f86    movl    $0x0, -0x4(%rbp)    # What does this mean?
0000000100000f8d    movl    %edi, -0x8(%rbp)
0000000100000f90    movq    %rsi, -0x10(%rbp)
0000000100000f94    popq    %rbp
0000000100000f95    retq
Run Code Online (Sandbox Code Playgroud)

它只在我使用函数时生成,不是无效的,所以我认为这可能是返回 0 的另一种方式,但是当我更改返回的常量时,这一行根本没有改变:

// return_1.c
int main(int argc, char** argv)
{
    return 1;
}

empty_return_1.bin:
(__TEXT,__text) section
_main:
0000000100000f80    pushq   %rbp
0000000100000f81    movq    %rsp, %rbp
0000000100000f84    movl    $0x1, %eax           # Return value modified
0000000100000f89    movl    $0x0, -0x4(%rbp)    # This value is not modified
0000000100000f90    movl    %edi, -0x8(%rbp)
0000000100000f93    movq    %rsi, -0x10(%rbp)
0000000100000f97    popq    %rbp
0000000100000f98    retq
Run Code Online (Sandbox Code Playgroud)

为什么会生成这条线,它的目的是什么?

AnT*_*AnT 5

该区域的用途由以下代码揭示

int main(int argc, char** argv)
{
    if (rand() == 42)
      return 1;

    printf("Helo World!\n");
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

一开始它确实如此

movl    $0, -4(%rbp)
Run Code Online (Sandbox Code Playgroud)

那么早期返回如下所示

callq   rand
cmpl    $42, %eax
jne .LBB0_2
movl    $1, -4(%rbp)
jmp .LBB0_3
Run Code Online (Sandbox Code Playgroud)

然后最后它确实

.LBB0_3:
movl    -4(%rbp), %eax
addq    $32, %rsp
popq    %rbp
retq
Run Code Online (Sandbox Code Playgroud)

所以,这个区域确实是保留来存储函数返回值的。它似乎并不是非常必要,并且它没有在优化代码中使用,但在-O0模式下这就是它的工作方式。