设置表示flag value = 1
,未设置表示flag value = 0
现在我了解了在MASM中设置和取消设置标志的几种方法,如下所示:
test al,0 ; set Zero flag
and al,0 ; set Zero flag
or al,1 ; clear Zero flag
Sign flag
也一样:
or al,80h ; set Sign flag
and al,7Fh ; clear Sign flag
要设置Carry flag
,我们使用STC指令;要清除“进位”标志,我们使用CLC:
stc ; set Carry flag
clc ; clear Carry flag
要设置Overflow flag
,我们添加两个产生负数和的正值。要清除Overflow flag
,我们将操作数与0:
mov al,7Fh ; AL = +127
inc al ; AL = 80h (-128), OF=1
or eax,0 ; clear Overflow flag
Overflow
和Carry
标志操作是易于理解和易于理解的,但是我发现很难理解设置Zero/Sign
标志背后的数学原理。任何帮助表示赞赏!
谢谢!
答案 0 :(得分:5)
使用标志的全部目的是它们是其他操作的副作用-您可以在操作发生后测试结果。
例如,您可以从10
倒数到0
,而无需明确测试零:
mov cx, 10
Again:
; Do some stuff, not changing cx
dec cx
jnz Again ; Go back to Again if not zero
“做某事”发生了十次,因为dec
影响了Z
标志。
存在stc
和clc
的原因是为了帮助进行多位数算术。 C
标志用于跟踪先前算术中的“进位”,以便您可以将它们纳入将来的操作中:
op1 dd 0x12345678 ; 32-bit value
op2 dd 0x9abcdef0 ; 32-bit value
mov ax,[op1+0] ; Get low word of op1
mov dx,[op1+2] ; Get high word of op1
add ax,[op2+0] ; Add in low word of op2
adc dx,[op2+2] ; Add in high word of op2 - WITH CARRY!
由于这些类型的操作,您可能需要在开始算法之前,先将C
或0
加载到1
中。因此,clc
和stc
-以及为什么没有其他(算术)标志具有“设置”或“清除”操作码的原因。
请注意,还有其他非算术标记:
D
(方向)标志控制诸如STOS
和MOVS
之类的字符串指令的方向。
因此,有cld
和std
条指令。I
(中断)标志控制是否启用中断。
因此,有cli
和sti
条指令。答案 1 :(得分:4)
SF和ZF仅基于结果而不是输入进行设置。
SF是结果的最高位,因此(对于位模式的2的补码解释),这意味着结果为负。
SF = ((signed)result < 0);
ZF = (result == 0);
您也可以说ZF是所有位的水平或,取反。 (如果只有一个设置位,则清除该信息。)
当然result
是8、16、32或64位,具体取决于操作数的大小。对于neg al
之类的指令,这些标志是根据实际输出的高位和零值而不是其所属的完整寄存器设置的。
当然不是所有指令都设置所有标志,例如inc
/ dec
famously会保持CF不变,而以常规方式设置其他标志,它可以在adc
循环中使用。
Rotates仅设置CF,并且(对于隐式移位1操作码)也设置OF。 SF / ZF / PF保持不变,这与常规的非循环移位不同。除非移位计数为零,否则所有标志都不会被修改。这是problematic for out-of-order execution的移位和轮换(标志是可变计数移位/轮换的额外依赖项),这就是BMI2 shlx
/ shrx
在Intel上更快的原因。而rol
/ ror
是多余的。
BSF / BSR根据输入(不是结果)设置ZF,如果输入为零,则不修改输出寄存器。
在这种情况下,英特尔的文档说“未定义”,但是AMD记录了所有硬件实际实现的未修改行为。我认为英特尔不太可能构建不会实现未修改行为的硬件,尤其是现在BMI1 lzcnt
/ tzcnt
为我们提供了没有虚假依赖的替代方案。 IDK为什么他们不只是记录bsf
/ bsr
如何在其硬件上工作。