Intel 标识寄存器中的常见标志 && 影响

0x0 简述

标识寄存器,8086 下存储于 FLAGS 寄存器,32 位下扩展为 EFLAGS。听起名知其义,即存储相关的标志。这些标识主要由是相关运算指令产生的结果,例如运算结果是否为零,运算是否溢出(进位、借位)等等。常见的基础标识位有 ZF、PF、SF、CF、OF、DF

0x1 ZF

主要用于标识运算结果是否为零:

mov ax, 2
sub ax, ax

当运算结果为零时,ZF = 1,否则 ZF = 0。标识寄存器通常由 add、sub、inc、or、and 等运算符直接影响,对于 mov、push、pop 等传送指令,不会影响到 ZF 标识。

0x2 PF

奇偶数标识位,当运算结果中 1 的位数为偶数时,PF = 1,反之 PF = 0

例如运算结果为 0010B

mov ax, 1
add ax, 1 ; PF = 0

当运算结果为 0011B 时,1 的总数为偶数:

mov ax, 1
add ax, 2 ; PF = 1

0x3 SF

在 8086 中,使用补码的方式来存储有符号数。对于负数,其最高位使用 1 来标识:

mov al, 10001000b
add al, 1           ; al = 10001001b

当执行运算操作后,al 的最高符号为 1。10001001b 可以当做 137,也作为有符号数 -119。

对于 CPU 而言,当最高符号为 1 时,会将其记录到 SF 标识中,即 SF = 1。而对于运算结果是看做 137 还是 -119,则是我们的程序实现问题,取决于将数据作为有符号或者无符号数。

0x4 CF

当运算产生进位、借位时,会对 CF 标识位产生影响。

mov al, 0FFh
add al, 1

由于 al 只能存放最大 0xFF 的数值,当继续增加时,产生进位。此时产生的进位并不会存储到 ah 中,也不会将其丢弃,而是更新 CF 标志位: CF = 1,表示进位产生。

同样的道理,当进行减法运算时,可能会产生借位:

mov al, 97h
mov bl, 98h
sub al, bl

此时 97h < 98h,产生借位,即实际上是进行 197h - 98h 运算,此时 CF 标识位也会置位。

0x5 OF

OF 标识位主要用于记录有符号数的溢出。

例如,对于一个 8 位的 al 寄存器来讲,能容纳的无符号数范围为 0 - 255,即 00h - 0FFh

对于有符号数,则范围为 -128 - 127 ,最高位为符号为,则范围为 10000000b - 01111111b

当进行运算时,对于有符号数来讲,可能会超出数值范围:

mov al, 7Fh
add al, 1     ; al = 8Fh

对于无符号来讲,0x8F(128)在数值范围之内;但是对于一个无符号数来讲,已经超出了 -128 - 127 的范围,所以此时 OF = 1

0x6 DF

DF 是方向标识位,主要用于标识递增或递减 SI / DI 寄存器:

; 初始化段寄存器
mov ax, 0
mov ds, ax
mov bx, 20h
mov es, bx
xor si, si
xor di, di
; 清除 DF 位
cld
; 拷贝数据,将 ds:si 复制到 es:di
mov cx, 10
rep movsb

DF = 0 时,每次复制完成后,SI 和 DI 依次递增;反之,当 DF = 1 时,SI 和 DI 反方向递减。

置位 DF 标识位,递减偏移寄存器:

std
mov cx, 10
rep movsb