位移值对 ModRegRm 字节的 Mod 字段有什么影响?

Kor*_*rdy 2 assembly machine-code sign-extension addressing-mode x86-16

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

为了说清楚,我将解释一下情况。假设我想汇编这条指令mov ax, bx。我查手册发现,当 的操作数mov是 2 个 16bit 寄存器时,操作码mov0x89和 来指定操作数(源和目的),mov在这种情况下,后面跟着一个 ModRegRm 字节,指定源以及目的地,在本例中为0xd8。二进制中的该字节 = 11011000.

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

modregrm 表

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

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位移吧?为什么位移量是 16 位,MOD 却0x01在第三条指令中?为什么汇编器忽略其余的位移并仅捕获 1 个字节?

Bre*_*dan 5

位移的大小取决于“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 2then mov [bx+6], axthen - 对于较小的(3 字节),您必须在 之前插入一条额外的指令作为填充.align 2,以确保指令在 2 字节边界上对齐(指令所要求的),对于较大的( 4 字节)你不需要(所以它少了 1 条指令,但结果代码的字节数相同)。clcmovnopclcalign 2mov