什么是注册%eiz?

在下面使用objdump转储的汇编代码中:

 lea 0x0(%esi,%eiz,1),%esi 

什么是注册%eiz ? 前面的代码是什么意思?

看看为什么GCC LEA EIZ? :

显然%eiz是一个伪寄存器,只是在任何时候都评估为零(就像MIPS上的r0 )。

我最终通过binutils guru Ian Lance Taylor发现了一个邮件列表post,揭示了答案。 有时GCC会在代码stream中插入NOP指令,以确保正确的alignment和类似的东西。 NOP指令需要一个字节,所以你会认为你可以根据需要添加多less个字节。 但根据Ian Lance Taylor的说法,芯片执行一条长指令比多条短指令要快。 因此,而不是插入七个NOP指令,而是使用一个bizarro LEA,它使用了七个字节,在语义上等同于一个NOP。

(游戏很晚,但是这似乎是一个有趣的补充):这根本不是一个寄存器,这是Intel指令编码的一个怪癖。 当使用ModRM字节从存储器加载时,寄存器字段有3个位用于存储8个可能的寄存器。 但ESP(堆栈指针)“将”的位置被处理器解释为“SIB字节在该指令之后”(即,它是扩展寻址模式,而不是ESP的引用)。 由于作者只知道的原因,GNU汇编程序一直以“%eiz”寄存器的forms表示这个“零寄存器本来就是零”。 英特尔语法只是放弃它。

安迪·罗斯提供了更多的深层推理,但不幸的是,这个技术细节是错误的,或者至less是令人困惑的。 确实,只有(%esp)的有效地址不能用ModR / M字节进行编码,而是被解码为(%esp) ,这是用来表示SIB字节也包含在内的。 但是, %eiz伪寄存器并不总是与SIB字节一起使用来表示使用了SIB字节。

SIB字节(比例/索引/基数)有三个部分:索引(一个寄存器,例如%eax%ecx ,即比例应用于),比例(从1到8的两个幂索引寄存器乘以)和基址(另一个被添加到缩放索引的寄存器)。 这是允许的指令,如add %al,(%ebx,%ecx,2) (机器码: 00 04 4b – 操作码,modr / m,sib(注意即使使用SIB字节,也不注意%eiz寄存器) ))(或在Intel语法中,“add BYTE PTR [ecx * 2 + ebx],al”)。

但是, %esp不能用作SIB字节中的索引寄存器。 而不是允许这个选项,而是增加一个选项来使用基址寄存器,没有缩放或索引。 因此,要在add %al,(%ecx) (机器码: 00 01 – opcode,modr / m)的情况下add %al,(%ecx) (机器码: 00 04 21 – opcode,modr / m,sib),则使用替代语法add %al,(%ecx,%eiz,1) (或对于Intel语法: add BYTE PTR [ecx+eiz*1],al )。

正如Sinan所链接的文章所解释的那样,这个特定的指令( lea 0x0(%esi,%eiz,1),%esi )仅仅被用作多字节的nop(相当于esi = &*esi )只需要执行一条nop指令而不是多条nop指令。