拆弹过程中,遇到一条objdump给出的相当奇怪的指令:
lea 0x0(%esi,%eiz,1),%esi
我们知道那些常用的x86寄存器,那么,%eiz又是什么?
google了一下,除了google非常好心地询问我是不是想找%eip之外,相当多询问同样问题的人得到这样的解答:
%eiz是一个伪寄存器(pseudo-register ),总是读出0值,就像MIPS的R0那样。
好高级!寄存器都有伪的……
但是,之后就更加困惑了
lea 0x0(%esi,%eiz,1),%esi
从语义上来看就相当于:
lea 0x0(%esi),%esi
就又相当于:
lea (%esi),%esi
就相当于
mov %esi,%esi
也就是一句nop。
GCC又不是唐僧,为什么使用这种罗嗦的方式表达毫无意义的操作?实在想不明白……
继续google,翻了相当多老美的抱怨之后,一篇blog令我豁然开朗。
GCC在代码中插入nop是为了保证代码按照特定字节对齐,这个好理解。
nop只占一个字节,于是想对齐多少,GCC就插入多少nop。
后来有GCC的一些高玩发现,Intel CPU执行单条语句会比执行同功能的多条语句要快,嗯,即使是nop这样的无功能的语句。于是GCC开始把多条连续的nop替换成单条同样字节长度的无意义语句。
于是就有了那个奇怪写法的LEA。
太神奇了!