读取已启用优化的汇编代码

时间:2016-08-18 16:34:37

标签: c gcc assembly optimization

我尝试比较使用和不使用-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

除了使用堆栈进行操作外,我看不到任何跳转或任何有效的添加子指令。有人可以向我解释一下吗?

由于

1 个答案:

答案 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;