今天继续学习汇编语言,感觉有点难哇
标志寄存器
我们前面介绍了13种寄存器分别的作用,现在还剩一种特殊的寄存器,它有以下功能:
- 用来存储相关指令的某些执行结果
- 用来为CPU执行相关指令提供行为依据
- 用来控制CPU的相关工作方式
这种特殊的寄存器被称为 标志寄存器(flag)
它和别的寄存器不同,其他寄存器用来存放数据,具有整个的意义,而flag寄存器是按位起作用的,其每一位都有特定作用
1 | 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 |
我们主要学习 CF
PF
ZF
SF
OF
DF
这几种标志位
常见标志位
ZF标志位
flag的第六位是ZF,零标志位
它记录相关指令执行后数值是否为0,如果是,那么ZF = 1表示肯定;如果不是,那么ZF = 0表示否定
在8086的指令集中,并不是所有的指令都会影响标志位寄存器
以下的指令是由影响的
1 | add sub mul div inc or and |
以下的没有影响
1 | mov push pop |
PF标志
flag的第二位是PF,奇偶标志位
它记录相关指令执行后,其结果的所有bit位中1的个数是否为偶数。如果是偶数,PF = 1;如果不是,PF = 0
比如下面的指令执行后,结果为00001011B,其中有3个1,则PF = 0
1 | mov al,1 |
SF标志位
flag的第七位是SF,符号标志位
它记录相关指令执行后,其结果是否为负。如果是,那么SF = 1;如果不是,SF = 0
这里我们知道,我们进行的计算,既可以看作有符号计算,也可以看作无符号计算;当我们进行无符号计算时,无论如何它对于我们而言都是非负数,但是对于SF而言,它的结果始终是由符号的。
也就是说当我们执行相关命令的时候我们始终是会影响到SF标志位的,至于是否需要这种影响,取决于我们自己
CF标志位
flag的第零位是CF,进位标志位
在进行无符号运算时,它记录了运算结果的最高有效值向更高维的进位值,或从更高位的借位值
当两个数相加时可能向更高位进位CF = 1
1 | mov al,98H |
当两个数相减时也有可能向更高位借位
1 | mov al,97H |
OF标志位
flag的第十一位是OF,溢出标志位
OF用来记载是否发生了溢出,如果发生,OF = 1;如果没有,OF = 0
这里我们需要区分一下进位与溢出:
- 进位是针对无符号计算,溢出是针对有符号的计算
- CF用于检测无符号运算溢出
- OF用于检测有符号运算溢出
更多的指令
adc指令
adc是带进位的加法指令,它利用CF位上的记录的进位制
1 | adc 操作对象1,操作对象2 |
功能:操作对象1 = 操作对象1 + 操作对象2 + CF
我们为什么要加上CF的值呢?我们可以使用其完成低位存在进位的加法,可以分成两步:
- 低位相加
add al,bl
- 高位进位相加
adc ah,bh
比如计算1E F000 1000H
+
20 1000 1EF0H
的值,结果放在ax(最高位),bx(次高位),cx(最低位)
1 | mov ax,001EH |
sbb指令
sbb是带借位的减法指令,它利用了CF位上记录的CF值
1 | sbb 操作对象1,操作对象2 |
功能:操作对象1 = 操作对象1 - 操作对象2 - CF
比如计算 003E 1000H
-
0020 2000H
的值,结果放在ax,bx
1 | mov bx,1000H |
popf和pushf
pushf的功能时将标志寄存器的值压入栈中
popf则是从栈中弹出数据,送入标志寄存器中
比较跳转
cmp指令
cmp指令的操作相当于sub,只不过其结果不被寄存器储存,而是只影响flag中的标志寄存器
我们可以通过cmp ax,bx
指令执行后,相关标志位的状态看出比较的结果:
- 如果(ax) = (bx),则 zf = 1
- 如果(ax) != (bx),则zf = 0
- 如果(ax) < (bx),则必将产生借位,cf = 1
- 如果(ax) >= (bx),则不必借位,cf = 0
- 如果(ax) > (bx),则不必借位,且结果不为0,cf = 0 and zf = 0
- 如果(ax) <= (bx),则可能借位,也可能结果为0,cf = 0 or zf = 0
但是在这里我们默认的进行的是无符号计算,但是在实际的比较中我们也会遇到有符号数值的比较
这个时候我们需要结合sf(进位)和of(溢出)的情况进行判断:
- 当of = 0 时,说明没有溢出,此时 逻辑上真正结果的正负 = 实际结果的正负
- 当of !=0 时,说明溢出,此时 逻辑上真正结果的正负 != 实际结果的正负
所以我们可以进行有符号整数的判断:
- 如果 (ax) < (bx),则(sf = 1 and of = 0) or (sf = 0 and of = 1)
- 如果 (ax) > (bx),则sf = 1 and of = 1
- 如果 (ax) >= (bx),则sf = 0 and of = 0
检测比较结果的条件转移指令
我们之前使用过jcxz条件跳转指令,但是它是对(cx)进行判断
下面有常用的根据无符号数的比较结果进行转移的条件转移指令:
1 | 指令 含义 检测的相关标志位 |
通过cmp指令和比较指令还有标志位,可以实现想要的逻辑判断
DF标志位和串传送指令
DF标志位
flag的第十位是DF,方向标志位。在串处理命令中,控制每次操作后si,di的递减
- df = 0 每次操作后si,di递减
- df = 1 每次操作后si,di递增
在8086CPU中提供两种方式对df进行修改:
cld
–> 令df = 0std
–> 令df = 1
串传送指令
1 | movsb |
执行movsb指令相当于进行下面的步骤(将ds:si指向的内存单元中的字节送入es:di中,然后根据df中的值,进行增减)
1 | mov es:[di],byte ptr ds:[si] |
1 | movsw |
执行movsw指令相当于进行下面的步骤(将ds:si指向的内存字单元中的字送入es:di中,然后根据df中的值,进行增减)
1 | mov es:[di],word ptr ds:[si] |
1 | rep movsb/movesw |
rep指令的含义是根据cx的值,重复执行后面的指令。可以理解为下面的指令:
1 | s: movsb/movsw |
当我们使用串传送时,需要为串传送指令提供以下信息:
- 传送的原始位置
- 传送的目的位置
- 传送的长度
- 传送的方向
DEBUG中的标志寄存器

图中标识了不同标志寄存器对应的位置
下面我们列出Debug对标志位的表示:
1 | 标志 值为1的标记 值为0的标记 |
实验11

1 | assume cs:code,ds:data |