为什么x86-64上的GCC在函数内部插入NOP?

Tho*_*zat 7 assembly gcc x86-64 nop

给定以下C函数:

void go(char *data) {
    char name[64];
    strcpy(name, data);
}
Run Code Online (Sandbox Code Playgroud)

x86-64上的GCC 5和6编译(简单gcc -c -g -o后跟objdump)到:

0000000000000000 <go>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   48 83 ec 50             sub    $0x50,%rsp
   8:   48 89 7d b8             mov    %rdi,-0x48(%rbp)
   c:   48 8b 55 b8             mov    -0x48(%rbp),%rdx
  10:   48 8d 45 c0             lea    -0x40(%rbp),%rax
  14:   48 89 d6                mov    %rdx,%rsi
  17:   48 89 c7                mov    %rax,%rdi
  1a:   e8 00 00 00 00          callq  1f <go+0x1f>
  1f:   90                      nop
  20:   c9                      leaveq 
  21:   c3                      retq   
Run Code Online (Sandbox Code Playgroud)

GCC是否有任何理由插入90/ nopat 1f或仅仅是在未启用优化时可能发生的副作用?

注意:这个问题与大多数其他问题不同,因为它询问nop函数体内部,而不是外部填充.

测试的编译器版本:GCC Debian 5.3.1-14(5.3.1)和Debian 6-20160313-1(6.0.0)

Pet*_*des 9

这很奇怪,我以前从未注意到nopasm输出中的杂散-O0.(可能是因为我不浪费时间查看未优化的编译器输出).

通常nop内部函数是对齐分支目标,包括像Brian链接的问题函数入口点.(另请参阅-falign-loops gcc文档,默认情况下,除了以外的优化级别-Os).


在这种情况下,它nop是裸空函数的编译器噪声的一部分:

void go(void) {
    //char name[64];
    //strcpy(name, data);
}
    push    rbp
    mov     rbp, rsp
    nop                     # only present for gcc5, not gcc 4.9.3
    pop     rbp
    ret
Run Code Online (Sandbox Code Playgroud)

在Godbolt Compiler Explorer中查看该代码,以便您可以检查asm是否有其他编译器版本和编译选项.

(技术上不是噪音,而是-O0启用-fno-omit-frame-pointer,并且在-O0甚至空功能设置并拆除堆栈帧.)


当然,这nop不存在于任何非零优化级别. 在问题的代码中没有调试或性能优势nop. (请参阅标签wiki中的性能指南链接,尤其是Agner Fog的微体系结构指南,了解在当前CPU上使代码快速运行的原因.)

我的猜测是它纯粹是gcc内部的神器.这nop是有作为nopgcc -SASM输出,而不是作为一个.p2align指令.gcc本身不计算机器代码字节,它只是在某些点使用对齐指令来对齐重要的分支目标.只有汇编程序知道nop达到给定对齐实际需要多大的a .

默认-O0告诉gcc你希望它快速编译而不是编写好的代码.这意味着asm输出告诉你更多关于gcc内部的信息-O,而不是其他级别,并且很少关于如何优化或其他任何事情.

如果您正在尝试学习asm,那么查看代码会更有趣-Og,例如(针对调试进行优化).

如果您正在尝试查看gcc或clang在编写代码时的表现,那么您应该查看-O3 -march=native(或者-O2 -mtune=intel,或者使用您构建项目的任何设置).-O3然而,令人费解的优化是学习一些asm技巧的好方法. -fno-tree-vectorize如果你想看到除此之外完全优化的非矢量化版本,这是很方便的.