一、 标志寄存器

CPU内部的寄存器中,有一种特殊的寄存器(对于不同的处理机,个数和结构都可能不同)具有以下三种作用:

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

这种特殊的寄存器在8086CPU中,被称为标志寄存器。8086CPU的标志寄存器有16位,其中存储的信息通常被称为程序状态字(PSW)。在后面我们将标志寄存器简称为flag。

flag和其他寄存器不一样,它是按位起作用的,每一位都有专门的含义,记录特定的信息。

8086CPU的flag寄存器的结构如下图所示:

flag的1、3、5、12、13、14、15位在8086CPU中没有使用,不具有任何含义。而0、2、4、6、7、8、9、10、11位都具有特殊的含义。

1.1 ZF标志

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

比如,指令:

mov ax,1
sub ax,1

执行后,结果为0,则zf=1

注意,在8086CPU的指令集中,有的指令的执行是影响标志寄存器的,比如:add、sub、mul、div、inc、or、and等,它们大都是运算指令(进行逻辑或算术运算);有的指令的执行对标志寄存器没有影响,比如,mov、push、pop等,它们大都是传送指令。在使用一条指令的时候,要注意这条指令的全部功能,其中包括,执行结果对标志寄存器的哪些标志位造成影响。

1.2 PF标志

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

比如,指令:

mov al,1
add al,10

执行后,结果为00001011B,其中有3个1,则pf=0

1.3 SF标志

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

计算机中通常用补码来表示有符号数据。计算机中的一个数据可以看作是有符号数,也可以看成是无符号数。这也就是说,对于同一个二进制数据,计算机可以将它当作无符号数据来运算,也可以当作有符号数据来运算,比如:

mov al,10000001B
add al,1

结果:(al)=10000010B

可以将add指令进行的运算当作无符号数的运算,那么add指令相当于计算129+1,结果为130(10000010B);也可以将指令进行的运算当作有符号数的运算,那么add指令相当于计算-127+1,结果为-126(10000010B)。

不管我们如何看待,CPU在执行add等指令时,就已经包含了两种含义,也得用同一种信息来记录两种结果。关键在于我们的程序需要哪一种结果。

SF标志,就是CPU对有符号数运算结果的一种记录,它记录数据的正负。在我们将数据当作有符号数来运算的时候,可以通过它来得知结果的正负。如果我们将数据当作无符号数来运算,SF的值则没有意义,虽然相关的指令影响了它的值。

这也就是说,CPU在执行add等指令时,是必然要影响到SF标志位的值的。

比如:

mov al,10000001B
add al,1

执行后,结果为10000010B,sf=1,表示:如果指令进行的是有符号数运算,那么结果为负。

mov al,10000001B
add al,01111111B

执行后,结果为0,sf=0,表示:如果指令进行的是有符号数运算,那么结果为负。

1.4 CF标志

flag的第0位是CF,进位标志位。一般情况下,在进行无符号数运算的时候,它记录了运算结果的最高有效位向更高位的进位值,或从更高位的借位值。

对于位数为N的无符号数来说,其对应的二进制信息的最高位,即第N-1位,就是它的最高有效位,而假想存在的第N位,就是相当于最高有效位的更高位,如图11.2所示:

当两个数据相加的时候,有可能产生从最高有效位向更高位的进位。比如,两个8位数据:98H+98H,将产生进位。但是这个进位值在8位数中无法保存,注意CPU在运算的时候,并不丢弃这个进位值,而是记录在一个特殊的寄存器的某一位上,8086CPU就用flag的CF位来记录这个进位值,比如,下面的指令:

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

而当两个数据做减法的时候,有可能向更高位借位。比如,两个8位数据:97H-98H,将产生借位,借位后,相当于计算197H-98H。而flag的CF位也可以用来记录这个借位值。比如,下面的指令:

mov al,97H
sub al,98H          ;执行后,(al)=FFH,CF=1,CF记录了向更高位的借位值
sub al,al           ;执行后,(al)=0, CF=0,CF记录了向更高位的借位值

1.5 OF标志

在进行有符号数运算的时候,如果结果超过了机器所能表示的范围称为溢出。

flag的第11位是OF,溢出标志位。一般情况下,OF记录了有符号数运算的结果是否发生了溢出。如果发生溢出,OF=1;如果没有,OF=0。

要注意CF和OF的区别:CF是对无符号数运算有意义的标志位,而OF是对有符号数运算有意义的标志位。比如:

mov al,98
add al,99

执行后结果为98+99=197,超过了8位有符号数的范围-128~127,但是没有超过无符号数的范围0~256,所以add指令执行后,CF=0,OF=1。CPU在执行add等指令的时候,就包含了两种含义:无符号运算和有符号运算。对于无符号运算,CPU用CF位来记录是否产生了进位;对于有符号数运算,CPU用OF位来记录是否产生了溢出,当然,还要用SF位来记录结果的符号。

