Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么x86-64上的GCC在函数中插入NOP?_Gcc_Assembly_X86 64_Nop_X86 - Fatal编程技术网

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

为什么x86-64上的GCC在函数中插入NOP?,gcc,assembly,x86-64,nop,x86,Gcc,Assembly,X86 64,Nop,X86,给定以下C函数: void go(char *data) { char name[64]; strcpy(name, data); } void go(void) { //char name[64]; //strcpy(name, data); } push rbp mov rbp, rsp nop # only present for gcc5, not gcc 4.9.3

给定以下C函数:

void go(char *data) {
    char name[64];
    strcpy(name, data);
}
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
x86-64上的GCC 5和6编译(普通的
GCC-c-g-o
,后跟
objdump
)如下:

0000000000000000:
0:55推送%rbp
1:48 89 e5 mov%rsp,%rbp
4:48 83欧共体50分$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:4889D6MOV%rdx%rsi
17:48 89 c7 mov%rax,%rdi
1a:e8 00 00呼叫1f
1f:90无
20:c9/Q
21:c3 retq
GCC是否有理由在
1f
处插入
90
/
nop
,或者这只是在未启用优化时可能发生的副作用

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


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

这很奇怪,我以前从未注意到asm输出中
-O0
处有杂散的
nop
s。(可能是因为我不会浪费时间看未优化的编译器输出)

通常,函数内部的
nop
s用于对齐分支目标,包括中的函数入口点。(另请参见
-falign loops
,在优化级别(而非
-Os
)时,默认情况下该选项处于启用状态)


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

void go(char *data) {
    char name[64];
    strcpy(name, data);
}
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
因此,您可以检查asm的其他编译器版本和编译选项

(从技术上讲不是噪声,但启用了
-O0
启用
-fno省略帧指针
,并且at-O0甚至是空函数设置和分解堆栈帧。)


当然,
nop
在任何非零优化级别上都不存在问题代码中的
nop
没有调试或性能优势。
(请参阅tag wiki中的性能指南链接,特别是了解如何在当前CPU上快速编写代码。)

我的猜测是,它纯粹是gcc内部构件的产物。此
nop
gcc-S
asm输出中作为
nop
存在,而不是作为
.p2align
指令存在。gcc本身不计算机器代码字节数,它只是在某些点使用对齐指令来对齐重要的分支目标。只有汇编器知道实现给定对齐实际需要多大的
nop

默认的
-O0
告诉gcc您希望它编译得快,而不是好代码。这意味着asm输出比其他
-O
级别告诉您更多关于gcc内部的信息,而很少告诉您如何优化或其他任何内容

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


如果您想了解gcc或clang在编写代码方面做得有多好,您应该看看
-O3-march=native
(或者
-O2-mtune=intel
,或者您构建项目时使用的任何设置)。不过,弄清在
-O3
上进行的优化是学习一些asm技巧的好方法
-fno tree vectorize
如果您希望看到除此之外的完全优化的非矢量化版本,则非常方便。

NOP通常用于计时。通常情况下,不必担心。是否可能为断点插入了重复的?调试器不需要您为断点插入不必要的NOP…这仅限于
-O0
。没有时间原因,也没有流水线原因。这没有任何帮助。@BrianAgnew:这不是那个问题的重复。将
nop
放在函数体中,而不是作为函数之间的填充,这在gcc5中是新的。还要注意,此
nop
gcc-S
asm输出中作为
nop
存在,而不是作为
.p2align
指令。回答得好。很有趣