[汇编语言]标志寄存器


CPU内部的寄存器中,有一种特殊的寄存器,具有以下3种作用

  1. 用来存储相关指令的某些执行结果
  2. 用来为CPU执行相关指令提供行为依据
  3. 用来控制CPU的相关工作方式

这种特殊的寄存器在8086CPU中,被称为标志寄存器,8086CPU的标志寄存器有16位,其中存储的信息通常被称为程序状态字(PSW),我们已经使用过8086CPU的ax、bx、cx、dx、si、di等13个寄存器,本章中的标志寄存器(flag)是最后一个寄存器

flag和其他寄存器不一样,其他寄存器是用来存放数据的,都是整个寄存器具有一个含义,但是flag寄存器是按位来起作用的,也就是说每一位都有专门的含义,记录特定的信息:

在这里插入图片描述
flag的1、3、5、12、13、14、15位在8086CPU中没有使用,不具有任何含义,而其他位都具有特殊的含义

这一章中,我们学习相关标志位以及典型指令

一、ZF标志

flag的第6位是ZF,零标志位。它记录相关指令执行后,其结果是否为0。如果结果为0,那么ZF = 1;结果不为0,ZF = 0

比如指令

mov ax,1
sub ax,1
执行后,结果为0,ZF = 1
mov ax,2
sub ax,1
执行后,结果不为0,ZF = 0

二、PF标志

flag的第2位是PF,奇偶标志位,它记录相关指令执行后,其结果的所有bit位中1的个数是否为偶数,如果为偶数pf = 1,奇数pf = 0

mov al,1
add al,10
执行后,结果为00001011B,其中奇数个13个),所以pf = 0

三、SF标志

flag的第7位是SF,符号标志位,它记录相关指令执行后,其结果是否为负。如果结果为负,SF = 1;结果非否,SF = 0。

10000001B可以看作是无符号数129,也可以看作是有符号数-127


四、CF标志

flag的第0位是CF,进位标志位。一般情况下,在进行无符号数运算的时候,它记录了运算结果的最高有效位向更高位的进位值或是借位值(减法就是借位)
在这里插入图片描述

mov al,98H
add al,al	;执行后,(al)=30H,CF = 1,CF记录了从最高位有效位向更高位的进位值
add al,al 	;执行后,(al)=60H,CF = 0,CF记录了从最高位有效位向更高位的进位值

五、OF标志

如果超出了机器所能表示的范围称为溢出。

那么什么是机器所能表示的范围呢?

比如说,指令运算的结果用8位寄存器或是内存单元来存放,比如add al,3,那么对于8位的有符号数据,机器所能表示的范围就是-128 ~ 127,同理,对于16位有符号数据,机器所能表示的范围就是-32768 ~ 32767

如果运算结果超出了机器所能表达的范围,将产生溢出

这里所讲到的溢出只是对有符号数运算而言。下面看两个溢出的例子:

mov al,98
add al,99

执行后将产生溢出,因为add al,99的有符号数运算是:(al)=(al)+99 = 99 + 98 = 197,结果197超过了8位有符号的范围

因为进行的是有符号数运算,所以al中存储的是有符号数,而C5H是由符号数-59的补码,如果我们用add指令进行的是有符号数运算,则99 + 98 = -59这样子的结果是无法接受的,造成这种情况的原因实际上对应的结果是197,为一个由符号数,在8位寄存器al中存放不下。

由于在进行有符号数运算时,可能会发生溢出而造成严重的结果错误。则CPU需要对指令执行后是否产生溢出进行记录。flag的第11位是OF,溢出标志位,一般情况下,OF记录了有符号数运算的结果是否发生了溢出。如果发生了溢出,则OF = 1,如果没有CF = 0

CF是对无符号数运算有意义的标志位,而OF是对有符号数运算有意义的标志位。

比如:

mov al,98
add al,99

