Setting/Unsetting MASM 标志如何工作
How Does Setting/Unsetting MASM Flags Work
设置表示 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
标志背后的数学原理。感谢您的帮助!
谢谢!
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 only set CF, and (for the implicit shift-by-1 opcode) also OF. SF/ZF/PF remain unmodified, unlike with regular non-circular shifts. Unless the shift count was zero, in which case all the flags are unmodified. This is 的移位和旋转(标志是变量计数 shifts/rotates 的额外依赖项),这就是 BMI2 shlx
/shrx
在 Intel 上更快的原因. rol
/ror
是额外的微指令。
BSF / BSR 根据 输入(不是结果)设置 ZF,如果输入为零,则保持输出寄存器不变。
Intel 的文档在那种情况下说 "undefined",但 AMD 记录了所有硬件实际实现的未修改行为。我认为英特尔不太可能构建不实现未修改行为的硬件,尤其是现在 BMI1 lzcnt
/tzcnt
为我们提供了一个没有错误依赖的替代方案。 IDK 为什么他们不只是记录 bsf
/bsr
如何在他们的硬件上工作。
使用标志的全部意义在于它们是其他操作的副作用 - 您可以在操作发生后测试结果。
因此,例如,您可以从 10
倒数到 0
而无需显式测试零:
mov cx, 10
Again:
; Do some stuff, not changing cx
dec cx
jnz Again ; Go back to Again if not zero
"Do some stuff" 发生了十次,因为 dec
影响了 Z
标志。
stc
和clc
存在的原因是为了帮助进行多位数运算。 C
标志用于跟踪先前算法中的 "Carries",以便您可以将它们纳入未来的操作:
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!
由于这些类型的操作,您可能需要在开始算法之前使用 0
或 1
预加载 C
。因此 clc
和 stc
- 以及为什么没有其他(算术)标志具有 "set" 或 "clear" 操作码。
请注意还有其他非算术标志:
D
(方向)标志控制字符串指令的方向,例如STOS
和MOVS
。
因此有 cld
和 std
指令。
I
(中断)标志控制是否启用中断。
因此有 cli
和 sti
指令。
设置表示 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
标志背后的数学原理。感谢您的帮助!
谢谢!
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 only set CF, and (for the implicit shift-by-1 opcode) also OF. SF/ZF/PF remain unmodified, unlike with regular non-circular shifts. Unless the shift count was zero, in which case all the flags are unmodified. This is shlx
/shrx
在 Intel 上更快的原因. rol
/ror
是额外的微指令。
BSF / BSR 根据 输入(不是结果)设置 ZF,如果输入为零,则保持输出寄存器不变。
Intel 的文档在那种情况下说 "undefined",但 AMD 记录了所有硬件实际实现的未修改行为。我认为英特尔不太可能构建不实现未修改行为的硬件,尤其是现在 BMI1 lzcnt
/tzcnt
为我们提供了一个没有错误依赖的替代方案。 IDK 为什么他们不只是记录 bsf
/bsr
如何在他们的硬件上工作。
使用标志的全部意义在于它们是其他操作的副作用 - 您可以在操作发生后测试结果。
因此,例如,您可以从 10
倒数到 0
而无需显式测试零:
mov cx, 10
Again:
; Do some stuff, not changing cx
dec cx
jnz Again ; Go back to Again if not zero
"Do some stuff" 发生了十次,因为 dec
影响了 Z
标志。
stc
和clc
存在的原因是为了帮助进行多位数运算。 C
标志用于跟踪先前算法中的 "Carries",以便您可以将它们纳入未来的操作:
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!
由于这些类型的操作,您可能需要在开始算法之前使用 0
或 1
预加载 C
。因此 clc
和 stc
- 以及为什么没有其他(算术)标志具有 "set" 或 "clear" 操作码。
请注意还有其他非算术标志:
D
(方向)标志控制字符串指令的方向,例如STOS
和MOVS
。 因此有cld
和std
指令。I
(中断)标志控制是否启用中断。 因此有cli
和sti
指令。