CPU内部的寄存器中,有一种特殊的寄存器(对于不同的处理机,个数和结构都可能不同)具有以下3种作用。

(1)用来存储相关指令的某些执行结果;

(2)用来为CPU执行相关指令提供行为依据;

(3)用来控制CPU的相关工作方式。

这种特殊的寄存器在8086CPU中,被称为标志寄存器。

flag和其他寄存器不一样,其他寄存器是用来存放数据的,都是整个寄存器具有一个含义。而flag寄存器是按位起作用的,也就是说,它的每一位都有专门的含义,记录特定的信息。

8086CPU的flag寄存器的结构如图11.1所示。

image-20220120184323262

flag的1、3、5、12、13、14、15位在8086CPU中没有使用,不具有任何含义。而0、2、4、6、7、8、9、10、11位都具有特殊的含义。

11.1 ZF标志

flag的第6位是ZF,零标志位。它记录相关指令执行后,其结果是否为0。如果结果为0,那么zf=1;如果结果不为0,那么zf=0。

image-20220120184456915

11.2 PF标志

flag 的第⒉位是PF,奇偶标志位。它记录相关指令执行后,其结果的所有bit位中1的个数是否为偶数。如果1的个数为偶数,pf=1,如果为奇数,那么pf=0。

image-20220120184545744

11.3 SF标志

flag 的第7位是SF,符号标志位。它记录相关指令执行后,其结果是否为负。如果结果为负,sf=1;如果非负,sf=0。

image-20220120184738582

11.4 CF标志

flag的第0位是CF,进位标志位。一般情况下,在进行==无符号数==运算的时候,它记录了运算结果的最高有效位向更高位的进位值,或从更高位的借位值。

11.5 OF标志

flag 的第11位是OF,溢出标志位。一般情况下,OF记录了有符号数运算的结果是否发生了溢出。如果发生溢出,OF=1;如果没有,OF=O。

一定要注意CF和 OF的区别:CF是对无符号数运算有意义的标志位,而OF是对有符号数运算有意义的标志位。

11.6 adc指令

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

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

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

比如指令 adc ax,bx 实现的功能是:(ax)=(ax)+(bx)+CF

image-20220120185300034

adc指令和add指令相配合就可以对更大的数据进行加法运算。

11.7 sbb指令

sbb是带借位减法指令,它利用了CF位上记录的借位值。

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

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

比如指令sbb ax,bx实现的功能是:(ax)=(ax)-(bx)-CF

11.8 cmp指令

cmp是比较指令,cmp的功能相当于减法指令,只是不保存结果。cmp指令执行后,将对标志寄存器产生影响。其他相关指令通过识别这些被影响的标志寄存器位来得知比较结果。

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

功能:计算操作对象1-操作对象但并不保存结果,仅仅根据计算结果对标志寄存器进行设置。

比如,指令cmp ax,ax,做(ax)-(ax)的运算,结果为0,但并不在 ax 中保存,仅影响flag的相关各位。指令执行后:zf=1,pf=1,sf=0,cf=0,of=0

11.9 检测比较结果的条件转移指令

因为 cmp 指令可以同时进行两种比较,无符号数比较和有符号数比较,所以根据cmp 指令的比较结果进行转移的指令也分为两种,即根据无符号数的比较结果进行转移的条件转移指令(它们检测zf、cf 的值)和根据有符号数的比较结果进行转移的条件转移指令(它们检测sf、of和zf的值)。

下面是常用的根据无符号数的比较结果进行转移的条件转移指令。

image-20220120191011801

这些指令比较常用,它们都很好记忆,它们的第一个字母都是 j,表示 jump;后面的字母表示意义如下。

image-20220120191034310

编程,统计data段中数值为8的字节的个数,用ax保存统计结果。

image-20220120191238779

这个程序也可以写成这样:

image-20220120191303032

11.10 DF标志和串传送指令

flag 的第10位是DF,方向标志位。在串处理指令中,控制每次操作后si、di的增减。

df=0 每次操作后si、di递增; df=1 每次操作后si、di递减。

格式:movsb

功能:执行movsb指令相当于进行下面几步操作。

(1) ((es)*16+(di))=((ds)*16+(si))

(2)如果df=0 则:

(si)=(si)+1

(di)-(di)+1

如果df=1则: (si)=(si)-1

(di)=(di)-1

image-20220120191533183

也可以传送一个字,指令如下。

格式:movsw

movsw的功能是将ds:si指向的内存字单元中的字送入es:di 中,然后根据标志寄存器df位的值,将si和di递增2或递减2。

movsbmovsw进行的是串传送操作中的一个步骤,一般来说,movsbmovsw都和rep配合使用,格式如下:

rep movsb

用汇编语法来描述 rep movsb 的功能就是:

s:movsb

loop s

可见,rep的作用是根据cx的值,重复执行后面的串传送指令。由于每执行一次movsb指令si和di都会递增或递减指向后一个单元或前一个单元,则rep movsb就可以循环实现(cx)个字符的传送。

同理,也可以使用这样的指令:rep movsw

由于flag的df位决定着串传送指令执行后,si和di改变的方向,所以CPU应该提供相应的指令来对df位进行设置,从而使程序员能够决定传送的方向。

8086CPU提供下面两条指令对df位进行设置。

cld指令:将标志寄存器的df位置0

std 指令:将标志寄存器的df位置1

编程,用串传送指令,将data 段中的第一个字符串复制到它后面的空间中。

image-20220120192836279

11.11 pushf和popf

pushf的功能是将标志寄存器的值压栈,而popf是从栈中弹出数据,送入标志寄存器中。

pushf和popf,为直接访问标志寄存器提供了一种方法。

11.12 标志寄存器在Debug中的表示

在 Debug 中,标志寄存器是按照有意义的各个标志位单独表示的。在 Debug 中,我们可以看到下面的信息。

image-20220120193222613

下面列出 Debug对我们已知的标志位的表示。

image-20220120193306633