add指令执行后,CF = 0,OF = 1,CPU在执行add等指令的时候就包含了两种含义:无符号数和有符号数的运算。对于无符号数运算,CPU用CF位来记录是否产生了进位;对于有符号数来说,用OF来记录是否产生了进位,当然还有CF来记录有结果的符号。对于无符号运算,99+98没有进位,CF=0,对于有符号数的运算,99+98发生了溢出,OF=1


六、adc指令

adc是带进位加法指令,它利用了CF位上记录的进位值。

指令格式:adc 操作对象1,操作对象2
功能:操作对象1 = 操作对象1 + 操作对象2 + CF

比如指令:adc ax,bx实现的功能是:(ax)=(ax)+(bx)+CF

mov ax,2
mov bx,1
sub bx,ax ;
adc ax,1

执行后(ax) = 4,执行的时候相当于是计算:(ax)+1+CF = 2 + 1 + 1

可以看出,adc指令比add指令多加了一个CF位的值。

为什么CPU要提供这样一条指令?

在执行adc指令的时候加上CF值的含义是由adc指令前面的指令所决定的,也就是说,关键在于所加上的CF值被什么指令设置的。显然,如果CF的值是被sub指令设置的,那么它的含义加上借位值,如果是被add指令设置的,它的含义就是进位值

下面的指令和add ax,bx具有相同的结果:

add al,bl
adc ah,bh

看来CPU提供adc指令的目的就是用来进行加法的第二部运算的。adc指令和add指令相配合就可以对更大的数据进行加法运算。

编程,计算1EF000H+201000H,结果存在ax(高16位)bx(低16)
因为两个数据的位数都大于16,用add指令无法进行计算。我们将计算分两步进行,先将低16位相加,然后将高16位和进位值相加。

mov ax,001EH
mov bx,0F000H
add bx,1000H
adc ax,0020H

adc指令执行后,可能产生进位值,所以也会对CF位进行设置。由于有这样的功能,我们就可以对任意大的数据进行加法运算

编程,计算1EF0001000H+2010001EF0H,结果存在ax(最高16位)bx(次高16位)cx(低16位)

  1. 先将低16位进行相加,完成后,CF记录本次相加的进位值
  2. 然后将次高16位和CF相加,完成后CF记录本次进位
  3. 最高16位和CF相加,完成后,CF中记录本次相加的进位值
mov ax,001EH
mov bx,0F000H
mov cx,1000H
add cx,1EF0H
adc bx,1000H
adc ax,0020H

七、sbb指令

sbb是带借位减法指令,它利用了CF位上记录的借位值

指令格式:sbb 操作对象1,操作对象2
功能:操作对象1 = 操作对象1 - 操作对象2 - CF

比如指令:sub ax,bx实现的是:(ax)=(ax)-(bx)-CF

sbb指令执行后,要对CF进行设置,利用sbb指令可以对任意大的数据进行减法运算。比如计算003E1000H-00202000H,结果存在ax、bx中

程序如下:

mov bx,1000H
mov ax,003Eh
sub bx,2000H
sbb ax,0020H

八、cmp指令

cmp是比较指令,cmp的功能相当于是减法指令,只是不保存结果。cmp指令执行后,将对标志寄存器产生影响。其他相关指令通过识别这些被影响的标志寄存器来得知比较结果。

cmp 指令格式:cmp 操作对象1,操作对象2

功能:计算操作对象1 - 操作对象2,但不保存结果,仅仅根据计算结果对标志寄存器来进行设置

比如:指令cmp ax,ax,做(ax)-(ax)的运算,结果为0,但并不在ax中保存,仅影响flag的相关各位。——比如看借不借位,结果为不为0决定了CF和ZF

cmp ah,bh
如果(ah)=(bh),则(ah)-(bh) = 0,所以zf = 1
如果(ah)≠(bh),则(ah)-(bh) ≠ 0,所以zf = 0

所以可以根据cmp指令执行后的zf值,就可以判断两个数据是否相等

对于有符号数,(ah)< (bh)的情况下,(ah)-(bh)可能会引起sf = 1,即结果为负。但是结果为负不一定说明(ah)<(bh),比如(ah)-(bh) = 34 - (-96) = 82H,82H是-126的补码,所以sf = 1