CF和OF所表示的进位和溢出,是分别对无符号数和有符号数运算而言的,它们之间没有任何关系。

二、adc指令

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

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

例:

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

执行后,(ax)=4

为什么要加上CF的值呢?先来看下CF的值的含义,在执行adc指令的时候加上的CF的值的含义,是由adc指令前面的指令决定的,也就是说,关键在于所加上的CF值是被什么指令设置的。显然,如果CF的值是被sub指令设置的,那么它的含义就是错位值;如果是被add指令设置的,那么它的含义就是进位值。所以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进行设置。由于有这样的功能,我们就可以对任意大的数据进行加法运算。

三、sbb指令

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

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

sbb和adc是基于同样的思想设计的两条指令。

四、cmp指令

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

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

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

比如,指令cmp ax,ax,做(ax)-(ax)的运算,结果为0,但并不在ax中保存,仅影响flag的各相关位。指令执行后,zf=1,pf=1,sf=0,cf=0,of=0。

下面的指令:

mov ax,8
mov bx,3
cmp ax,bx

执行后:(ax)=8, zf=0, pf=1, sf=0, cf=1, of=0

我们通过cmp指令执行后,相关标志位的值就可以看出比较的结果,以cmp ax,bx为例:

  • 如果(ax)=(bx),则(ax)-(bx)=0,所以:zf=1
  • 如果(ax)≠\ne​=(bx),则(ax)-(bx)≠\ne​= 0,所以:zf=0
  • 如果(ax)<(bx),则(ax)-(bx)将产生借位,所以:cf=1
  • 如果(ax)>=(bx),则(ax)-(bx)不会产生借位,所以:cf=0
  • 如果(ax)>(bx),则(ax)-(bx)即不必借位,结果又不为0,所以:cf=0且zf=0
  • 如果(ax)<=(bx),则(ax)-(bx)即可能借位,结果可能为0,所以:cf=1或zf=1

根据上面的标志寄存器的值和cmp结果的对应,我们可以看出比较指令的设计思路,即:通过做减法运算,影响标志寄存器,标志寄存器的相关位记录了比较的结果,反过来看上面的例子,指令cmp ax,bx的逻辑含义是比较ax和bx中的值,如果执行后:

  • zf=1,说明(ax)=(bx)
  • zf=0,说明(ax)≠\ne​=(bx)
  • cf=1,说明(ax)<(bx)
  • cf=0,说明(ax)>=(bx)
  • cf=0并且zf=0,说明(ax)>(bx)
  • cf=1或zf=1,说明(ax)<=(bx)

同add、sub指令一样,CPU在执行cmp指令时,同样包含两种含义:进行无符号数运算和进行有符号数运算。所以利用cmp指令可以对无符号数进行比较,也可以对有符号数进行比较。上面陈述的都是利用cmp进行无符号数比较时,相关标志位对比较结果的记录。下面我们看下如果用cmp来进行有符号数比较时,CPU用哪些标志位对比较结果进行记录,以cmp ah,bh为例进行说明:

  • 如果(ah)=(bh),则(ah)-(bh)=0,所以:zf=1
  • 如果(ah)≠\ne​=(bh),则(ah)-(bh)=≠\ne​= 0,所以:zf=0

所以,根据cmp指令执行后zf标志位的值,我们就可以知道两个数据是否相等,我们继续看,如果(ah)<(bh)则可能发生什么情况:

对于有符号数运算,在(ah)<(bh)的情况下,(ah)-(bh)显然可能引起sf=1,即结果为负,比如(ah)=1, (bh)=2,则(ah)-(bh)=0FFH为-1的补码,因为结果为负,所以SF=1,但是注意,仅仅通过sf=1就判断操作对象1<操作对象2是不成立的,再看下如下的例子:
(ah)=22H, (bh)=0A0H,则(ah)-(bh)=34-(-96)=82H,82H是-126的补码,所以sf=1,这里sf=1,但是显然(ah)>(bh)。

两个有符号数相减,如果A<B,那么得到的肯定是一个负数,这个思路没有错,关键在于我们根据什么来断定得到的是一个负数。CPU将cmp指令得到的结果记录在flag的相关标志位中,我们可以根据指令执行后,相关标志位的值来判断比较的结果。单纯的考察sf的值不可能知道结果的正负,因为sf记录的只是可以在计算机中存放的相应位数的结果的正负。比如add ah,al执行后,sf记录的是ah中的8位二进制信息所表示的数据的正负。cmp ah,bh执行后,sf记录的是(ah)-(bh)所得到的8位结果数据的正负,虽然这个结果没有在我们能够使用的寄存器或内存单元中保存,但是在执行执行的过程中,它暂存在CPU内部的暂存器中。

