在下面的汇编程序中是否需要这条线?
Is this line necessary in the following Assembly Program?
我是 ALP 的新手,在查看这个程序时,我发现有一行我认为是不必要的,可以简单地删除,更改几行。
代码如下:
DATA SEGMENT
N1 DW 2804H
N2 DW 4213H
BCD_SUM DW ?
DATA ENDS
CODE SEGMENT
ASSUME CS: CODE, DS: DATA
START: MOV AX, DATA
MOV DS, AX
MOV AX, N1
MOV BX, N2
ADD AL, BL
DAA
MOV CL, AL
MOV AL, AH ; Here I have Problem
ADD AL, BH
DAA
MOV CH, AL
MOV BCD_SUM, CX
MOV AH, 4CH
INT 21H
CODE ENDS
END START
为什么不直接 add ah, bh
?
将 AX
处的高位字节移动到低位,然后添加,这有什么原因吗?或者我可以简单地更改它吗?
由于代码是当前编写的,因此该指令是必需的,因为它将所需的值放入AL
寄存器,为后续指令做准备。它后面的 ADD
指令显式使用 AL
中的值,下一个 DAA
指令(隐式)也是如此。
为了确保我们在同一页上,为了未来读者的利益,让我们浏览一下代码并对其进行注释:
; Set the segment register 'DS' to the constant value 'DATA'
; (indirectly via 'AX', since you can't move an immediate into a segment register).
MOV AX, DATA
MOV DS, AX
; Put the constant values 'N1' and 'N2' into the 'AX' and 'BX' registers, respectively.
MOV AX, N1
MOV BX, N2
; Add the lower 8 bits of 'BX' to the lower 8 bits of 'AX'.
ADD AL, BL
; Using the results of that last addition ('AL' and flags),
; adjust for packed binary-coded decimal arithmetic.
DAA
; Save the result (from 'AL') in 'CL' (since 'AL' is about to be clobbered).
MOV CL, AL
; Having just done the low 8 bits of 'AX' ('AL'), we are now going to do
; the high 8 bits ('AH'). But because the DAA instruction uses 'AL'
; as an implicit operand, we first need to swap 'AL' and 'AH'.
MOV AL, AH
ADD AL, BH
DAA
; Just like we saved the result of the low 8 bits in 'CL',
; save the result of the high 8 bits in 'CH'.
MOV CH, AL
; Now, the result is in 'CX' (low byte in 'CL', high byte in 'CH'),
; so store/save it into the WORD-sized variable 'BCD_SUM'.
MOV BCD_SUM, CX
; Call DOS interrupt to terminate the process.
;
; Note that there is a bug here: you should be setting the 'AL' register
; to the process's return code. You could do this explicitly with a
; 'MOV AL, ReturnCode' instruction, or you could just do
; 'MOV AX, 4C00h' to set both halves at once.
MOV AH, 4CH
INT 21H
希望你现在明白了原始代码的逻辑,以及为什么要这样写。它将完整的 WORD 大小的值加载到 AX
和 BX
寄存器中,然后对低字节(低 8 位)和高字节执行打包的二进制编码的十进制算术运算。最后,它将结果作为完整的 WORD 大小的值保存在 BCD_SUM
中,间接通过 CX
作为临时寄存器。
现在,您当然可以用不同的方式编写相同的代码,但仍然可以完成相同的任务。这基本上就是您在问题中的建议——重新排序说明,以便您:
ADD AH, BH ; add high bytes first
MOV AL, AH ; swap order of bytes
DAA ; adjust result of addition, now in AL
但是,这样写代码绝对没有任何优势。只是个人选择问题,你觉得哪个更清楚。
个人,我更喜欢先设置寄存器(和原来的代码一样),然后执行ADD
和 DAA
背靠背。为什么?因为 DAA
取决于 flags ,这些标志由 ADD
指令隐式设置(具体来说,辅助进位标志,AF
)。虽然 MOV
指令不会破坏标志,但 大多数 其他指令会破坏标志,因此养成将 ADD
和 DAA
指令分开的习惯可能会引入一个很难找到的错误。
像这样重新排列指令的唯一可能的好处是减轻数据依赖性,从而提高代码的执行速度。不过,这不会发生在这里,因为这三个指令之间仍然有一个完整的依赖链。
我是 ALP 的新手,在查看这个程序时,我发现有一行我认为是不必要的,可以简单地删除,更改几行。
代码如下:
DATA SEGMENT
N1 DW 2804H
N2 DW 4213H
BCD_SUM DW ?
DATA ENDS
CODE SEGMENT
ASSUME CS: CODE, DS: DATA
START: MOV AX, DATA
MOV DS, AX
MOV AX, N1
MOV BX, N2
ADD AL, BL
DAA
MOV CL, AL
MOV AL, AH ; Here I have Problem
ADD AL, BH
DAA
MOV CH, AL
MOV BCD_SUM, CX
MOV AH, 4CH
INT 21H
CODE ENDS
END START
为什么不直接 add ah, bh
?
将 AX
处的高位字节移动到低位,然后添加,这有什么原因吗?或者我可以简单地更改它吗?
由于代码是当前编写的,因此该指令是必需的,因为它将所需的值放入AL
寄存器,为后续指令做准备。它后面的 ADD
指令显式使用 AL
中的值,下一个 DAA
指令(隐式)也是如此。
为了确保我们在同一页上,为了未来读者的利益,让我们浏览一下代码并对其进行注释:
; Set the segment register 'DS' to the constant value 'DATA'
; (indirectly via 'AX', since you can't move an immediate into a segment register).
MOV AX, DATA
MOV DS, AX
; Put the constant values 'N1' and 'N2' into the 'AX' and 'BX' registers, respectively.
MOV AX, N1
MOV BX, N2
; Add the lower 8 bits of 'BX' to the lower 8 bits of 'AX'.
ADD AL, BL
; Using the results of that last addition ('AL' and flags),
; adjust for packed binary-coded decimal arithmetic.
DAA
; Save the result (from 'AL') in 'CL' (since 'AL' is about to be clobbered).
MOV CL, AL
; Having just done the low 8 bits of 'AX' ('AL'), we are now going to do
; the high 8 bits ('AH'). But because the DAA instruction uses 'AL'
; as an implicit operand, we first need to swap 'AL' and 'AH'.
MOV AL, AH
ADD AL, BH
DAA
; Just like we saved the result of the low 8 bits in 'CL',
; save the result of the high 8 bits in 'CH'.
MOV CH, AL
; Now, the result is in 'CX' (low byte in 'CL', high byte in 'CH'),
; so store/save it into the WORD-sized variable 'BCD_SUM'.
MOV BCD_SUM, CX
; Call DOS interrupt to terminate the process.
;
; Note that there is a bug here: you should be setting the 'AL' register
; to the process's return code. You could do this explicitly with a
; 'MOV AL, ReturnCode' instruction, or you could just do
; 'MOV AX, 4C00h' to set both halves at once.
MOV AH, 4CH
INT 21H
希望你现在明白了原始代码的逻辑,以及为什么要这样写。它将完整的 WORD 大小的值加载到 AX
和 BX
寄存器中,然后对低字节(低 8 位)和高字节执行打包的二进制编码的十进制算术运算。最后,它将结果作为完整的 WORD 大小的值保存在 BCD_SUM
中,间接通过 CX
作为临时寄存器。
现在,您当然可以用不同的方式编写相同的代码,但仍然可以完成相同的任务。这基本上就是您在问题中的建议——重新排序说明,以便您:
ADD AH, BH ; add high bytes first
MOV AL, AH ; swap order of bytes
DAA ; adjust result of addition, now in AL
但是,这样写代码绝对没有任何优势。只是个人选择问题,你觉得哪个更清楚。
个人,我更喜欢先设置寄存器(和原来的代码一样),然后执行ADD
和 DAA
背靠背。为什么?因为 DAA
取决于 flags ,这些标志由 ADD
指令隐式设置(具体来说,辅助进位标志,AF
)。虽然 MOV
指令不会破坏标志,但 大多数 其他指令会破坏标志,因此养成将 ADD
和 DAA
指令分开的习惯可能会引入一个很难找到的错误。
像这样重新排列指令的唯一可能的好处是减轻数据依赖性,从而提高代码的执行速度。不过,这不会发生在这里,因为这三个指令之间仍然有一个完整的依赖链。