我尝试比较使用和不使用-O3选项的编译器输出,我无法理解优化代码的工作原理。
这是C代码:
#include <stdio.h>
#include <limits.h>
int main(int argc, char *argv[]) {
int a = 3;
int b = argc;
while (b) {
++a;
--b;
}
printf("%d\n", a);
return 0;
}
这是没有优化的objdump输出。看起来很安全直截了当:
000000000040052d <main>:
#include <stdio.h>
#include <limits.h>
int main(int argc, char *argv[]) {
40052d: 55 push %rbp
40052e: 48 89 e5 mov %rsp,%rbp
400531: 48 83 ec 20 sub $0x20,%rsp
400535: 89 7d ec mov %edi,-0x14(%rbp)
400538: 48 89 75 e0 mov %rsi,-0x20(%rbp)
int a = 3;
40053c: c7 45 f8 03 00 00 00 movl $0x3,-0x8(%rbp)
int b = argc;
400543: 8b 45 ec mov -0x14(%rbp),%eax
400546: 89 45 fc mov %eax,-0x4(%rbp)
while (b) {
400549: eb 08 jmp 400553 <main+0x26>
++a;
40054b: 83 45 f8 01 addl $0x1,-0x8(%rbp)
--b;
40054f: 83 6d fc 01 subl $0x1,-0x4(%rbp)
int main(int argc, char *argv[]) {
int a = 3;
int b = argc;
while (b) {
400553: 83 7d fc 00 cmpl $0x0,-0x4(%rbp)
400557: 75 f2 jne 40054b <main+0x1e>
++a;
--b;
}
printf("%d\n", a);
400559: 8b 45 f8 mov -0x8(%rbp),%eax
40055c: 89 c6 mov %eax,%esi
40055e: bf 04 06 40 00 mov $0x400604,%edi
400563: b8 00 00 00 00 mov $0x0,%eax
400568: e8 a3 fe ff ff callq 400410 <printf@plt>
return 0;
40056d: b8 00 00 00 00 mov $0x0,%eax
}
但是在向gcc添加-O3选项之后我得到了这个:
0000000000400470 <main>:
#include <stdio.h>
#include <limits.h>
int main(int argc, char *argv[]) {
400470: 8d 47 03 lea 0x3(%rdi),%eax
400473: 48 83 ec 08 sub $0x8,%rsp
400477: ba 03 00 00 00 mov $0x3,%edx
40047c: 85 ff test %edi,%edi
}
__fortify_function int
printf (const char *__restrict __fmt, ...)
{
return __printf_chk (__USE_FORTIFY_LEVEL - 1, __fmt, __va_arg_pack ());
40047e: be 14 06 40 00 mov $0x400614,%esi
400483: bf 01 00 00 00 mov $0x1,%edi
400488: 0f 45 d0 cmovne %eax,%edx
40048b: 31 c0 xor %eax,%eax
40048d: e8 ce ff ff ff callq 400460 <__printf_chk@plt>
}
printf("%d\n", a);
return 0;
}
400492: 31 c0 xor %eax,%eax
400494: 48 83 c4 08 add $0x8,%rsp
400498: c3 retq
除了使用堆栈进行操作外,我看不到任何跳转或任何有效的添加子指令。有人可以向我解释一下吗?
由于
答案 0 :(得分:3)
您的代码已针对printf("%d\n", 3 + argc)
进行了优化,因为gcc可以找出循环的作用。
3 + argc是第一个lea 0x3(%rdi),%eax
。
实际上,gcc并没有完全解决循环:
test / cmov似乎正在做的事情:
int a = 3;
if (argc != 0)
a = argc + 3;
又名
int a = argc ? 3 + argc : 3;