我正在试验拆解简单C程序的clang二进制文件(用-O0编译),我对生成的某个指令感到困惑. 这里有两个带有标准参数的空主函数,其中一个返回值而另一个不返回: // return_void.cvoid main(int ar
这里有两个带有标准参数的空主函数,其中一个返回值而另一个不返回:
// 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模式下使用它的方式.