2010-03-31 122 views
49

在下面的汇编代码我甩了使用objdump什么是注册%eiz?

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

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

+1

您可能会发现http://sourceware.org/ml/binutils/2009-01/msg00081.html有趣。 – 2010-03-31 14:01:10

回答

51

Why Does GCC LEA EIZ?

显然%eiz是(在MIPS像r0)一个伪寄存器,只是计算结果为零时刻。

...

我最终发现的binutils大师伊恩·兰斯·泰勒邮件列表后,揭示了答案。有时GCC会在代码流中插入NOP指令,以确保正确对齐和类似的东西。 NOP指令需要一个字节,所以你会认为你可以根据需要添加尽可能多的字节。但根据Ian Lance Taylor的说法,芯片执行一条长指令比多条短指令要快。因此,不是插入七条NOP指令,而是使用一个bizarro LEA,它使用了七个字节,并且在语义上等同于一个NOP。

+2

聪明的人:)谢谢你的答案! 因此上面的代码只是nop的更长版本:P – Heartinpiece 2013-09-02 04:59:49

21

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

+1

感谢分享:) – 2012-08-29 01:25:08

12

安迪罗斯提供了更多的底层推理,但不幸的是或者至少在技术细节上引起混淆。确实,只有(%esp)的有效地址不能用ModR/M字节进行编码,而是被解码为(%esp),它用于表示还包含SIB字节。但是,%eiz伪寄存器并不总是与SIB字节一起使用来表示使用了SIB字节。 SIB字节(比例/索引/基数)有三个部分:索引(一个寄存器,例如%eax%ecx,该比例应用于),比例尺(2的幂从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指令。