强大的x86指令
今天调试一个应用程序时,偶然中看到一条很长的x86指令,机器码有11个字节,目标操作数是一个堪称复杂的表达式,于是摘录下来。
1020f789 c78491c400000000000000 mov dword ptr [ecx+edx*4+0C4h],0
其中:
- 1020f789是这条指令的线性地址
- c78491c400000000000000是机器码
- mov dword ptr [ecx+edx*4+0C4h],0是指令的助记符,MOV是操作码,dword ptr [ecx+edx*4+0C4h]是目标操作数,0是源操作数
晚上回到家里后,拿出IA手册来查,虽然手册很厚,但是手册里描述的还是非常清楚明了,很快就明白了11个机器码的意义
- c7是“MOV r/m32, imm32”这种形式的MOV指令的操作码(Op Code),MOV指令可以说是形式最多的一条x86指令,根据操作数的类型的不同,又细分为很多种。比如“MOV r/m32, imm32”代表的是目标操作数是内存或者寄存器,而源操作数是立即数。也就是把一个立即数赋值给一个变量(在寄存器或者内存中)。
- 84是所谓的ModR/M字节,简单说就是用来指定地址模式,有时也翻译为取址模式,其中的R代表寄存器,M代表内存。ModR/M字节的编码在IA手册中有一张表可以查,
- 84代表的是[--][--]+disp32,表下的备注解释了[--][--]的意思:
- The [--][--] nomenclature means a SIB follows the ModR/M byte
- 通常方括号里是寄存器的名字,而这里,用这种形式表示,寄存器的使用方法是用接下来的一个字节单独描述的。这个字节有个专门的名字叫SIB。SIB代表的是Scale,Index和Base
- 91便是SIB字节,它的编码也有一张表,查表得知,ECX是Base,Index和Scale[EDX*4](Scale是4,EDX是Index)。
- 接下来的4个字节(32位)c4000000是“位移(displacement)”,也84所代表的[--][--]+disp32中的disp32
- 最后的四个字节是立即数
那么这样的复杂指令用来做什么呢?一种典型的使用场合就是用来循环处理一个数组,ECX指向数组的基地址,EDX做循环变量,索引数组的元素,而数组元素的长度可以为2、4、8三种。设计的真是别具匠心啊!