什么是注册%eiz?

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

看看为什么GCC LEA EIZ?:

显然%eiz是一个伪寄存器,只是在任何时候都评估为零(如r0MIPS).

...

我最终找到了binutils大师伊恩兰斯泰勒的邮件列表帖子,揭示了答案.有时GCC会将NOP指令插入到代码流中,以确保正确对齐和类似的东西.NOP指令占用一个字节,因此您可以认为可以根据需要添加任意数量的字节.但根据Ian Lance Taylor的说法,芯片执行一条长指令要比许多短指令快.因此,它们不是插入七条NOP指令,而是使用一个奇怪的LEA,它占用了7个字节,在语义上等同于NOP.

  • 更具体地说,它是不必要的 SIB 字节的占位符,它对没有索引的寻址模式进行编码。 (4认同)
  • 聪明的人:)谢谢你的答案!因此上面的代码只是nop的较长版本:P (2认同)

And*_*oss 23

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

  • binutils 仅对*冗余* SIB 字节执行此操作(即除 E/RSP 之外的基础字节,并且没有索引)。它使用 `(%esp)` / `(%rsp)` 而不是 `(%esp, %eiz, 1)`。 (2认同)

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指令.

  • 顺便说一句,ESP 不能成为索引的原因是“(%esp)”是比“(%esp,%esp, 1..8)”更有用的寻址模式。由于您无法在没有 SIB 字节的情况下对 base=ESP 进行编码,因此您需要某种方法来指定无索引。(因为没有基数需要 disp32,并且他们不想要求 `disp32=0( , %esp, 1)` 来使 ESP 相对寻址变得不合理地昂贵。) (3认同)