【问题标题】:How Does Setting/Unsetting MASM Flags Work设置/取消设置 MASM 标志如何工作
【发布时间】:2018-12-13 10:27:26
【问题描述】:

Set 表示flag value = 1,Unset 表示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

OverflowCarry 标志操作是自懂且易于掌握的,但我发现很难理解设置 Zero/Sign 标志背后的数学原理。任何帮助表示赞赏!

谢谢!

【问题讨论】:

  • 也许考虑如何使用标志会有所帮助。考虑一下:你很少需要你已经溢出了。你做你的工作,然后(根据需要)检查溢出。故意设置标志是……不常见的。但是,进位标志通常用于简单算术之外的目的。比如DOS经常使用CF来表示错误情况。
  • 请注意,在大多数示例中,设置标志“只是”操作的副作用,并不意味着设置/清除标志。 (只有 stcclc 明确用于设置/清除标志)。

标签: assembly x86 conditional-statements masm eflags


【解决方案1】:

使用标志的全部意义在于它们是其他操作的副作用 - 您可以在操作发生后测试结果。

因此,例如,您可以从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 标志。

stcclc 存在的原因是为了帮助进行多位运算。 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!

由于这些类型的操作,您可能需要在开始算法之前使用01 预加载C。因此clcstc - 以及为什么没有其他(算术)标志具有“设置”或“清除”操作码。

请注意,还有其他非算术标志:

  • D(方向)标志控制字符串指令的方向,例如STOSMOVS。 因此有cldstd 指令。
  • I(中断)标志控制是否启用中断。 因此有clisti 指令。

【讨论】:

  • 感谢清晰的解释,它帮助了很多!
【解决方案2】:

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 如何在他们的硬件上工作。

【讨论】:

    猜你喜欢
    • 2010-09-28
    • 2022-09-27
    • 2014-04-17
    • 2013-06-07
    • 1970-01-01
    • 1970-01-01
    • 2019-10-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多