所得到的相应结果的正负,并不能说明,运算所应该得到的结果的正负。这是因为在运算的过程中可能发生溢出,如果有这样的情况发生,那么sf的值就不能说明任何问题,例如:

mov ah,22H
mov bh,0A0H
sub ah,bh

结果sf=1,运算实际得到的结果是(ah)=82H,但是在逻辑上,运算所应该得到的结果为34-(-96)=130。就是因为130这个结果作为一个有符号数超过了-128~127这个范围,在ah中不能表示,而ah中的结果被CPU当作有符号数解释为-126。而sf被用来记录这个实际结果的正负,所以sf=1。但是sf=1不能说明在逻辑上,运算所得是正确结果的正负。

但是逻辑上的结果的正负,才是cmp指令所求的真正结果,因为我们就是要靠它得到两个操作对象的比较信息。所以cmp指令所作的比较结果,不是仅仅靠sf就能记录的,因为它只能记录实际结果的正负。

差错就出现在了溢出这里,如果没有溢出发生,那么实际结果的正负和逻辑结果的正负就是完全一致的,所以我们应该在考察sf(得知实际结果的正负)的同时考察of(得知有没有溢出),就可以得知逻辑上真正结果的正负,同时就可以知道比较的结果。

以下,我们以cmp ah,bh为例,总结下CPU执行cmp指令后,sf和of的值是如何来说明比较的结果的。

  • 如果sf=1,而of=0: of=0,说明没有溢出,逻辑上真正的结果代表实际结果,因为sf=1,实际结果为负,所以逻辑上真正的结果为负,所以(ah)<(bh)
  • 如果sf=1,而of=1: of=1说明有溢出,此时逻辑上真正结果的正负≠\ne​=实际结果的正负,因为sf=1,实际结果为负,说明逻辑上真正的结果为正,这样sf=1,of=1,说明了(ah)>(bh)
  • 如果sf=0,而of=1: of=1说明有溢出,sf=0表明实际结果非负,如果因为溢出导致了实际结果为正,那么逻辑上真正的结果必然非负,这样sf=0,of=1,说明了(ah)<(bh)
  • 如果sf=0,而of=0:of=0说明没有溢出,逻辑上真正结果的正负=实际结果的正负,因为sf=0,实际结果为负,所以逻辑上真正的结果非负,所以(ah)>=(bh)

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

”转移“指代可以修改IP,而”条件“指的是指令可以根据某种条件,决定是否修改IP。

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

除了jcxz外,CPU还提供了其他的条件转移指令,大多数条件转移指令都检测标志寄存器的相关标志位,根据检测的结果来决定是否修改IP。它们检测的就是被cmp指令影响的那些,表示比较结果的标志位。这些条件转移指令通常和cmp相配合使用,就好像call和ret指令通常相互配合使用的一样。

因为cmp指令可以同时进行两种比较,无符号数比较和有符号数比较,所以根据cmp指令的比较结果进行转移的指令也分为两种,即根据无符号数的比较结果进行转移的条件转移指令(检测zf、cf的值)和根据有符号数的比较结果进行转移的条件转移指令(检测sf、of和zf的值)

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

指令 含义 检测的相关标志位
je 等于则转移 zf=1
jne 不等于则转移 zf=0

/待补充 238

