前言
在学习了解计算机结构时,针对X86指令从汇编码到机器码的转换过程详解。
例题入手
在下方表格[1]里可以看到部分X86 ALU(Arithmetic Logic Unit)指令的操作码
表格[1]
下方表格[2]是部分寄存器位置对应的编码值,由于小编采用的是德国的教材,所以表格内部分文字描述是德语,我已对其翻译,不用担心。
表格[2]
以下表格[3]是Mod R/M Byte编码格式
表格[3]
以上信息为题干信息,现在来看求解题目:
根据给出的操作码(第一列)以及编码长度(第3列)求其对应的机器编码(第二列)
-
AND eax, 0
首先根据指令得出操作码为 AND,然后Scr.1为寄存器eax, Scr.2是0为1Byte的立即操作数,在表格[1]中找到操作码AND对应的值为0x83/4 (0x83是操作码,4是偏移量)由于是eax,0 属于寄存器直接寻址,所以Mod的值为11;当Mod值为11时(即寄存器直接寻址),Reg对应的是源寄存器,R/M对应的是目标寄存器, 其余情况下Reg对应的是目标寄存器,R/M对应的是源寄存器。 所以有偏移量4所以Reg.对应为100,R/M为000
Mod Reg R/M 11 100 000 Mod R/M 码段对应的16进制为e0,整个指令的机器码为操作码 0x83 + e0 +立即操作数的16进制形式 00 = 0x83e000。如果立即操作数为10则将最后两位改为0a
2. MOV ebx, [ecx]
首先根据指令得出操作码为 MOV,然后Scr.1为寄存器ebx, Scr.2表示寄存器存储的是地址,在表格[1]中找到操作码MOV对应的值为0x8B
由于是ebx, [ecx]属于 寄存器非直接寻址,所以Mod的值为00;当Mod值为00时(即寄存器非直接寻址),Reg对应的是目标寄存器,R/M对应的是源寄存器。 根据表[2]ebx为011 所以Reg为011,ecx 为001,所以R/M为001
Mod | Reg | R/M |
---|---|---|
00 | 011 | 001 |
对应的16进制为19
Mod R/M 码段对应的16进制为19,整个指令的机器码为操作码0x8B19。
3. ADD ebx, [ecx+4]
首先根据指令得出操作码为 ADD,然后Scr.1为寄存器ebx, Scr.2表示寄存器存储的是地址加上偏移量4,在表格[1]中找到操作码MOV对应的值为0x03
由于是ebx, [ecx+4]属于 寄存器非直接寻址且有偏移,所以Mod的值根据表格[2]为01;Reg对应的是目标寄存器,R/M对应的是源寄存器。 根据表[2]ebx为011 所以Reg为011,ebx 为011,R/M为001
Mod | Reg | R/M |
---|---|---|
01 | 011 | 001 |
对应的16进制为59
Mod R/M 码段对应的16进制为59,然后在末尾加上位移4的16进制码为04,所以整个指令的机器码为操作码0x035904。
4. AND eax, ebx
首先根据指令得出操作码为 AND,然后Scr.1为寄存器eax, Scr.2表示寄存器ebx,在表格[1]中找到操作码MOV对应的值为0x21
由于eax, ebx属于 寄存器直接寻址,所以Mod的值为11;当Mod值为1时(即寄存器直接寻址),Reg对应的是源寄存器,R/M对应的是目标寄存器。 根据表[2]eax为000 所以R/M为000,ebx 为011,所以Reg为011
Mod | Reg | R/M |
---|---|---|
11 | 011 | 000 |
对应的16进制为d8
Mod R/M 码段对应的16进制为d8,整个指令的机器码为操作码0x21d8。
5. MOV ebx, [ecx +8]
参考 ADD exb, [ecx+8] ,结果为0x8b5908
6. OR eax, ebx
参考 AND eax, ebx, 结果为0x09d8
7. SUB eax, 200
首先根据指令得出操作码为 SUB,然后Scr.1为寄存器eax, Scr.2表示立即操作数200,在表格[1]中找到操作码SUB对应的值为0x2d(因为200是对应的4Byte)
这里由于立即操作数是200所以用4Byte表示为c8 00 00 00,这是SUB针对立即操作数比较特殊的地方,此时Mod R/M不再适用。
直接得出结果是 0x2dc8000000.
- SUB eax, 1;对应的编码长(Codelang) 为3B(补充题)
当立即操作数是1Byte时,例子是1 ,此时按照之前正常的逻辑进行处理如下:
根据表格[1] 操作码是SUB, 然后Scr.1为寄存器eax, Scr.2表示立即操作数1,在表格[1]中找到操作码SUB对应的值为0x83/5 (操作码为0x83,有偏移量5)
由于eax, 1属于 寄存器直接寻址,所以Mod的值为11;当Mod值为1时(即寄存器直接寻址),Reg对应的是源寄存器,R/M对应的是目标寄存器。 根据表[2]eax为000 所以R/M为000,Reg为偏移量5, 101
Mod | Reg | R/M |
---|---|---|
11 | 101 | 000 |
对应的16进制为e8
所以整个应该就是操作码0x83+e8+01(偏移量)=0x83e801.
当立即操作数为4Byte时和1Byte时,处理过程不一样,是因为 0x2D 是一个专用操作码,用于从 EAX 寄存器中减去 32 位立即数,所以立即数 200 必须被扩展为 32 位。由于历史原因,我们使用小端位数记数法来记录即时数据。在过去,当 16 位总线还很普遍的时候,可以用这种方式开始计算,因为转移是从最小有效位 (LSB) 计算到最大有效位 (MSB)(比较写入的乘法/加法)。
分析总结
除开SUB 操作码针对4Byte立即操作数时,适用Mod R/M 模型来处理;当Src.1 和Src.2都是寄存器时,属于寄存器直接寻址,Mod 为11,此时Reg和R/M的数据要进行互换一下,参考上面的例子;
如果是Src.1是寄存器,Src.2表示存储的是地址且无偏移量的情况下,那么就是非直接寻址,Mod 为00,如果在非直接寻址情况下,有偏移量,那么Mod就需要根据偏移量的大小参考表格[2]去选择是01还是10。然后Reg R/M 在剩余的3中情况下都不需要互换,参考上面的例子。
最后给大家提供一个用于检查从汇编码到机器码的转换的网站,可以验证自己是否正确转换。由于小编在G国,所以不确定这个网站国内是否适用,如果不适用的话请留言,谢谢!
欢迎阅读,以及欢迎指出不足之处,如果点赞就更好了;
祝您学习愉快~😊😊😊