什么是寄存器 %eiz?
Posted
技术标签:
【中文标题】什么是寄存器 %eiz?【英文标题】:What is register %eiz? 【发布时间】:2011-02-02 22:55:45 【问题描述】:在我使用objdump
转储的以下汇编代码中:
lea 0x0(%esi,%eiz,1),%esi
什么是寄存器%eiz
?上面的代码是什么意思?
【问题讨论】:
你可能会觉得sourceware.org/ml/binutils/2009-01/msg00081.html很有趣。 【参考方案1】:见Why Does GCC LEA EIZ?:
显然
%eiz
是一个伪寄存器,它始终只计算为零(就像 MIPS 上的r0
)。
...
我最终找到了 binutils 大师 Ian Lance Taylor 的邮件列表帖子,其中揭示了答案。有时 GCC 会在代码流中插入 NOP 指令以确保正确对齐和类似的东西。 NOP 指令占用一个字节,因此您会认为可以根据需要添加任意数量的字节。但根据 Ian Lance Taylor 的说法,芯片执行一条长指令比执行许多短指令要快。因此,它们没有插入 7 个 NOP 指令,而是使用了一个 bizarro LEA,它占用了 7 个字节并且在语义上等同于 NOP。
【讨论】:
聪明人 :) 感谢您的回答!因此上面的代码只是 nop 的更长版本:P 更具体地说,它是一个不必要的 SIB 字节的占位符,它编码没有索引的寻址模式。【参考方案2】:Andy Ross 提供了更多基本推理,但不幸的是,他错了,或者至少对技术细节感到困惑。确实,仅(%esp)
的有效地址不能仅使用 ModR/M 字节进行编码,因为它不会被解码为 (%esp)
,它用于表示还包括 SIB 字节。但是,%eiz
伪寄存器并不总是与 SIB 字节一起使用来表示使用了 SIB 字节。
SIB 字节(标度/索引/基址)包含三个部分:索引(应用标度的寄存器,例如 %eax
或 %ecx
),标度(从索引寄存器乘以 1 到 8)和基数(添加到缩放索引的另一个寄存器)。这就是允许诸如 add %al,(%ebx,%ecx,2)
之类的指令(机器代码:00 04 4b
-- opcode, modr/m, sib(注意没有 %eiz 寄存器,即使使用了 SIB 字节))(或者在 Intel 语法中,“添加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
)。
正如思南链接的文章中所解释的,这条特定指令(lea 0x0(%esi,%eiz,1),%esi
)仅用作多字节 nop(相当于esi = &*esi
),因此只需执行一条类似 nop 的指令而不是多个 nop 指令。
【讨论】:
顺便说一句,ESP 不能成为索引的原因是(%esp)
是一种比(%esp, %esp, 1..8)
更有用的寻址模式。由于您无法在没有 SIB 字节的情况下对 base=ESP 进行编码,因此您需要某种方式来指定无索引。 (因为没有基地需要 disp32,而且他们不想要求 disp32=0( , %esp, 1)
使 ESP 相对寻址变得不合理地昂贵。)【参考方案3】:
(游戏很晚,但这似乎是一个有趣的补充):它根本不是一个寄存器,它是 Intel 指令编码的一个怪癖。当使用 ModRM 字节从内存中加载时,寄存器字段有 3 位用于存储 8 个可能的寄存器。但是,ESP(堆栈指针)“将”所在的位置被处理器解释为“SIB 字节遵循该指令”(即,它是扩展寻址模式,而不是对 ESP 的引用)。由于只有作者知道的原因,GNU 汇编器总是将这个“寄存器本来应该是零”表示为“%eiz”寄存器。英特尔语法只是删除它。
【讨论】:
binutils 仅对 redundant SIB 字节执行此操作(即 E/RSP 以外的基本字节,并且没有索引)。它使用(%esp)
/ (%rsp)
而不是(%esp, %eiz, 1)
。
这是适合 GNU 汇编器的输入,还是只是反汇编器的功能?
上述原因可能是IZ代表索引零。以上是关于什么是寄存器 %eiz?的主要内容,如果未能解决你的问题,请参考以下文章