AMD64 – nopw汇编指令?

在这个编译器输出中,我试图了解nopw指令的机器码编码如何工作:

00000000004004d0 <main>:
  4004d0:       eb fe                   jmp    4004d0 <main>
  4004d2:       66 66 66 66 66 2e 0f    nopw   %cs:0x0(%rax,%rax,1)
  4004d9:       1f 84 00 00 00 00 00

http://john.freml.in/amd64-nopl有一些关于“nopw”的讨论。有人可以解释4004d2-4004e0的含义吗?从代码列表看,66 ..代码是多字节扩展。我觉得我可以得到一个比我更好的答案,除非我试图在操作码列表上几个小时。

该asm输出来自C中的以下(疯狂)代码,其优化为简单的无限循环:

long i = 0;

main() {
    recurse();
}

recurse() {
    i++;
    recurse();
}

当编译gcc -O2时,编译器会识别无限递归,并将其转换为无限循环;实际上,它实际上是在main()中循环,而不调用recurse()函数。

编辑笔记:带NOP的填充函数不是无限循环的特有的。这是一系列具有一定范围的NOP,on the Godbolt compiler explorer.的功能

0x66字节是“操作数大小覆盖”前缀。其中有一个以上相当于拥有一个。

0x2e是64位模式下的“空前缀”(它是一个CS:段覆盖,否则这就是为什么它显示在汇编助记符中)。

0x0f 0x1f是采用ModRM字节的NOP的2字节操作码

0x84是ModRM byte,在这种情况下编码使用5个字节的寻址模式。

一些CPU对于具有许多前缀(例如多于三个)的指令进行解码的速度很慢,因此指定SIB disp32的ModRM字节是一种比五个前缀字节更多的额外5个字节的更好的方式。

07001:

Each of the instruction decoders can handle three prefixes per clock
cycle. This means that three instructions with three prefixes each can
be decoded in the same clock cycle. An instruction with 4 – 6 prefixes
takes an extra clock cycle to decode.

基本上,这些字节是一个长的NOP指令,永远不会被执行。因为编译器发出了一个.p2align 4指令,所以在下一个函数是对齐在一个16字节的边界,所以汇编器填充了一个NOP。对于将执行的NOP,长期NOP的最佳选择取决于微架构。对于像许多前缀的微架构,如Intel Silvermont或AMD K8,具有3个前缀的两个NOP可能会更快地解码。

博客文章链接到(http://john.freml.in/amd64-nopl)的问题解释了为什么编译器使用复杂的单个NOP指令而不是一串单字节0x90 NOP指令。

您可以在AMD技术参考文献中找到有关指令编码的详细信息:

> http://developer.amd.com/documentation/guides/pages/default.aspx#manuals

主要在“AMD64架构程序员手册卷3:通用和系统说明”中。我相信英特尔对x64架构的技术参考将具有相同的信息(甚至可以更容易理解)。

转载注明原文:AMD64 – nopw汇编指令? - 代码日志