如果我编译一个具有-O2
优化的程序,那么具有数学运算的任何函数都是"内联"完成的,没有物理 CPU 指令在汇编中在此处输入链接描述。所以在c
有这个:
#include <stdio.h>
#include <stdlib.h>
int f(int a, int b, int c){
return a*b+c;
}
int main(){
printf("%in",f(1,2,4));
return 0;
}
并编译为cc -O2 -fverbose-asm -S a.c
,气体输出:
.text
.p2align 4,,15
.globl f
.type f, @function
f:
.LFB22:
# a.c:5: return a*b+c;
imull %esi, %edi # b, tmp93
# a.c:5: return a*b+c;
leal (%rdi,%rdx), %eax #, tmp92
# a.c:6: }
ret
.LFE22:
.size f, .-f
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "%in"
.section .text.startup,"ax",@progbits
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB23:
subq $8, %rsp #,
# a.c:8: printf("%in",f(1,2,4));
movl $6, %esi # HERE, I can change the value and gcc will not even notice
leaq .LC0(%rip), %rdi #,
xorl %eax, %eax #
call printf@PLT #
# a.c:10: }
xorl %eax, %eax #
addq $8, %rsp #
ret
.LFE23:
.size main, .-main
.ident "GCC: (Debian 8.3.0-6) 8.3.0"
.section .note.GNU-stack,"",@progbits
在这里你可以看到,f
函数甚至不会从main调用。因此,简单地避免了该函数,并且在编译时以某种方式计算其返回值到某些指令周期。但是,当编译器不直接在 CPU 上运行时,数学计算是如何在编译时完成的,而 CPU 只进行汇编?还是编译器在编译时执行一些 cpu 任务,然后再编译为 asm?当编译器可以直接转换为操作码并执行程序而无需汇编程序的"一步"时,为什么需要asm?
编译器是一个程序,它只是执行所需的计算。 它不会模拟 CPU 这样做,此步骤(称为恒定折叠(早在生成任何指令之前就发生了。