8086 CPU 内部有 14 个 16 位寄存器,前面已经已经学习了 AX、BX、CX、DX、CS、DS、SS、ES、SI、DI、IP、SP、BP 这 13 个寄存器,还差一个,这就是本篇要介绍的标志寄存器,简称 flag。

flag 寄存器是一个特殊的寄存器,它是按位起作用的,它具有 3 种作用:

  • 用来存储相关指令的某些执行结果
  • 用来为 CPU 执行相关指令提供行为依据
  • 用来控制 CPU 的相关工作方式

8086CPU 的 flag 寄存器结果如下所示:

1
1

下图是各个标志位的简介(图片来自百度百科):

2
2

CF

进位标志,在无符号数进行运算的时候,它记录了运算结果的的最高位进位或借位的情况。

adc 是带进位加法指令,利用了 CF 上的进位值

指令格式: adc 操作对象1,操作对象2

功能:操作对象1 = 操作对象1 + 操作对象2 + CF

利用这个我们可以实现任意位数的数相加。

sbb 是带借位减法指令,利用了 CF 上记录的借位值,利用这个指令可以计算任意两个数的减法。

通过学习 adc 和 sbb 指令能使我们更好的认识 CF 标志位。

PF

奇偶标志位,它记录了相关指令执行后,其结果的所有二进制位中 1 的个数是否为偶数,如果 1 的个数为偶数,PF = 1,如果为奇数,PF = 0。

AF

算数操作结果的第三位(从0开始计数)如果产生了进位或者借位则将其置为1,否则置为0,常在BCD(binary-codedecimal)算术运算中被使用。

ZF

零标志位,它记录了相关指令执行后,其结果是否为 0 ,结果为 0 则 ZF = 1,结果不为 1 则 ZF = 0。

SF

符号标志位,它记录了相关指令执行后,其结果是否为负。当我们将数据当做有符号数来计算的时候,它记录结果的正负,如果为负则 SF = 1,不为负则 SF = 0。如果把数据当做无符号数来计算,则 SF 标志无意义。

TF

当TF被设置为1时,CPU进入单步模式,所谓单步模式就是CPU在每执行一步指令后都产生一个单步中断。主要用于程序的调试。8086/8088中没有专门用来置位和清零TF的命令,需要用其他办法。

IF

决定CPU是否响应外部可屏蔽中断请求。IF为1时,CPU允许响应外部的可屏蔽中断请求。

DF

方向标志位,在串处理指令中,控制每次操作后 si 和 di 的增减

  • DF = 0,每次操作后 si 和 di 递增
  • DF = 1,每次操作后 si 和 di 递减

串传送指令 movsb ,执行后相当于如下操作

  • 把 DS:[si] 中的一个字节送入 ES:[di] 中
  • 如果 DF = 0,si 和 di 的值递增 1

串传送指令 movsw ,它的功能和 movsb 差不多,只不过它每次传送一个字,具体功能为将 DS:[si] 指向内存的字单元送入 ES:[di] 中,根据 DF 的值将 si 和 di 递增或者递减 2。

OF

溢出标志位,记录了有符号数运算结果是否发生了溢出。如果发生溢出,OF = 1,没有的话则 OF = 0 。

类似于高级语言中的逻辑判断

在高级语言中我们可以使用 if 和 else 来进行逻辑判断,那么汇编能实现类似的功能吗?必须的可以啊,在讲解之前先来学习下 cmp 指令和一系列检测比较结果的条件转移指令。

cmp 指令是比较指令,相当于减法指令,只是不保存结果,将对标志寄存器产生影响。例如下面的指令:

mov ax,8
mov bx,3
cmp ax,bx

执行后 ax 中的值仍为 8,ZF=0(执行后结果不为0),PF=1(执行后结果为5,即101中1的个数为偶数),CF=0(没有发生进位或借位),OF=0(没有发生溢出)。

检测比较结果的条件指令如下所示

指令 含义 检测的相关标志位
je 等于则转移 ZF=1
jne 不等于则转移 ZF=0
jb 低于则转移 CF=1(发生借位)
jnb 不低于则转移 CF=0(没有发生借位)
ja 高于则转移 CF=0且ZF=0(没有借位且结果不为0)
jna 不高于则转移 CF=1或ZF=1(有借位或执行结果为0)

上面的指令很好记,根据英文意思便可知道要表达的意思

e:equal

ne:not equal

b:blow

nb:not blow

a:above

na:not above

可以用 cmp 指令和一系列检测比较结果的条件转移指令来实现类似于高级语言中的逻辑判断,例子:实现如下功能

if (ah == bh) {
ah = ah + ah
} else {
ah = ah + bh
}

核心汇编代码如下:

	 cmp ah,bh
je s
add ah,bh
jmp short s1
s: add ah,ah
s1: ...

pushf 和 popf

pushf 是将标志寄存器的值压栈

popf 是将标志寄存器的值出栈

有了这两个指令就能和上篇中执行子程序前将标志寄存器的内容压栈,等待子程序执行完后再将栈中的数据恢复到标志寄存器中。

debug 中标志寄存器的表示方法

标志寄存器在 debug 中的表示不像其它寄存器那么直观,它是按位展示的,在 9 个标志位中 TF 没有表示出来,其它 8 个位的表示如下所示:

3
3