我正在尝试计算汇编中的表达式:
7 * (4 + 10) + (15 / 5)
。我假设 BEDMAS 原则仍然适用,但我运行的代码没有给我正确的数值。DIV
时,它不会自动除以AX
寄存器中的值吗?
MOV BX,10
ADD BX,4
MOV AX,15
MOV BL,5
DIV BL
ADD AX,BX
MOV BX, 7
MUL BX
HLT
当我们调用
时,它不会自动除以DIV
寄存器中的值吗?AX
在 8086 中,有一个 byte 大小的分区和一个 word 大小的分区。
div
将 AX 除以您提供的任何字节大小的源操作数,例如。 div bl
。商归入 AL,余数归入 AH。div
将 DX:AX 除以您提供的任何字大小的源操作数,例如。 div bx
。商归入 AX,余数归入 DX。因此,在
MOV AX,15
MOV BL,5
DIV BL
中,您正在执行完美的字节大小除法。事实是,通过用除法器 5 加载 BL,您破坏了之前存储在 BX 寄存器中的总和 10 + 4。请记住,BL 不是一个单独的寄存器:它是我们给 BX 寄存器的最低 8 位起的名称。 BH 也是如此,BH 是我们给 BX 寄存器的最高 8 位起的名字。类似的规则适用于以下 16 位寄存器:AX、BX、CX 和 DX。
MOV BX,10 ADD BX,4 MOV AX,15 MOV BL,5 DIV BL ADD AX,BX <<<< Forgot to zero AH beforehand (i) MOV BX, 7 MUL BX <<<< Needlessly clobbers DX (ii)
(i) 幸运的是 AH 中的余数为零,但一般来说,您应该扩展 AL 中的商以覆盖整个 AX 寄存器。
(ii) DX clobber 的存在是因为在 8086 中存在 byte 大小和 word 大小的乘法。
mul
将 AL 乘以您提供的任何字节大小的源操作数,例如。 mul bl
。产品转到 AX。mul
将 AX 乘以您提供的任何字大小的源操作数,例如。 mul bx
。产品转到 DX:AX。除了上面提到的“缺陷”之外,这个计算不遵循正常的代数规则。
您已计算出 7 * ( (4 + 10) + (15 / 5) ),而任务要求 ( 7 * (4 + 10) ) + (15 / 5)
7 * (4 + 10) + (15 / 5)
B球拍是第一位的。而且由于这两组括号位于同一级别(它们不相互嵌套),因此我们计算它们的值的顺序并不重要。因为我们知道字节大小的除法仅在 AX 上运行,所以我们正在仔细选择其他一些寄存器来保存总和:
; (4 + 10) then (15 / 5) ; (15 / 5) then (4 + 10)
mov bl, 4 mov ax, 15
add bl, 10 ; -> BL=14 mov cl, 5
mov ax, 15 div cl ; -> AL=3
mov cl, 5 mov bl, 4
div cl ; -> AL=3 add bl, 10 ; -> BL=14
我们可以替换这些值并继续下一步。
7 * 14 + 3
M乘法必须在A加法之前,并且由于字节大小的乘法在架构上使用 AL 寄存器,因此我们必须首先将当前在 AL 中的值 3 复制到另一个寄存器:
mov cl, al ; Free AL, making CL=3
mov al, 7
mul bl ; BL=14 -> AX=98
add al, cl ; CL=3 -> AL=101
如果参与的数字更大,则可能需要一个字大小的解决方案。然后我们需要预先将 DX 寄存器清零,因为字大小的除法实际上将 DX:AX 除以字大小的操作数:
; (4 + 10) then (15 / 5) ; (15 / 5) then (4 + 10)
xor dx, dx xor dx, dx
mov bx, 4 mov ax, 15
add bx, 10 ; -> BX=14 mov cx, 5
mov ax, 15 div cx ; -> AX=3
mov cx, 5 mov bx, 4
div cx ; -> AX=3 add bx, 10 ; -> BX=14
由于字长乘法在架构上使用 AX 寄存器,因此我们必须首先将 AX 中当前的值 3 复制到另一个寄存器:
mov cx, ax ; Free AX, making CX=3
mov ax, 7
mul bx ; BX=14 -> DX:AX=98
add ax, cx ; CX=3 -> AX=101