九、检测比较结果的条件转移指令

转移指的是他可以修改IP,而条件指的是他可以根据某种条件,决定是否修改IP

比如,jcxz就是一个条件转移指令,他可以检测cx中的数值,如果(cx)=0,就修改IP,否则什么也不做。所有条件转移位移都是-128 ~ 127

除了jcxz外,CPU还提供了其他条件转移指令,大多数条件转移指令都检测标志寄存器的相关标志位,根据检测的结果来决定是否修改IP。他们检测的是哪些标志位?他们检测的都是哪些标志位?

下面是常用的根据无符号数的比较结果进行转移的条件转移指令:

指令含义检测的相关标志位
je等于则转移zf = 1
jne不等于则转移zf = 0
jb低于则转移cf = 1
jnb不低于则转移cf = 0
ja高于则转移cf = 0且zf = 0
jna不高于则转移cf = 1或zf = 1

e表示equal
ne表示not equal
b表示below
nb表示not below
a表示above
na表示not above

这些都是cmp指令进行无符号数比较的时候,记录比较结果的标志位,比如je,检测zf位,当zf = 1的时候,进行转移,如果在je前面使用了cmp指令,那么je对zf的检测实际上就是间接的堆cmp比较结果。

编程实现如下功能:如果(ah)=(bh)则(ah)=(ah)+(ah),否则(ah)=(ah)+(bh)

cmp ah,bh
je s
add ah,bj;否则的情况
jmp short ok
s:add ah,ah
ok:...

十、DF标志和串传送指令

flag的第十位是DF,方向标志位。在串处理指令中,控制每次操作后si和di的增减

df = 0,每次操作后si、di递增
df = 1,每次操作后si、di递减

下面看一个串传送指令:
格式:movsb
功能:执行movsb相当于进行下面几步操作:

  1. ((es)*16+(di)) = ((ds)*16+(si))
  2. 如果df = 0,则(si)=(si)+1,(di)=(di)+1;如果df = 1,则相应减1

汇编语言描述movsb功能如下:
``mov es:[di],byte ptr ds:[si] ;可以看作底层是这样子写

如果df = 0
inc si
inc di

如果df = 1
dec si
dec di

可以看出,movsb的功能是将ds:si指向的内存单元中的字节送入es:di,然后根据df的值,将si和di+1或是-1

当然也可以传送一个字:
格式:mov sw
mov es:[di],word ptr ds:[si];可以看作底层是这样子写

如果df = 0
add si,2
add di,2

如果df = 1
sub si,2
sub di,2

movsb和movsw进行的是串传送操作的一个步骤,一般来说,movsb和movsw都是和rep配合使用,格式如下:
rep movsb
用汇编语法来描述rep movsb的功能就是:
s: movsb
loop s

可以看出,rep的作用是根据cx,重复执行后面的串传送指令。由于每执行依次movsb指令si和di都会递增或是递减指向后一个单元或是前一个单元。则rep movsb就可以循环实现(cx)个字符的传送

同理,也可以使用这样子的指令:rep movsw

相当于是:
s: movsw
loop s

由于flag的df位决定着串传送指令执行后,si和di改变的方向,所以CPU应该提供相应的指令来对df位进行设置,从而使程序员能够决定传送的方向。

8086CPU提供下面两条指令对df位进行设置:
cld指令:将标志寄存器的df置为0
std指令:将标志寄存器的df置为1

看下面两个程序:

  1. 用串传送指令,将data段中的第一个字符串复制到他后面的空间中
data segment
	db 'welcome to masm'
	db 16 dup(0)
data ends

传送的原始位置:ds:si
传送的目的位置:es:di
传送的长度:cx
传送的方向:df

mov ax,data
mov ds,ax
mov si,0 ;ds:si指向data:0
mov es,ax
mov di,16
mov cx,16
cld
rep movsb

十一、pushf和popf

pushf的功能是将标志寄存器中的值压栈,而popf是从栈中弹出数据,送入标志寄存器中

pushf和popf为直接访问标志寄存器提供了一种方法

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值