CPU 内部的寄存器中,有一种特殊的寄存器(根据不同的处理器,个数和结构都可能不同)具有以下 3 种作用。
- 用来存储相关指令的某些执行结果
- 用来为 CPU 执行相关指令提供行为依据
- 用来控制 CPU 相关的工作方式
这种特殊的寄存器在 8086CPU 中,被称为标志寄存器。8086CPU 的标志寄存器有 16 位,其中存储的信息通常被称为程序状态字(PSW)。
8086CPU 的 flag 寄存器的结构如下图所示:
flag 寄存器的 1、3、5、12、13、14、15 位在 8086CPU 中没有使用,不具有任何含义。而 0、2、4、6、7、8、9、10、11 位都具有特殊的含义。
在 debug 调试器中各标志位的状态如下:
状态标志位
CF 标志位
flag 的第 0 位是 CF 位,进位标志位,用来记录无符号运算的结果。当逻辑运算,出现超出寄存器大小的范围进位时 CF 位置 1,或者向超出寄存器大小范围进行借位时 CF 位置 1。
例1(进位):
1 | al=FF=0(进位值) 1(最高有效位)111 1111 |
例2(借位):
1 | al=5=0(借位值) 0101 |
这里的进位或者借位,就可以当成 CF 位,当两个数相加或相减的操作数超过寄存器的大小,CF 位就会置 1。
PF 标志位
flag 的第 2 位是 PF,奇偶标志位。它记录了相关指令执行后,其结果的所有 bit 位中 1 的个数是否为偶数。如果 1 的个数偶数,pf=1,如果为奇数,那么 pf=0。
例1:
1 | mov al,1 |
执行后,结果为 00010001B,其中有 2(偶数)个 1,则 pf=1;
例2:
1 | sub al,10 |
执行后,结果为 00000001B,其中有 1(奇数)个 1,则 pf=0。
PF位通常用来做校验的,校验数据传输的结果是否正确,或者校验数据拷贝的结果是否正确。例如:传输的时候有 4 个 1,但是接收的时候是3 个 1,这个时候就说明你传输的结果错了。
ZF 标志
flag 的第 6 位是 ZF,零标志位。它记录相关指令执行后,其结果是否为 0。结果为 0,那么 zf=1;如果结果不为 0,那么 zf=0。
例1:
1 | mov ax,1 |
执行后,结果为 0,则 zf=1,表示 “结果是 0”
例2:
1 | mov ax,2 |
执行后,结果不为0,则 zf=0,表示 “结果非 0”
在 8086CPU 的指令集中,大多数逻辑运算指令的执行是影响标志寄存器的,大多数数据转移指令的执行对标志寄存器没有影响。
SF 标志
flag 的第 7 位是 SF,符号标志位。它记录相关指令执行后,其结果是否为负。如果结果为负,sf=1;如果非负,sf=0。
在计算机中我们可以人为把一个数据看作是有符号数,也可以看成是无符号数。当把一个数看作有符号数,其最高位就是符号位(不包括在数值运算中)
例如:
1 | 0000 0001B,有符号数+1; |
例1(3+4):
1 | mov al,3 |
计算结果:3+4=7
两个正数相加,最高位是 0,SF 置 0
例2(-1-1):
1 | mov al,ff |
计算结果:-1+(-1)=-2(FE)
当 2 个负数相加最高位是1,所以 SF 置 1 。同时又因为这两个值相加导致出现溢出,所以 CF 位也置 1 。我们可以得出有符号数的运算,是会影响到无符号数运算的 CF 标志位。那这个会对无符号数运算有影响吗?
SF位和CF位同时改变对计算结果没有影响,SF 位是符号位只表示这个值是正数还是负数,不会影响结果。如果我们做的是无符号计算,对于我们来说 SF 位如何改动都是没有意义的。
OF 标志
flag 的第 11 位是 OF,溢出标志位(针对有符号数的进位运算)。如果有符号数运算结果超出机器所能表达的范围,将产生溢出,这里的溢出只是对有符号数运算而言。对于 8 位的有符号数据,机器所能表示的范围是 -128127,对于 16 位有符号数据,机器所能表示的范围是 -3276823767。
例1(100+100):
1 | mov al,64 |
计算结果:100+100=00C8
al 最大有符号数 127(7F),当 2 个正数相加得到的结果是负数,那就说明计算结果超过该寄存器有符号数的存储范围 OF 置 1 ,否则 OF 为 0
OF位和CF位同样互不影响,你要计算有符号数的进位,就看OF位;要计算无符号数的进位就看 CF 位。计算的时候别把这两个位搞混了,你想计算有符号数的进位,但是用的是CF位来计算,那就出问题了。
控制标志位
TF 位
TF 位用于单步执行,调试器中的 T 命令就是单步执行。默认情况下 TF 位是为 0 的,也就是说 IP指针寄存器自动加1,程序会自动往下一条一条地执行指令。当 TF 置 1 时,就是单步执行,调试器里面的单步调试,就是 CPU 里面已经设置好了 TF 位,允许单步执行,所以调试器才可以单步执行。
IF 位
IF 位默认状态是置 1 的,这个是中断标志位。中断可以理解为高级语言中的函数,其功能是控制计算机的外设数据的输入/输出。IF 置 1 表示开中断,IF 置 0 表示关中断。如果 IF 位置 0 了,那么外设就无法使用了,你无法通过外设向计算机中输入任何的数据。
DF 位
DF 位默认状态是 0 ,是方向标志位。表示数据读取/拷贝是从左向右拷贝数据,还是从右向左拷贝数据。DF 置 0 是从左往右,即从低地址向高地址读取/拷贝数据。DF 置 1 是则相反。
JCC 指令
JCC 指令是根据状态标志位,进行跳转的指令,它主要分为 3 组
一组是直接判断状态标志位
一组是无符号数的JCC指令
一组是有符号数的JCC指令
代码练习
JB.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38;程序名:jb.asm
;功能:显示一个字符串
;===========================
assume cs:code,ds:data
data segment
;8086汇编中的变量定义
;在数据段偏移地址0处,定义一个以字节为单位的string变量
;为其分配 22 个字节大小的内存空间,并将数值初始化为相应字符
string db "hello ,welcome to JB!","$"
;在数据段偏移地址 number 处,定义一个以字节为单位的 number 变量,
;为其分配 6 个字节大小的内存空间,并将数值初始化为 "1,2,3,4,5,6"
number db 1,2,3,4,5,6
data ends
code segment
start:
mov ax,data
mov ds,ax
;jb(jmp below)无符号数跳转,[si] < [si+1] CF=0
mov si,offset number
mov al,byte ptr ds:[si]
cmp al,[si+1] ;使用减法运算,功能与 sub 指令一样,区别在于该指令不会改变寄存器中的值
jb str
;
mov ax,4c00h
int 21h
;
str:
mov dx,offset string
mov ah,9
int 21h
mov ax,4c00h
int 21h
code ends
end startJL.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32;程序名:JL.asm
;功能:显示一个字符串
;===========================
assume cs:code,ds:data
data segment
string db "hello ,welcome to JL!","$"
number db 1,2,3,4,5,6
data ends
code segment
start:
mov ax,data
mov ds,ax
;jL(jmp less)有符号数跳转,[si] < [si+1] SF xor OF=1 跳转
mov si,offset number
mov al,-1
cmp al,1 ;有符号数 -1<1
;jb str ;用无符号数跳转,程序出现错误
jl str
;
mov ax,4c00h
int 21h
;
str:
mov dx,offset string
mov ah,9
int 21h
mov ax,4c00h
int 21h
code ends
end startje.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30;程序名:je.asm
;功能:显示一个字符串
;===========================
assume cs:code,ds:data
data segment
string db "hello ,welcome to jE!",0dh,0ah,24h
number db 1,2,3,4,5,6
data ends
code segment
start:
mov ax,data
mov ds,ax
;je(jmp equal)相等就跳转,[si] == [si] ZF=1
mov si,offset number
mov al,byte ptr ds:[si]
cmp al,[si]
je str
;
mov ax,4c00h
int 21h
str:
mov dx,offset string
mov ah,9
int 21h
mov ax,4c00h
int 21h
code ends
end start
注意:你要进行有符号数运算,就用有符号数跳转;无符号数运算,用无符号数跳转。无符号数跳转中含有B(Below)和A(Above),有符号数跳转中含有L(Less)和G(greater)。如有其他问题,自己修改代码进行验证。
跳转指令太多,有映像就行,不需要死记,如果忘了就去查,这些指令用多了就记住了。
- 本文标题:8086汇编-标志寄存器
- 本文作者:9unk
- 创建时间:2022-04-17 01:07:13
- 本文链接:https://9unkk.github.io/2022/04/17/8086-hui-bian-biao-zhi-ji-cun-qi/
- 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!