ASM8086:mul、imul、进位标志和溢出标志
ASM8086: mul, imul, carry flag and overflow flag
我理解了进位标志和溢出标志的逻辑。
但是,当我读到这个程序(写在 MASM 8086 中)时,我有点困惑。
程序的目的是判断二次方程是否有两个不同的解、两个相等的解或根本没有解。
.model small
.stack
.data
aa dw 2
bb dw 4
cc dw 2
sol_msg db "There exist two real solutions", CR, NL
no_sol_msg db "No real solutions! ", CR, NL
sol_coinc db "The two solutions coincide! ", CR, NL
.code
.startup
mov ax, bb
imul bb
jc overflow ; I decided to work at most with 16-bit numbers
push ax
mov ax, aa
imul cc
jc overflow
mov bx, 4
imul bx
jc overflow
pop bx
sub bx, ax
jo overflow
js mess2
jz mess3
lea si, sol_msg
jmp next
mess2: lea si, no_sol_msg
jmp next
mess3: lea si, sol_coinc
next: mov bx, LUNG_MSG
mov ah, 2
loop1: mov dl, [si]
INT 21h
inc si
dec bx
jnz loop1
jmp end1
overflow:
nop
end1:
.exit
end
现在,我的疑问是:为什么前三个检查测试了进位标志,最后一个测试了溢出标志?
因为在最后一个中,我们在两个有符号数之间进行减法(正如我们所想的那样),我们必须检查溢出标志以查看是否存在溢出(即如果数字超出区间[-2^15,2^15-1]
).
但是对于第一个,例如,我们用 imul
做 (bb)^2
。
所以我们认为它们是 16 位有符号数(所以 -2^15 <= bb <= 2^15-1
)并且如果至少有一个和(在乘法算法)打开 CF
/OF
位。
但是既然我们处理的是有符号数,难道我们不应该检查溢出标志吗?
我还注意到,自 2^15-1=32767
以来,如果我将 bb
设置为 190
(190^2=36100
),则 CF=0
;如果 bb
等于 200
(200^2=40000
) CF=1
.
这是为什么?谁能详细解释一下,好吗?
P.S.: 我用的是EMU8086.
对于 IMUL:
当中间产品的有符号整数值与符号不同时,设置 CF 和 OF 标志
扩展操作数大小截断乘积,否则清除 CF 和 OF 标志。为了
指令的一种操作数形式,当有效位被带入上半部分时,CF 和 OF 标志被设置
结果的部分,并在结果恰好位于结果的下半部分时清除。
IE。这些标志在这里几乎相等。
对于子:
SUB 指令执行整数减法。它评估有符号和无符号整数的结果
操作数并设置 OF 和 CF 标志以分别指示有符号或无符号结果中的溢出。科幻小说
flag 表示签名结果的符号。 OF 用于签名。检查指令集参考手册。即使对于这个旧代码,它仍然是实际的。
然而请看x86 flags
如果你看一下IMUL in Intel's docs的伪算法,你会看到
IF OperandSize = 16
THEN
TMP_XP ← AX ∗ SRC (* Signed multiplication; TMP_XP is a signed integer at twice the width of the SRC *)
DX:AX ← TMP_XP[31:0];
SF ← TMP_XP[15];
IF SignExtend(TMP_XP[15:0]) = TMP_XP
THEN CF ← 0; OF ← 0;
ELSE CF ← 1; OF ← 1;
FI;
FI;
CF
和 OF
要么都设置,要么都清除。因此,您可以在 IMUL
之后检查任一标志
我理解了进位标志和溢出标志的逻辑。 但是,当我读到这个程序(写在 MASM 8086 中)时,我有点困惑。
程序的目的是判断二次方程是否有两个不同的解、两个相等的解或根本没有解。
.model small
.stack
.data
aa dw 2
bb dw 4
cc dw 2
sol_msg db "There exist two real solutions", CR, NL
no_sol_msg db "No real solutions! ", CR, NL
sol_coinc db "The two solutions coincide! ", CR, NL
.code
.startup
mov ax, bb
imul bb
jc overflow ; I decided to work at most with 16-bit numbers
push ax
mov ax, aa
imul cc
jc overflow
mov bx, 4
imul bx
jc overflow
pop bx
sub bx, ax
jo overflow
js mess2
jz mess3
lea si, sol_msg
jmp next
mess2: lea si, no_sol_msg
jmp next
mess3: lea si, sol_coinc
next: mov bx, LUNG_MSG
mov ah, 2
loop1: mov dl, [si]
INT 21h
inc si
dec bx
jnz loop1
jmp end1
overflow:
nop
end1:
.exit
end
现在,我的疑问是:为什么前三个检查测试了进位标志,最后一个测试了溢出标志?
因为在最后一个中,我们在两个有符号数之间进行减法(正如我们所想的那样),我们必须检查溢出标志以查看是否存在溢出(即如果数字超出区间[-2^15,2^15-1]
).
但是对于第一个,例如,我们用 imul
做 (bb)^2
。
所以我们认为它们是 16 位有符号数(所以 -2^15 <= bb <= 2^15-1
)并且如果至少有一个和(在乘法算法)打开 CF
/OF
位。
但是既然我们处理的是有符号数,难道我们不应该检查溢出标志吗?
我还注意到,自 2^15-1=32767
以来,如果我将 bb
设置为 190
(190^2=36100
),则 CF=0
;如果 bb
等于 200
(200^2=40000
) CF=1
.
这是为什么?谁能详细解释一下,好吗?
P.S.: 我用的是EMU8086.
对于 IMUL: 当中间产品的有符号整数值与符号不同时,设置 CF 和 OF 标志 扩展操作数大小截断乘积,否则清除 CF 和 OF 标志。为了 指令的一种操作数形式,当有效位被带入上半部分时,CF 和 OF 标志被设置 结果的部分,并在结果恰好位于结果的下半部分时清除。 IE。这些标志在这里几乎相等。 对于子: SUB 指令执行整数减法。它评估有符号和无符号整数的结果 操作数并设置 OF 和 CF 标志以分别指示有符号或无符号结果中的溢出。科幻小说 flag 表示签名结果的符号。 OF 用于签名。检查指令集参考手册。即使对于这个旧代码,它仍然是实际的。 然而请看x86 flags
如果你看一下IMUL in Intel's docs的伪算法,你会看到
IF OperandSize = 16
THEN
TMP_XP ← AX ∗ SRC (* Signed multiplication; TMP_XP is a signed integer at twice the width of the SRC *)
DX:AX ← TMP_XP[31:0];
SF ← TMP_XP[15];
IF SignExtend(TMP_XP[15:0]) = TMP_XP
THEN CF ← 0; OF ← 0;
ELSE CF ← 1; OF ← 1;
FI;
FI;
CF
和 OF
要么都设置,要么都清除。因此,您可以在 IMUL