目录
引言
11.1 ZF标志
11.2 PF标志
11.3 SF标志
检测点11.1
11.4 CF标志
11.5 OF标志
检测点11.2
11.6 abc指令
11.7 sbb指令
11.8 cmp指令
11.9 检测比较结果的条件转移指令
检测点11.3
11.10 DF标志和串传送指令
1、DF标志
2、串传送指令
11.11 pushf和popf
11.12 标志寄存器在Debug中的表示
引言
CPU内部的寄存器中有一种特殊的寄存器,被称为标志寄存器,具有以下三种作用,:
(1)用来存储相关指令的某些执行结果;
(2)用来为CPU执行相关指令提供行为依据;
(3)用来控制CPU的相关工作方式。
8086 CPU的标志寄存器只有16位,其中存储的信息通常被称为程序状态字(PSW)。
标志寄存器(简称为flag)。flag寄存器是按位起作用的,每一位都有专门的含义,记录特定的信息,与其他寄存器不一样。
8086 CPU的flag寄存器的结构:
flag的1、3、5、12、13、14、15位在8086 CPU中没有使用,不具有任何含义;而0、2、4、6、7、8、9、10、11位都具有特殊的含义。
11.1 ZF标志
flag的第6位是ZF,零标志位,它记录相关指令执行后,结果为0,ZF=1(记录下是0这样的肯定信息),结果不为0,ZF=0(表示结果非0)。
mov ax,1
sub ax,1
mov ax,1
and ax,0
指令执行后,结果为0,则ZF=1
mov ax,2
sub ax,1
mov ax,1
or ax,0
指令执行后,结果为1,则ZF=0
在8086CPU中,add、sub、mul、div、inc、or、and等它们大多都是运算(逻辑运算或是算术运算)指令,是影响标志寄存器的,而mov、push、pop等传送指令对标志寄存器一般没有影响,因为不会产生结果。
11.2 PF标志
flag的第2位是PF,奇偶标志位。记录指令执行后结果所有的二进制位中1的个数。为偶数,PF=1;为奇数,PF=0。
mov al,1
add al,10
执行结果为00001011B,有3个1,则PF=0
mov al,1
or al,10
执行后结果为00000011B,有2个1,则PF=1
11.3 SF标志
flag的第7位是SF,符号标志位。它记录相关指令执行后,其结果是否为负。如果结果为负,sf=1;如果非负,sf=0。
计算机中通常用补码来表示有符号数据。计算机中的一个数据可以看作是有符号数,也可以看作是无符号数。也就是说,对于同一个二进制数据,计算机可以把它当作无符号数据来运算,也可以当作有符号数据来运算。CPU在执行add等指令的时候,就已经包含了两种含义,也将得到用同一种信息来记录的两种结果。
在我们将数据当作有符号数来运算的时候,可以通过它来得知结果的正负。如果我们将数据当作无符号数来运算,SF的值则没有意义,虽然相关的指令影响了它的值。
检测点11.1
11.4 CF标志
flag的第0位是CF,进位标志位。一般情况下,在进行无符号运算的时候,它记录了运算结果的最高有效位向更高位的进位值,或从更高位的借位值。
对于位数为N的无符号数,其对应的二进制信息的最高位,即第N-1位,就是它的最高有效位,假想存在第N位是相对于最高有效位的更高位。
两个8位的数据运算可能产生进位或者借位,由于这个进位值在8位数中无法保存,8086CPU就用flag的CF位来记录这个进位值。
mov al.98h
add al,al ;执行后(al)=30H,cf=1,cf记录了从最高有效位向更高位的进位值
add al,al ;执行后(al)=60H,cf=0,cf记录了从最高有效位向更高位的进位值
mov al,97h
sub al,98h ;执行后(al)=ffh,cf=1,cf记录了向更高位的借位值
sub al,al ;执行后(al)=0,cf=0,cf记录了向更高位的借位值
11.5 OF标志
检测点11.2
11.6 abc指令
adc是带进位加法指令,利用了CF位上记录的进位值。
格式:adc 操作对象1,操作对象2
功能:操作对象1=操作对象1+操作对象2+CF。
mov ax,2
mov bx,1
sub bx,ax
adc ax,1
执行后 (ax)=4,相当于计算(ax)+1+CF=2+1+1+4
mov ax,1
add ax,ax
adc ax,3
执行后(ax)=5,相当于执行(ax)+3+CF=2+3+0=5
mov al,98H
add al,al
adx al,3
执行后 (al)=34H,相当于执行(ax)+3+CF=30H+3+1=34H
由adc指令前面的指令,决定在执行adc指令的时候加上的CF的值的含义。也就是说关键在于所加上的CF值是被什么指令设置的。如果CF的值是被sub指令设置的,那么它的含义就是借位值;如果是被add指令设置的,那么它的含义就是进位值。
加法运算分两步进行:①低位相加②高位相加加上低位相加产生的进位值。
CPU提供adc指令的目的,就是来进行加法的第二步运算的。adc指令和add指令相配合就可以对更大的数据进行加法运算。
编程:计算1EF000H+201000H,结果存放在AX(高16位)和BX(低16位)中。
mov ax,001EH
mov bx,0F000H
add bx,1000H
adc ax,0020H
编程:1EF0001000H+2010001EF0H,结果存放在AX(高16位)、BX(次16位)中和cx(低16位)。
计算分三步进行:
(1)先将低16位相加,完成后,CF中记录本次相加的进位值。
(2)再将次高16位和CF(来自低16位的进位值)相加,完成后,CF中记录本次相加的进位值。
(3)最后高16位和CF(来自次高16位的进位值)相加,完成后,CF中记录本次相加的进位值。
mov ax,001EH
mov bx,0F000H
mov cx,1000H
add cx,1EF0H
add bx,1000H
adc ax,0020H
编程:对两个128位数据进行相加
assume cs:code,ds:data
data segment
db 16 dup(88H)
db 16 dup(11H)
data ends
code segment
start:
mov ax,data
mov ds,ax
mov si,0
mov di,16
mov cx,8
call add128
mov ax,4C00H
int 21H
add128:
push ax
push cx
push si
push di
sub ax,ax;将CF设置为0
s:
mov ax,[si]
adc ax,[di]
mov [si],ax
inc si;不能用add si,2代替
inc si;因为会影响cf位
inc di;而loop和inc不会影响
inc di
loop s
pop di
pop si
pop cx
pop ax
ret
code ends
end start
11.7 sbb指令
sbb是带借位减法指令,利用了CF位上记录的借位值。
格式:sbb 操作对象1,操作对象2
功能:操作对象1=操作对象1-操作对象2-CF
利用sbb指令我们可以对任意大的数据进行减法运算。
sbb和adc是基于同样的思想设计的两条指令,在应用思路上sbb和adc类似。
编程:计算003E1000H-00202000H,结果放在ax,bx中
mov bx,1000H
mov ax,003EH
sub bx,2000H
sbb ax,0020H
11.8 cmp指令
cmp是比较指令,功能上相当于减法指令,只是不保存结果。
格式:cmp 操作对象1,操作对象2
功能:计算操作对象1-操作对象2但不保存结果,仅仅是根据计算结果对标志寄存器进行设置。
cmp指令运算执行后通过做减法将对标志寄存器产生影响,其他相关指令通过识别这些被影响的标志寄存器位来得知比较结果。
cmp ax,ax
执行后结果为0,ZF=1,PF=1,SF=0,CF=0,OF=0
mov ax,8
mov bx,3
cmp ax,bx
执行后ax、bx的值不变,ZF=0,PF=1,SF=0,CF=0,OF=0
通过cmp指令执行后,相关标志位的值就可以看出比较的结果。
cmp ax,bx
指令"cmp ax,bx”的逻辑含义是比较ax和bx中的值,如果执行后:
CPU在执行cmp指令时也包含进行无符号数运算和进行有符号数运算两种含义,所以利用cmp指令可以对无符号数进行比较也可以对有符号数进行比较。
单纯地考察SF的值不可能知道结果的正负。因为SF记录的只是可以在计算机中存放的相应位数的结果的正负(例如:add ah,al执行后,sf记录的是ah中的8位二进制信息所表示的数据的正负)。
以cmp ah,bh为例,总结一下CPU执行cmp指令后,sf和of的值是如何来说明比较的结果的:
1、如果SF=1或SF=0,OF=0,逻辑上真正结果的正负=实际结果的正负。
of=0,说明没有溢出,逻辑上真正结果的正负=实际结果的正负;
若sf=1,实际结果为负,所以逻辑上真正的结果为负,所以(ah)<(bh)
若sf=0,实际结果非负,所以逻辑上真正的结果非负,所以(ah)≥(bh)
2、如果SF=1或SF=0,OF=1,逻辑上真正结果的负正≠实际结果的正负。
of=1,说明有溢出,逻辑上真正结果的正负≠实际结果的正负;
若sf=1,实际结果为负,而又有溢出,这说明是由于溢出导致了实际结果为负,简单分析一下,就可以看出,如果因为溢出导致了实际结果为负,那么逻辑上真正的结果必然为正,则说明(ah)>(bh)。
若sf=0,实际结果非负,而of=1说明有溢出,则结果非0,所以,实际结果为正。实际结果为正,而又有溢出,这说明是由于溢出导致了导致了实际结果非负,简单分析一下就可以看出,如果因为溢出导致了实际结果为正,那么逻辑上真正的结果必然为负,则说明(ah)<(bh)。
11.9 检测比较结果的条件转移指令
与cmp相配使用,根据cmp指令的比较结果(cmp指令执行后相关标志位的值)进行工作的指令。
cmp指令可以同时进行两种比较,无符号数比较和有符号数比较,所以根据cmp指令的比较结果进行转移的指令也分为两种:
(1)根据无符号数的比较结果进行转移的条件转移指令,它们检测ZF、CF的值;
根据有符号数的比较结果进行转移的条件转移指令,它们检测SF、OF、ZF的值。
它们所检测的标志位都是cmp指令进行无符号数比较时候记录比较结果的标志位。
指令 |
含义 |
检测的相关标志位 |
je |
等于则转移 |
ZF=1 |
jne |
不等于则转移 |
ZF=0 |
jb |
低于则转移 |
CF=1 |
jnb |
不低于则转移 |
CF=0 |
ja |
高于则转移 |
CF=0 and ZF=0 |
jna |
不高于则转移 |
CF=1 or ZF=1 |
j |
e |
ne |
b |
nb |
a |
na |
jump |
equal |
not equal |
below |
not below |
above |
not above |
编程:如果(ah)=(bh)则(ah)=(ah)+(ah),否则(ah)=(ah)+(bh)。
cmp ah,bh
je s ;ZF=1则跳转
add ah,bh
jmp short ok
s: add ah,bh
ok: ret
je检测的是ZF的位置,不管je前面是什么指令,只要CPU执行je指令时,ZF=1那么就发生转移。
mov ax,0
mov ax,0
je s
inc ax
s:
inc ax
执行后(ax)=1,add ax,0使得ZF=1,所以je指令将进行转移。
编程:统计data段中数值为8的字节的个数,用ax保存统计结果。
方案一
assume cs:code
data segment
db 8,11,8,1,8,5,63,38
data ends
code segment
start:
mov ax,data
mov ds,ax
mov bx,0;ds:bx指向第一个字节
mov ax,0;初始化累加器
mov cx,0
s:
cmp byte ptr [bx],8;和8进行比较
jne next;如果不相等转到next,继续循环
inc ax;如果相等就计数值加1
next:
inc bx
loop s;执行后:(ax)=3
mov ax,4c00h
int 21h
code ends
end segment
方案二
assume cs:code
data segment
db 8,11,8,1,8,5,63,38
data ends
code segment
start:
mov ax,data
mov ds,ax
mov bx,0;ds:bx指向第一个字节
mov ax,0;初始化累加器
mov cx,0
s:
cmp byte ptr [bx],8;和8进行比较
je ok;如果不相等转到ok,继续循环
jmp short next;如果不想等就转到next,继续循环
ok:
inc ax;如果相等就计数值加1
next:
inc bx
loop s;执行后:(ax)=3
mov ax,4c00h
int 21h
code ends
end segment
编程:统计data段中数值大于8的字节的个数,用ax保存统计结果。
assume cs:code
data segment
db 8,11,8,1,8,5,63,38
data ends
code segment
start:
mov ax,data
mov ds,ax
mov bx,0;ds:bx指向第一个字节
mov ax,0;初始化累加器
mov cx,0
s:
cmp byte ptr [bx],8;和8进行比较
jna next;如果大于8转到next,继续循环
inc ax;如果大于就计数值加1
next:
inc bx
loop s;执行后:(ax)=3
mov ax,4c00h
int 21h
code ends
end segment
检测点11.3
11.10 DF标志和串传送指令
1、DF标志
flag的第10位是DF,方向标志位。
在串处理指令中,控制每次操作后si(一般指向原始偏移地址)、di(一般指向目标偏移地址)的增减。
DF=0:每次操作后si、di递增;
DF=1:每次操作后so、di递减。
2、串传送指令
movsb(mov string byte)串传送指令
以字节为单位传送
格式:movsb
执行movsb相当于以下操作:
(1)((es)*16+(di))=((ds)*16+(si))
(2)如果DF=0,则(si)=(si)+1,(di)=(di)+1;
如果DF=1,则(si)=(si)-1,(di)=(di)-1。
movsb功能:将ds:si指向的内存单元中的字节送入es:di中,然后根据标志寄存器DF位的值将si和di递增1或递减1。
movsw
以字为单位传送。
将ds:si指向的内存单元中的字送入es:di中,然后根据标志寄存器DF位的值将si和di递增2或递减2。
movsb和movsw进行的是串传送操作中的一个步骤,一般和rep配合使用,格式:rep movsb,rep的作用是根据cx 的值,重复执行后面的串传送指令。由于每执行一次movsb指令si和di都会递增或递减指向后一个单元或前个单元,则rep movsb就可以循环实现(cx)个字符的传送。
使用串传送指令进行数据的传送,需要提供:
1、传送的原始位置;
2、传送的目的位置;
3、传送的长度;
4、传送的方向。
由于flag的DF位决定着串传送指令执行后,si和di改变的方向,8086CPU提供两条指令对DF位进行设置:
(1)cld指令:将标志寄存器的DF位设置为0;
(2)std指令:将标志寄存器的DF位设置为1。
11.11 pushf和popf
pushf的功能是将标志寄存器的值压栈,popf是从栈中弹出数据,送入标志寄存器中。
pushf和popf为直接访问标志寄存器提供了一种方法。
下面的程序执行后ax的值是多少?
mov ax,0
push ax
popf
mov ax,0fff0h
add ax,0010h
pushf
pop ax
and al,11000101b
and ah,00001000b文章来源:https://www.toymoban.com/news/detail-728558.html
11.12 标志寄存器在Debug中的表示
文章来源地址https://www.toymoban.com/news/detail-728558.html
到了这里,关于汇编语言——第11章 标志寄存器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!