11-标志寄存器+adc/sbb+cmp+条件转移指令相关推荐

  1. 标志寄存器PSW和汇编条件转移指令解释

    标志寄存器PSW 标志寄存器PSW(程序状态字寄存器PSW)    标志寄存器PSW是一个16为的寄存器.它反映了CPU运算的状态特征并且存放某些控制标志.8086使用了16位中的9位,包括6个状态标 ...

  2. 王爽 汇编语言第三版 第11章 标志寄存器

    条件码: ① OF(Overflow Flag)溢出标志,溢出时为1,否则置0.标明一个溢出了的计算,如:结构和目标不匹配. ② SF(Sign Flag)符号标志,结果为负时置1,否则置0. ③ Z ...

  3. 标志寄存器的详细解释

    简介:    CPU内部的寄存器中,有一种特殊的寄存器(对于不同的处理机,个数和结构都可能不同)具有三种作用.    (1)用来存储相关指令的某些执行结果.    (2)用来为CPU执行相关指令提供行 ...

  4. 【汇编】流程转移——标志寄存器(ZF—零标志、PF—奇偶标志、SF—符号标志、CF—进位标志、OF—溢出标志)、adc进位加法指令、sbb借位减法指令、cmp指令、DF标志、REP指令、std、cld

    11.1 标志寄存器 8086CPU中有14个寄存器,在历来文章中已经介绍过大部分,还有一个标志寄存器,在cpu中也担任着重要的位置. 在标志寄存器中是按位来起作用的,也就是说其中每一位的0和1都有着 ...

  5. 汇编语言随笔(3)-条件转移指令和标志寄存器

    标志寄存器 标志寄存器通常具有以下三种作用:       1,用来存储相关指令的某些执行效果       2,用来为CPU执行相关指令提供行为依据       3,用来控制CPU的相关工作方式     ...

  6. 贺利坚老师汇编课程57笔记:CMP和JXXX配合实现条件转移指令if

    指路老师的博客 实现分支程序设计 套路 CMP OPER1,OPER2;或者其他影响标志寄存器的指令 JXXX 标号 恐惧 JXXX系列指令和CMP指令配合,构造条件转移指令 不必考虑CMP指令对相关 ...

  7. 【8086汇编】cmp指令和条件转移指令jxxx

    1.定义 2.无符号比较影响标志位 3.有符号比较影响标志位 4.各种条件转移指令 5.cmp配合条件转移的使用

  8. 汇编语言随笔(9)-实验11(用条件转移指令来编写子程序)

    编写一个子程序,将包含任意字符.以0结尾的字符串中的小写字母转变为大写字母 子程序名称:letterc      参数:ds:si指向字符串首地址. 因为字符串中包含有任意字符,所以不能采用and操作 ...

  9. cmp指令 标志寄存器

    cmp 比较指令 不保存结果的减法指令,但影响标志寄存器 cmp ax,bx ax=bx, 则ZF=1 ax!=bx, 则ZF=0 ax<bx, 则CF=1 ax<=bx,则CF=1或ZF ...

  10. 汇编语言之标志寄存器

     1.标志寄存器 CPU内部的寄存器中,有一种特殊的寄存器(对于不同的处理机,个数和结构都可能不同)具有以下3种作 用: 1. 用来存储相关指令的某些执行结果. 2. 用来为CPU执行相关指令提供 ...

最新文章

  1. Java黑皮书课后题第3章:*3.33(金融:比较成本)假设你要通过两种不同的包裹运输大米。你可能会编写一个程序来比较成本,该程序提示用户输入每个包裹的重量和价格,然后显示具有更优惠的包裹
  2. 增加FiroFox3对迅雷的支持
  3. linux入门系统那个好,初学Linux哪个发行版本好?这些更合适!
  4. 优先级(HTML、CSS)
  5. matlab怎么做多元非线性拟合,MATLAB多元非线性拟合
  6. 如何更改itunes备份位置_itunes备份路径是什么,如何修改itunes备份路径
  7. 简单普及数字人民币概论、特征、架构介绍
  8. K8sAPI接口文档
  9. html+js画一颗心形,用SVG和Vanilla JS框架创建一个“星形变心形”的动画效果
  10. 201819102036张祺
  11. 网络游戏中玩家在线数据的存取
  12. Codeforces.838D.Airplane Arrangements(思路)
  13. java version 1.8下载_JDK1.8下载、安装和环境配置教程
  14. 武汉疫情 - 新型冠状病毒信息整理
  15. 04 Response对象的status_code属性可以获取响应状态码
  16. 应用在电磁炉触控面板中的电容式触摸芯片
  17. matlab 伯德图 横坐标步长_使用MATLAB的m函数画伯德图,设置显示横坐标为HZ
  18. (已更新)王者荣耀改名神器助手微信小程序源码下载
  19. 华为鲲鹏HCIA考试-练习03
  20. 【论文阅读|深读】LINE: Large-scale Information Network Embedding

热门文章

  1. 程序员相亲图鉴,太真实了!
  2. 一年Android工作经验,一举拿下百度、网易、美团、小米、快手等Offer面经
  3. oracle判断一个值不在记录中,Oracle: DELETE前不需SELECT判断记录是否存在,INSERT前不需SELECT判断是否有若干字段值重复的记录。...
  4. python 贴吧调度器_简单的Python调度器Schedule详解
  5. python中矩阵除法_Python numpy矩阵处理运算工具用法汇总
  6. java socket聊天_java_基于Java Socket实现一个简易在线聊天功能(一),最近做了一个项目,其中有一 - phpStudy...
  7. python中数据处理的格式,json.csv txt excel
  8. 鼠标点击改变单元格颜色或点击改变行颜色
  9. 七牛云 rs.php 没有,设置了callbackUrl,七牛只是在客户端上打印了json格式的key和hash,居然没有按照设置跳转回来..怎么弄?...
  10. java deadlock oracle_【DEADLOCK】Oracle“死锁”模拟