标志寄存器的 3 种作用:
- 存储相关指令的某些执行结果
- 为 CPU 执行相关指令提供行为依据
- 用来控制 CPU 的相关工作方式
flag 寄存器是按位起作用的,每一位有专门的含义,记录特定信息。
ZF 标志
Zero Flag,零标志位,记录相关指令执行后,其结果是否为 0。结果为 0 时 zf = 1,否则 zf = 0。
大多运算指令(逻辑、算术运算)的执行对标志寄存器有影响。传送指令例如:mov、push、pop 对标志寄存器没有影响。
PF
Plural Flag,奇偶标志位,记录相关指令执行后,其结果的所有 bit 位中 1 的个数如果为偶数,pf = 1,如果为奇数,pf = 0。
SF 标志
Sign Flag,记录相关指令执行后,其结果是否为负。如果结果为负,sf = 1,如果非负,sf = 0。
CF 标志
Carry Flag,进位标识位。进行无符号数运算时,记录了运算结果的最高有效位向更高位的进位值,或从更高位的借位值。
OF 标志
Overflow Flag,进行有符号数运算时,如果超过了机器所能表示的范围成为溢出。
CF 和 OF 所表示的进位和溢出,是分别对于无符号数和有符号数运算而言的,他们之间没有任何关系。
adc 指令
adc 是带进位加法指令,利用了 CF 位上的进位值。
1 | adc 操作对象1,操作对象2 |
例:
1 | mov ax,2 |
执行后 (ax) = 4,相当于 (ax) + 1 + CF = 2 + 1 + 1 = 4。
利用 adc 和 add 指令可以对任意大的数据进行加法运算。
计算 1ef0001000H + 2010001ef0H,结果放在 ax(最高 16 位)、bx(次高 16 位)、cx(低 16 位)。
1 | mov ax,001eH |
计算两个 128 位数据的和。ds:si 指向第一个数的内存空间;ds:di 指向存储第二个数的内存空间。
1 | add128: |
sbb 指令
sbb 是带借位减法指令,利用了 CF 位上记录的借位值。
格式:
1 | sbb 操作对象1,操作对象2 |
sbb ax,bx
实现了 (ax) = (ax) - (bx) - CF。
计算 003e1000H - 00202000H,结果放在 ax,bx 中:
1 | mov bx,1000H |
cmp 指令
cmp 是比较指令,相当于做减法,只是不保存结果。cmp 指令执行后将影响标志寄存器,其他寄存器通过识别这些被影响的标志寄存器位来得知比较结果。
cmp 指令格式:
1 | cmp 操作对象1,操作对象2 |
功能:计算 操作对象 1 - 操作对象 2,但不保存结果,仅根据计算结果设置标志寄存器。
1 | mov ax,8 |
比较指令的设计思路:通过做减法运算,影响标志寄存器,标志寄存器的相关位记录了比较的结果。
无符号数的情况
1 | cmp 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,说明 (ax) ≤ (bx)
有符号数的情况
- sf = 1 且 of = 0,说明 (ax) < (bx)
- sf = 1 且 of = 1,说明 (ax) > (bx)
- sf = 0 且 of = 1,说明 (ax) < (bx)
- sf = 0 且 of = 0,说明 (ax) ≥ (bx)
关于 2 的推理过程:如果结果为负,但是溢出了,说明是溢出导致结果为负,那么逻辑上真正的结果为正,所以 ax > bx。
检测比较结果的条件转移指令
根据某种条件决定是否修改 IP。
大多数条件转移指令都检测标志寄存器的相关标志位,根据检测结果决定是否修改 IP。常与 cmp 指令配合使用。
cmp 指令可以同时进行有符号数比较和无符号数比较,因此根据 cmp 指令的比较结果进行转移的指令也分为两种。
指令 | 含义 | 检测的相关标志位 |
---|---|---|
je | 等于则转移 | zf = 1 |
jne | 不等于则转移 | zf = 0 |
jb | 低于则转移 | cf = 1 |
jnb | 不低于则转移 | cf = 0 |
ja | 高于则转移 | cf = 0 且 zf = 0 |
jna | 不高于则转移 | cf = 1 或 zf = 1 |
统计 data 段中数值为 8 的字节的个数,用 ax 保存统计结果:
1 | mov ax,data |
DF 标志和串传送指令
flag 的第 10 位是 DF,方向标志位,Direction Flag。
df = 0,每次操作后 si、di 递增;
df = 1,每次操作后 si、di 递减。
串传送指令 movsb
:
功能:
((es)*16+(di)) = ((ds)*16+(si))
- 如果 df = 0,则:
(si) = (si) + 1
,(di) = (di) + 1
如果 df = 1,则:(si) = (si) - 1
,(di) = (di) - 1
movsb
的功能是将 ds:si
指向的内存单元中的字节送入 es:di
,然后根据标志寄存器 df 位的值,将 si 和 di 递增或递减。
也可以传送一个字:
movsw
功能:将 ds:si
指向的内存字单元中的字送入 es:di
中,然后根据标志寄存器 df 位的值,将 si 和 di 递增 2 或递减 2。
一般 movsb
和 movsw
都和 rep
配合使用。
1 | rep movsb |
相当于:
1 | s: movsb |
rep
根据 cx 的值,重复执行后面的串传输指令。实现将 (cx) 个字符从 ds:si
传送到 es:di
。
8086CPU 提供下面两条指令对 df 位进行设置:
- cld 指令:将标志寄存器的 df 位设置为 0
- std 指令:将标志寄存器的 df 位设置为 1
编程,用串传送指令,将 data 段中的第一个字符串复制到它后面的空间中。
1 | cs:code,ds:data |
pushf 和 popf
pushf
的功能是将标志寄存器的值压栈,popf
是从栈中弹出数据送入标志寄存器。
pushf
、popf
为直接访问标志寄存器提供了一种方法。
检测点 11.4
1 | mov ax,0 |
(ax) = 45h = 69
标志寄存器在 Debug 中的表示
标识 | 值为 1 的标记 | 值为 0 的标记 |
---|---|---|
of | OV | NV |
sf | NG | PL |
zf | ZR | NZ |
pf | PE | PO |
cf | CY | NC |
df | DN | UP |