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)
这很奇怪,我以前从未注意到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. (请参阅x86标签wiki中的性能指南链接,尤其是Agner Fog的微体系结构指南,了解在当前CPU上使代码快速运行的原因.)
我的猜测是它纯粹是gcc内部的神器.这nop是有作为nop的gcc -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如果你想看到除此之外完全优化的非矢量化版本,这是很方便的.