2

我正在编写一个 8086 汇编程序,它接受指令并生成 8086 机器代码。我使用“Intel 8086 用户手册”作为参考。

为了清楚起见,我将解释情况。假设我想组装这条指令mov ax, bx。我会查手册发现,当 的操作数mov是 2 个 16 位寄存器时,操作码为movis0x89并指定操作数(源和目标)mov,在这种情况下,后面跟着一个 ModRegRm 字节,指定源和目的地,在这种情况下,是0xd8。二进制中的这个字节 = 11011000

Mod 为 2 位,Reg、Rm 各为 3 位。所以,Mod = 11,Reg = 011,Rm = 000。这里很简单,但有一些我不明白的地方,那就是寻址模式和位移。

模式表

查看表格和以下三个指令及其机器代码。

mov [bx+0x6], ax ;894706

mov [bx+0xbf],ax ;8987BF00

mov [bx+0xffff],ax ;8947FF

假设每条指令中的位移长度分别为 8 位、8 位、16 位,我错了吗?

我认为我是对的,因为它很明显,0x6并且0xbf是 1 字节和0xffff2 字节。

问题是,为什么第二条指令中的 MOD 字段10b or 0x02不是01b or 0x01? 应该是0x01因为位移是8bit位移吧?为什么0x01即使位移是16位,MOD也在第三条指令中?为什么汇编程序忽略了其余的位移而只捕获了 1 个字节?

4

1 回答 1

4

位移的大小取决于“MOD”字段(例如,如果 MOD=001b,则为 8 位,如果 MOD=010b,则为 16 位)并且符号扩展为预期大小。

这意味着类似的指令mov [bx+6], ax可以编码为mov [bx+0x0006], ax(MOD=010b 和 16 位位移),也可以编码为mov [bx+0x06], ax(MOD=001b 和 8 位位移)。

同理,mov [bx+65535],ax可以任意编码(8位位移或16位位移);因为 0xFF 可以符号扩展为 0xFFFF。

然而; mov [bx+191],ax不能编码为 8 位位移,因为当 191 (0xBF) 符号扩展时,它变成 0xFFBF,不等于 191。它必须使用 16 位位移。

本质上; 如果整个 16 位位移的最高 9 位都相同(值 0x0000 到 0x007F 全部清除,或者值 0xFF80 到 0xFFFF 全部设置)它可以编码为 8 位位移或 16 位位移; 否则必须使用 16 位位移。

当在不同的编码之间进行选择时;一个好的汇编程序会选择最小的可能性(并使用 8 位位移,因为它会使指令缩短 1 个字节)。一个更好的汇编器可以使用更大的版本,如果它避免了填充的需要(如果下面的指令需要在某个边界上对齐)。举个例子,然后考虑-.align 2对于较小的(3 字节),您必须在4字节)你没有(所以它少了1条指令,但结果代码的字节数相同)。mov [bx+6], ax.align 2clcmovnopclcalign 2mov

于 2020-05-10T10:51:38.827 回答