虚拟机指令的执行
执行流程图
总结昨天的算法,我画了一个图以更直观的表示出执行过程。
整数算术运算指令
今天先来学习下基本的加减乘除指令是怎样执行的?
指令 | 含义 | 操作码 |
---|
ADD $R1,$R2,$R3 | $R1=$R2+$R3 | 16 |
SUB $R1,$R2,$R3 | $R1=$R2-R3 | 18 |
MULT $R1,$R2,$R3 | $R1=$R2*$R3 | 20 |
DIV $R1,$R2,$R3,$R4 | $R1=$R3/$R4和$R2=$R3%$R4 | 22,24 |
下面的代码部分就是这些操作的执行过程。
1 2 3 4 5 6 7 8 9
| ADD: R[RAM[R[$IP]+1]]=R[RAM[R[$IP]+2]]+R[RAM[R[$IP]+3]]; R[$IP]=R[$IP]+4; SUB: R[RAM[R[$IP]+1]]=R[RAM[R[$IP]+2]]-R[RAM[R[$IP]+3]]; R[$IP]=R[$IP]+4; MULT: R[RAM[R[$IP]+1]]=R[RAM[R[$IP]+2]] * R[RAM[R[$IP]+3]]; R[$IP]=R[$IP]+4;
|
加减乘处理过程都比较简单,取出地址的值,进行运算就可。而除这个操作就比较复杂一些,因为在执行指令之前需要检查除数是否为零。如果为0,虚拟机将把”0xFFFFFFFFFFFFFFFFF”放到除法指令的第一个寄存器操作数里去。
1 2 3 4 5 6 7 8 9 10
| DIV: if(R[RAM[R[$IP]+4]]==0){ ERROR0_LVL2("Divide by zero!\n") R[RAM[R[$IP]+1]]=R[RAM[R[$IP]+2]] =0xFFFFFFFFFFFFFFFFF" } else{ R[RAM[R[$IP]+1]]=R[RAM[R[$IP]+3]]/R[RAM[R[$IP]+4]]; R[RAM[R[$IP]+2]]=R[RAM[R[$IP]+3]]%R[RAM[R[$IP]+4]]; } R[$IP]=R[$IP]+5;
|
通过学习上面通用的算法,回到sub_E90函数中,突然惊奇的发现switch分支的最前面一部分就是整数算术运算指令的处理过程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| case 128: v11 = *((_WORD *)v1 + (unsigned __int8)v7[2] + 8) + *((_WORD *)v1 + (unsigned __int8)v7[3] + 8); goto LABEL_25; case 129: *((_WORD *)v1 + (unsigned __int8)v7[1] + 8) += __ROL2__(*((_WORD *)v7 + 1), 8); return v2; case 130: v12 = *((_WORD *)v1 + (unsigned __int8)v7[2] + 8) - *((_WORD *)v1 + (unsigned __int8)v7[3] + 8); goto LABEL_57; case 131: *((_WORD *)v1 + (unsigned __int8)v7[1] + 8) -= __ROL2__(*((_WORD *)v7 + 1), 8); return v2; case 132: v11 = *((_WORD *)v1 + (unsigned __int8)v7[2] + 8) * *((_WORD *)v1 + (unsigned __int8)v7[3] + 8); goto LABEL_25; case 133: *((_WORD *)v1 + (unsigned __int8)v7[1] + 8) *= __ROL2__(*((_WORD *)v7 + 1), 8); return v2; case 134: v2 = 0; v12 = *((_WORD *)v1 + (unsigned __int8)v7[2] + 8) / *((_WORD *)v1 + (unsigned __int8)v7[3] + 8); goto LABEL_57; case 135: v2 = 0; *((_WORD *)v1 + (unsigned __int8)v7[1] + 8) /= __ROL2__(*((_WORD *)v7 + 1), 8); return v2; case 136: v2 = 0; *((_WORD *)v1 + (unsigned __int8)v7[1] + 8) = *((_WORD *)v1 + (unsigned __int8)v7[2] + 8) % *((_WORD *)v1 + (unsigned __int8)v7[3] + 8); return v2; case 137: v2 = 0; *((_WORD *)v1 + (unsigned __int8)v7[1] + 8) %= __ROL2__(*((_WORD *)v7 + 1), 8); return v2; case 138: v11 = *((_WORD *)v1 + (unsigned __int8)v7[2] + 8) & *((_WORD *)v1 + (unsigned __int8)v7[3] + 8); goto LABEL_25; case 139: *((_WORD *)v1 + (unsigned __int8)v7[1] + 8) &= __ROL2__(*((_WORD *)v7 + 1), 8); return v2; case 140: v11 = *((_WORD *)v1 + (unsigned __int8)v7[2] + 8) | *((_WORD *)v1 + (unsigned __int8)v7[3] + 8); goto LABEL_25; case 141: *((_WORD *)v1 + (unsigned __int8)v7[1] + 8) |= __ROL2__(*((_WORD *)v7 + 1), 8); return v2; case 142: v11 = *((_WORD *)v1 + (unsigned __int8)v7[2] + 8) ^ *((_WORD *)v1 + (unsigned __int8)v7[3] + 8); case 143: *((_WORD *)v1 + (unsigned __int8)v7[1] + 8) ^= __ROL2__(*((_WORD *)v7 + 1), 8); return v2;
|
上面的代码部分涵盖了加、减、乘、除(整除、取余)、与、或、异或操作,其中每两个为一组,区别在于:前一个为三操作数的指令,后一个为两操作数的指令。拿三操作数加法指令为例分析。
1 2 3 4 5 6
| case 128: v11 = *((_WORD *)v1 + (unsigned __int8)v7[2] + 8) + *((_WORD *)v1 + (unsigned __int8)v7[3] + 8); goto LABEL_25; LABEL_25: *((_WORD *)v1 + (unsigned __int8)v7[1] + 8) = v11; return v2;
|
这里采用无符号整型数,将寄存器2和寄存器3里的值相加的结果传入v11,跳出到LABEL_25。在LABEL_25处,再将v11传入寄存器1中进行返回,采用了一个间接赋值操作机制。
总结
myvm中只涉及到整数的算术运算指令,如果遇到浮点型的数,可能就会出错,在这里需要完善一下,加一下格式转换和对小数点的处理等情况。明天将继续分析switch分支的情况。