当前位置 : 主页 > 手机开发 > 无线 >

使用返回值时为什么0移动到堆栈?

来源:互联网 收集:自由互联 发布时间:2021-06-10
我正在试验拆解简单C程序的clang二进制文件(用-O0编译),我对生成的某个指令感到困惑. 这里有两个带有标准参数的空主函数,其中一个返回值而另一个不返回: // return_void.cvoid main(int ar
我正在试验拆解简单C程序的clang二进制文件(用-O0编译),我对生成的某个指令感到困惑.

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

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

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

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

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

它只在我使用函数时才生成,因此我认为它可能是另一种返回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

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

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

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

    printf("Helo World!\n");
    return 0;
}

一开始就是这样

movl    $0, -4(%rbp)

那么早期的回归看起来如下

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

然后最后它做到了

.LBB0_3:
movl    -4(%rbp), %eax
addq    $32, %rsp
popq    %rbp
retq

因此,该区域确实保留用于存储函数返回值.它似乎并不十分必要,并且它不是在优化代码中使用,而是在-O0模式下使用它的方式.

网友评论