1. 预备知识
标志寄存器的作用:(1)存储相关指令的某些执行结果;(2)为 CPU 执行相关指令提供行为依据;(3)控制 CPU 的相关工作方式。和其他寄存器用来存放数据不同,标志寄存器按位起作用,每一位都有特定的含义。标志寄存器中各标志位:
15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
OF DF IF TF SF ZF AF PF CF
标志寄存器只有在进行相关运算时起作用,mov 等转移指令不会引起标志寄存器值的变化。常用的标志寄存器:
- ZF 记录指令执行后,其结果是否为 0。如果为 0 则 ZF 为 1,否则为 0。
- PF 记录指令执行后,其结果所有二进制位中 1 的个数是否为偶数。如果为偶数则 PF 为 1,否则为 0。
- SF 记录指令执行后,其结果是否为负。如果为负则 SF 为 1,否则为 0。
- CF 记录无符号数的运算中,向更高位的进位值或从更高位的借位值。在判断标志位 CF 的值时,将原计算看作是无符号数的计算。
- OF 记录有符号数的运算中,运算结果是否发生溢出。如果溢出则 OF 为 1,否则为 0。在判断标志位 OF 的值时,将原计算看作是有符号数的计算。如计算,add 0F0H, 088H,等价于 (-16) + (-120) = -136,超出了 8 位有符号数的表示范围。
adc 指令和 sbb 指令分别表示带进位的加法指令和带借位的减法指令,即在运算时需带上标志位 CF 的值,如 +(CF) 和 -(CF)。adc 指令可用于针对溢出位数的加法,如先针对低位使用 add 指令相加,再针对次高位使用 adc 指令相加,最后针对最高位使用 adc 指令相加。
cmp 是比较指令,相当于完成减法功能,但是不保存结果,仅影响标志位的值。可以借由 cmp 指令实现高级语言中的 if 功能,格式为 cmp 对象1, 对象2。如 cmp ax,bx:
- 如果 (ax)=(bx),则 ZF=1。
- 如果 (ax)≠(bx),则 ZF=0。
- 如果 (ax)<(bx),则减法计算将产生借位,CF=1。
- 如果 (ax)≥(bx),CF=0。
- 如果 (ax)>(bx),CF=0 且 ZF=0。
- 如果 (ax)≤(bx),CF=1 或 ZF=1。
根据上述比较指令产生的结果,对应的转移指令如下:
指令 | 含义 | 检测的相关标志位 |
---|---|---|
je | 等于则转移 | ZF=1 |
jne | 不等于则转移 | ZF=0 |
jb | 小于则转移 | CF=1 |
jnb | 不小于则转移 | CF=0 |
ja | 大于则转移 | CF=0 且 ZF=0 |
jna | 不大于则转移 | CF=1 或 ZF=1 |
DF 标志位为方向标志位,在串处理指令中,控制每次操作后 si 和 di 的增减。DF=0,每次操作后 si 和 di 递增;DF=1,每次操作后 si 和 di 递减。
pushf 的功能是将标志寄存器的值入栈;popf 的功能是从栈中弹出数据,并送入标志寄存器中。pushf 和 popf 为直接访问标志寄存器提供了一种方法。
2. 检测点 11.1
写出下面每条指令执行后,ZF、PF、SF 等标志位的值。
指令 | ZF | PF | SF |
---|---|---|---|
sub al,al | 1 | 1 | 0 |
mov al,1 | 1 | 1 | 0 |
push ax | 1 | 1 | 0 |
pop bx | 1 | 1 | 0 |
add al,bl | 0 | 0 | 0 |
add al,10 | 0 | 1 | 0 |
mul al | 0 | 1 | 0 |
- 第一行,减法运算,结果为零;结果中 1 的个数为零,为偶数;结果不为负。
- 第二 / 三行,转移指令,不影响标志寄存器的值。
- 第四行,运算结果为寄存器 BX 的值,标志寄存器的值不变。
- 第五行,AL 为 0001,BL 为 0001,结果为 0010。
- 第六行,AL 为 0010,结果为 1100。
- 第七行,8 位乘法。一个乘数默认放在 AL 中,另一个为指定值。即 (AL) * (AL),结果为 1001 0000,8 位乘法结果存放在 16 位寄存器 AX 中,内容为 0000 0000 1001 0000,表示正数。
3. 检测点 11.2
写出下面每条指令后,ZF、PF、SF、CF、OF 等标志位的值。
指令 | CF | OF | SF | ZF | PF |
---|---|---|---|---|---|
sub al,al | 0 | 0 | 0 | 1 | 1 |
mov al,10H | 0 | 0 | 0 | 1 | 1 |
add al,90H | 0 | 0 | 1 | 0 | 1 |
mov al,80H | 0 | 0 | 1 | 0 | 1 |
add al,80H | 1 | 1 | 0 | 1 | 1 |
mov al,0FCH | 1 | 1 | 0 | 1 | 1 |
add al,05H | 1 | 0 | 0 | 0 | 0 |
mov al,7DH | 1 | 0 | 0 | 0 | 0 |
add al,0BH | 0 | 1 | 1 | 0 | 1 |
- 第一行,减法运算,结果为零。无进位 / 借位,无溢出。
- 第二 / 四 / 六 / 八行,转移指令,不影响标志寄存器的值。
- 第三行,加法运算,10H + 90H = 0A0H。结果 AL 的最高位为 1,表示负数。无进位 / 借位,无溢出。 1111 1100 + 0000 0101 = 0001 0000 0001
- 第五行,加法运算,80H + 80H。对于有符号数的计算而言,(-128) + (-128) = -256,超出了 8 位有符号数的范围,有溢出;对于无符号数的计算而言,80H + 80H = 100H,有向更高位进位,且 AL 只能存储 00H 部分。
- 第七行,加法运算,0FCH + 05H。对于有符号数的计算而言,(-4) + (5) = 01H,无溢出;对于有符号数的计算而言,FCH + 05H = 101H,有向更高位进位,且 AL 只能存储 01H 部分。
- = 101H,但 AL 只能存储 01H 部分。有向更高位的进位,无溢出。0111 1101 + 0000 1011 =
- 第九行,加法运算,7DH + 0BH。对于有符号数的计算而言,(125) + (11) = 136,超出了 8 位有符号数的范围,有溢出;对于无符号数的计算而言,7DH + 0BH = 88H,无向更高位的进位。结果 AL 的最高位为 1,表示负数。
4. 检测点 11.3
(1)补全下面的程序,统计 F000:0 处 32 个字节中,大小在 [32, 128] 的数据的个数。
mov ax,0f000h
mov ds,ax
mov bx,0
mov dx,0
mov cx,32
s:
mov al,[bx]
cmp al,32
___________
cmp al,128
___________
inc dx
s0:
inc bx
loop s
由 mov al,[bx] 可知,每次使用寄存器 BX 从内存单元取值,s0 部分用于从内存单元中取值,则寄存器 DX 用于统计大小在 [32, 128] 的数据的个数。则,如果所取数据 [bx] 同时满足大于等于 32 和小于等于 128 时执行 inc dx 指令,否则直接执行 s0 部分的代码。所以,如果 cmp 比较指令任意一处不满足上述关系,则直接跳转到 s0 处。结合预备知识部分,当 (al) < 32 或 (al) > 128 时跳转到 s0 处,分别对应的转移指令为 jb 和 ja。代码段部分为:
mov ax,0f000h
mov ds,ax
mov bx,0
mov dx,0
mov cx,32
s:
mov al,[bx]
cmp al,32
jb s0
cmp al,128
ja s0
inc dx
s0:
inc bx
loop s
(2)补全下面的程序,统计 F000:0 处 32 个字节中,大小在 (32, 128) 的数据的个数。
mov ax,0f000h
mov ds,ax
mov bx,0
mov dx,0
mov cx,32
s:
mov al,[bx]
cmp al,32
___________
cmp al,128
___________
inc dx
s0:
inc bx
loop s
和上一题的分析类似,代码段部分为:
mov ax,0f000h
mov ds,ax
mov bx,0
mov dx,0
mov cx,32
s:
mov al,[bx]
cmp al,32
jna s0
cmp al,128
jnb s0
inc dx
s0:
inc bx
loop s
5. 检测点 11.4
下面的程序执行后:(ax)=?
mov ax,0
push ax
popf
mov ax,0fff0h
add ax,0010h
pushf
pop ax
and al,11000101B
and ah,00001000B
- 第三条语句 popf 将栈中数据 0 弹出,并送入标志寄存器,此时标志位全部置零。
- 第四 / 五条语句,加法运算,0FFF0H + 0010H。对于有符号数的计算而言,(-16) + (16) = 0,无溢出,OF=0;对于无符号数的计算而言,(65520) + (16) = 65536,有向更高位的进位,CF=1。且 ZF=1,PF=1。
- 语句 pushf 将标志寄存器的内容入栈,此时标志寄存器的内容为 0000 0000 0100 0101,则后续出栈后 (AX)=0045H。
- and al,11000101B 进行按位与运算,结果为 (AL)=0100 0101=45H;and ah,00001000B 进行按位与运算,结果为 (AH)=0000 0000H。所以,最终 (AX)=0045H。
6. 总结
- 本文主要用到标志寄存器中 ZF、PF、SF、CF 和 OF 的功能。其中 OF 针对有符号数的运算检测是否有溢出,CF 针对无符号数的运算检测是否存在进位和借位。
- 结合标志寄存器中各标志位的功能,cmp 比较指令和转移指令可以轻松实现高级语言中的 if 语句功能。
- pushf 和 popf 直接作用于标志寄存器。