Sum*_*Tea 52 x86 assembly gnu-assembler objdump
在我使用以下转出的汇编代码中objdump:
lea 0x0(%esi,%eiz,1),%esi
Run Code Online (Sandbox Code Playgroud)
什么是注册%eiz?前面的代码是什么意思?
Sin*_*nür 55
显然
%eiz是一个伪寄存器,只是在任何时候都评估为零(如r0MIPS).
...
我最终找到了binutils大师伊恩兰斯泰勒的邮件列表帖子,揭示了答案.有时GCC会将NOP指令插入到代码流中,以确保正确对齐和类似的东西.NOP指令占用一个字节,因此您可以认为可以根据需要添加任意数量的字节.但根据Ian Lance Taylor的说法,芯片执行一条长指令要比许多短指令快.因此,它们不是插入七条NOP指令,而是使用一个奇怪的LEA,它占用了7个字节,在语义上等同于NOP.
And*_*oss 23
(游戏很晚,但这似乎是一个有趣的补充):它根本不是一个寄存器,它是英特尔指令编码的一个怪癖.当使用ModRM字节从存储器加载时,寄存器字段有3位用于存储8个可能的寄存器.但ESP(堆栈指针)"将"所在的位置被处理器解释为"SIB字节遵循该指令"(即它是扩展寻址模式,而不是ESP的引用).由于作者只知道的原因,GNU汇编器总是将"零寄存器本来就是零"表示为"%eiz"寄存器.英特尔语法只是放弃它.
use*_*531 14
安迪罗斯提供了更多的潜在推理,但不幸的是错误或至少混淆了技术细节.确实有效的地址(%esp)不能仅用ModR/M字节编码而不是被解码(%esp),它用于表示还包括SIB字节.但是,%eiz伪寄存器并不总是与SIB字节一起使用来表示使用了SIB字节.
SIB字节(scale/index/base)有三个部分:索引(诸如as %eax或者%ecx应用scale 的寄存器),scale(索引寄存器乘以1到8的2的幂) by)和base(另一个添加到缩放索引的寄存器).这是允许指令,如add %al,(%ebx,%ecx,2)(机器代码:00 04 4b- 操作码,modr/m,sib(注意即使使用SIB字节也注意没有%eiz寄存器))(或在Intel语法中,"添加BYTE PTR [ecx*2] + ebx],al").
但是,%esp不能用作SIB字节中的索引寄存器.而不是允许这个选项,英特尔改为添加一个选项来使用基址寄存器,没有缩放或索引.因此,为了消除add %al,(%ecx)(机器代码:00 01- 操作码,modr/m)和add %al,(%ecx)(机器代码:00 04 21- 操作码,modr/m,sib)的情况,替代add %al,(%ecx,%eiz,1)使用替代语法(或用于英特尔语法:) add BYTE PTR [ecx+eiz*1],al.
正如Sinan链接的文章中所解释的那样,这个特定的指令(lea 0x0(%esi,%eiz,1),%esi)仅用esi = &*esi作多字节的nop(相当于),因此只需要执行一条类似nop的指令而不是多条nop指令.