57

在以下我使用的汇编代码中objdump

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

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

4

3 回答 3

59

请参阅为什么 GCC LEA EIZ?

显然%eiz是一个伪寄存器,始终只计算为零(如r0在 MIPS 上)。

...

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

于 2010-03-31T14:03:16.367 回答
25

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

于 2012-08-28T17:06:57.433 回答
14

Andy Ross 提供了更多的基本推理,但不幸的是,它是错误的,或者至少对技术细节感到困惑。确实,just 的有效地址(%esp)不能仅使用 ModR/M 字节进行编码,因为它不会被解码为(%esp),它用于表示还包括 SIB 字节。但是,%eiz伪寄存器并不总是与 SIB 字节一起使用来表示使用了 SIB 字节。

SIB 字节(标度/索引/基数)包含三个部分:索引(应用比例的寄存器,例如%eax%ecx),比例(索引寄存器乘以从 1 到 8 的 2 的幂) by)和基数(添加到缩放索引的另一个寄存器)。这就是允许诸如add %al,(%ebx,%ecx,2)(机器代码:00 04 4b--opcode,modr/m,sib(注意没有 %eiz 寄存器,即使使用了 SIB 字节))(或在 Intel 语法中,“add BYTE PTR [ecx*2 +ebx], 人")。

但是,%esp不能用作 SIB 字节中的索引寄存器。英特尔没有允许此选项,而是添加了一个选项,可以按原样使用基址寄存器,而无需缩放或索引。因此,为了区分add %al,(%ecx)(machine code: 00 01-- opcode, modr/m) 和add %al,(%ecx)(machine code: 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 指令。

于 2014-01-15T04:06:13.123 回答