标志寄存器(FLAGS)
FLAGS 寄存器(也称 PSW,程序状态字)不像其他寄存器那样存放数据,而是按位记录 CPU 执行指令后的状态信息。这些标志位决定了条件转移指令的行为。
前置知识
需要了解 01-寄存器 中 FLAGS 寄存器的基本概念,以及 08-过程调用与算术指令 中的 adc/sbb(它们依赖 CF 标志)。
标志位一览
8086 的 FLAGS 是 16 位寄存器,用到了其中 9 位:
| 位 | 标志 | 名称 | 含义 |
|---|---|---|---|
| 0 | CF | Carry Flag(进位标志) | 无符号运算是否产生进位/借位 |
| 2 | PF | Parity Flag(奇偶标志) | 结果中1的个数是否为偶数 |
| 4 | AF | Auxiliary Carry Flag | 辅助进位(BCD运算用) |
| 6 | ZF | Zero Flag(零标志) | 运算结果是否为0 |
| 7 | SF | Sign Flag(符号标志) | 运算结果是否为负 |
| 8 | TF | Trap Flag(陷阱标志) | 单步执行(debug的t命令使用) |
| 9 | IF | Interrupt Flag(中断标志) | 是否响应可屏蔽中断 |
| 10 | DF | Direction Flag(方向标志) | 串操作方向 |
| 11 | OF | Overflow Flag(溢出标志) | 有符号运算是否溢出 |
常用标志位详解
ZF:零标志(第6位)
记录指令执行后结果是否为 0:
- 结果为 0 → ZF = 1
- 结果不为 0 → ZF = 0
mov ax, 1
sub ax, 1 ; 结果为0,ZF=1
mov ax, 2
sub ax, 1 ; 结果为1,ZF=0
不是所有指令都影响标志位
mov、push、pop等传送指令不影响标志位。只有运算指令(add、sub、mul、div、inc、dec、and、or 等)才会根据结果设置标志位。
PF:奇偶标志(第2位)
记录结果二进制表示中 1 的个数是否为偶数:
- 1的个数为偶数 → PF = 1
- 1的个数为奇数 → PF = 0
mov al, 1 ; 二进制 00000001,1个1(奇数)→ PF=0
add al, 2 ; 结果 00000011,2个1(偶数)→ PF=1
PF 主要用于通信中的奇偶校验,一般编程用得不多。
SF:符号标志(第7位)
记录有符号运算结果是否为负:
- 结果为负(最高位为1)→ SF = 1
- 结果非负(最高位为0)→ SF = 0
mov al, 10000001B ; 作为有符号数是 -127
add al, 1 ; 结果 10000010B = -126,SF=1(负数)
SF 和最高位
对于有符号数,最高位就是符号位(0正1负),所以 SF 记录的就是结果的最高位值。
CF:进位标志(第0位)
记录无符号数运算时,最高有效位是否产生了进位(加法)或借位(减法):
- 有进位/借位 → CF = 1
- 无进位/借位 → CF = 0
; 加法进位
mov al, 98H
add al, al ; 98H + 98H = 130H → AL=30H,CF=1(有进位到高位)
add al, al ; 30H + 30H = 60H → AL=60H,CF=0
; 减法借位
mov al, 97H
sub al, 98H ; 97H - 98H 需要借位 → CF=1
sub al, al ; 0 - 0 不需要借位 → CF=0
CF 是 adc/sbb 指令的基础。
OF:溢出标志(第11位)
记录有符号数运算结果是否溢出(超出了有符号数能表示的范围):
- 有溢出 → OF = 1
- 无溢出 → OF = 0
mov al, 97H ; 作为有符号数是 -105
add al, al ; -105 + (-105) = -210,超出8位有符号数范围(-128~127) → OF=1
CF 和 OF 的区别
- CF 关心无符号数:结果是否超过了 N 位无符号数的范围(0~2
- OF 关心有符号数:结果是否超过了 N 位有符号数的范围(-2^(N-1)~2
- 它们是独立判断的!同一条指令可能 CF=0 同时 OF=1(有符号溢出但无符号没进位),反之亦然。
cmp 指令:比较
cmp 是减法指令,但不保存结果,只根据减法结果设置标志位。相当于”做减法但只改标志位”。
格式:cmp 操作对象1, 操作对象2 → 计算 操作对象1 - 操作对象2
通过 cmp 设置标志位后,可以用条件转移指令判断大小关系:
有符号数比较
| 指令 | 含义 | 条件 |
|---|---|---|
je / jz | 等于(Equal/Zero) | ZF=1 |
jne / jnz | 不等于 | ZF=0 |
jl / jnge | 小于(Less) | SF≠OF |
jle | 小于等于 | ZF=1 或 SF≠OF |
jg / jnle | 大于(Greater) | ZF=0 且 SF=OF |
jge | 大于等于 | SF=OF |
无符号数比较
| 指令 | 含义 | 条件 |
|---|---|---|
je / jz | 等于 | ZF=1 |
jne / jnz | 不等于 | ZF=0 |
jb / jnae | 低于(Below) | CF=1 |
jbe | 低于等于 | CF=1 或 ZF=1 |
ja / jnbe | 高于(Above) | CF=0 且 ZF=0 |
jae | 高于等于 | CF=0 |
; 比较 ax 和 bx,如果 ax > bx 则跳到 greater
cmp ax, bx
ja greater ; 无符号比较用 ja/jb
; 或
jg greater ; 有符号比较用 jg/jl
greater:
; ...
记忆技巧
无符号比较:a=above(大于), b=below(小于), e=equal 有符号比较:g=greater(大于), l=less(小于), e=equal 加 n 表示 not(如 jne = jump if not equal)
其他标志位
| 标志 | 作用 |
|---|---|
| TF(陷阱标志) | TF=1 时 CPU 执行完一条指令后触发单步中断,debug 的 t 命令就是通过设置 TF 实现的 |
| IF(中断标志) | IF=1 时 CPU 响应可屏蔽中断,IF=0 时屏蔽。详见 10-中断与端口 |
| DF(方向标志) | 控制串操作指令(movsb/cmpsb等)地址增减方向,DF=0时地址递增,DF=1时递减 |
debug 中查看标志位
在 debug 中用 r 命令查看寄存器时,最后会显示标志位状态,用字母表示:
| 标志 | 置1(=1) | 置0(=0) |
|---|---|---|
| OF | OV | NV |
| SF | NG | PL |
| ZF | ZR | NZ |
| PF | PE | PO |
| CF | CY | NC |
| DF | DN | UP |
| IF | EI | DI |
相关
- 01-寄存器 — FLAGS 寄存器总览
- 07-转移指令与循环 — 条件转移指令是标志位的主要用途
- 08-过程调用与算术指令 — adc/sbb 使用 CF 标志
- 10-中断与端口 — IF 标志和 TF 标志与中断相关