我对Linux内核的头文件之一arch/x86/include/asm/nops.h中的注释感到有些困惑。它指出
<...>以下说明在64位模式下不是nop,对于64位模式,请使用K8或P6 nopsmovl%esi,%esileal 0x00(%esi),%esi<...>
我想作者在这里隐含了机器指令(分别是'89 F6'和'8D 76 00'),而不是汇编指令。从英特尔软件开发人员手册第2A卷LEA
的描述可以得出,后一条指令(lea 0x00(%rsi), %esi
)与前一条指令mov %esi,%esi
相同。
因此这简化为问题,mov %esi,%esi
是否实际上是x86-64上的无操作。
mov
不会更改标志。这种mov
也不改变存储器。看来,如果它更改了%rip
以外的内容,则应该是通用寄存器。但是我不知道它如何更改%rsi
的内容。如果您操纵通用寄存器的下半部分,那么上半部分应该不会改变,对吧?
mov %esi, %esi
将%rsi的高32位清零,因此在x86_64上不是空操作。
请参见Why do x86-64 instructions on 32-bit registers zero the upper part of the full 64-bit register?
#include <stdio.h>
int main(int argc, char * argv[])
{
void * reg_rsi = 0;
asm (
"movq $0x1234567812345678, %%rsi;\n"
"movl %%esi, %%esi;\n"
"movq %%rsi, %0;\n"
: "=r" (reg_rsi)
: /* no inputs */
: /* no clobbered */
);
printf("reg_rsi = %p\n", reg_rsi);
return 0;
}
这为我的x86_64计算机提供了“ reg_rsi = 0x12345678”。