11.1 ~ 11.6

2020-11-10
2020-11-10
6 min read
Hits

  《汇编语言(第3版)》11.1 ~ 11.6、《零基础入门学习汇编语言》P54 ~ 55

第十一章 标志寄存器

  8086 CPU 的标志寄存器有 16 位,其中存储的信息通常被称为程序状态字(PSW)。

  我们已经使用过 8086 CPU 的 ax、bx、cx、dx、si、di、bp、sp、ip、cs、ss、ds、es 等 13 个寄存器了。

  本章中的标志寄存器(以下简称为 flag)是我们要学习的最后一个寄存器。

  flag 和其他寄存器不一样,其他寄存器是用来存放数据的,都是整个寄存器具有一个含义。

  而 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,零标志位。它记录相关指令执行后

  1. 结果为 0,ZF=1
  2. 结果不为 0,ZF=0

  例如

mov ax,1
sub ax,1
指令执行后,结果为 0,则 ZF=1

mov ax,2
sub ax,1
指令执行后,结果为 1,则 ZF=0

  对于 ZF 的值,我们可以这样来看,ZF 标记相关指令的计算结果是否为 0,如果为 0,则在 ZF 要记录下“是 0”这样的肯定信息。

mov ax,1
and ax,0
执行后,结果为 0,则 ZF=1,表示“结果是 0”

mov ax,1
or ax,0
执行后,结果不为 0,则 ZF=0,表示“结果非 0”

在 8086 CPU 的指令集中,有的指令的执行是影响标志寄存器的,比如:add、sub、mul、div、inc、or、and 等,它们大都是运算指令(进行逻辑或算术运算); 有的指令的执行对标志寄存器没有影响,比如:mov、push、pop 等,它们大都是传送指令。

  我们在使用一条指令的时候,要注意这条指令的全部功能,其中包括,执行结果对标记寄存器的哪些标志位造成影响。

11.2 PF 标志

flag 的第 2 位是 PF,奇偶标志位。它记录指令执行后,结果的所有二进制中 1 的个数

  1. 为偶数,PF=1
  2. 为奇数,PF=0

  示例

mov al,1
add al,10
执行后,结果为 00001011B,其中有 3(奇数)个 1,则 PF=0

mov al,1
or al,10
执行后,结果为 00000011B,其中有 2(偶数)个 1,则 PF=1

有符号数与补码

  我们知道计算机中通常用补码来表示有符号数据。计算机中的一个数据可以看作是有符号数,也可以看成是无符号数。

  比如

  1. 00000001B,可以看作为无符号数 1,或有符号数 +1
  2. 10000001B,可以看作为无符号数 129,也可以看作有符号数 -127

  这也就是说,对于同一个二进制数据,计算机可以将它当作无符号数据来运算,也可以当作有符号数据来运算。

11.3 SF 标志

flag 的第 7 位是 SF,符号标志位。它记录指令执行后

  1. 结果为负,SF=1
  2. 结果为正,SF=0

  示例

mov al,10000001B
add al,1
结果:(al)=10000010B

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

  也可以将 add 指令进行的运算当作有符号数的运算,那么 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
表示:如果指令进行的是有符号数运算,那么结果为非负。

  某些指令将影响标志寄存器中的多个标志位。这些被影响的标记为比较全面地记录了指令的执行结果,为相关的处理提供了所需的依据。

  比如指令 sub al,al 执行后,ZF、PF、SF 等标志位都要受到影响,它们分别为:1、1、0。

11.4 CF 标志

  flag 的第 0 位是 CF,进位标志位。

  一边情况下,在进行无符号数运算的时候,它记录了运算结果的最高有效位向更高位的进位值,或从更高位的错位值。

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

  我们知道,当两个数据相加的时候,有可能产生从最高有效位向更高位的进行。

  比如,两个 8 位数据:98H+98H,将产生进位。由于这个进位值在 8 位数中无法保存,我们在前面的课程中,就只是简单地说这个进位值丢失了。

  其实 CPU 在运算的时候,并不丢弃这个进位值,而是记录在一个特殊的寄存器的某一位上。

  8086 CPU 就用 flag 的 CF 位来记录这个进位值。

  另外一种情况,而当两个数据做减法的时候,有可能向更高位借位。

  比如,两个 8 位数据:91H-98H,将产生借位,借位后,相当于计算 197H-98H。

  而 flag 的 CF 位也可以用来记录这个借位值。

11.5 OF 标志

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

  比如:add al,3,那么对于 8 位的有符号数据,机器所能表示的范围就是 -128~127。

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

这里所讲的溢出,只是对有符号数运算而言。(就像进位只是相对于无符号数而言!)

  就上面的两个例子来说

mov al,98
add al,99

  add 指令运算的结果是 (al)=0C5H,因为进行的是有符号数运算,所以 al 中存储的是有符号数,而 0C5H 是有符号数 -59 的补码。

  如果我们用 add 指令进行的是有符号数运算,则 98+99=-59 这样的结果让人无法接受。

  造成这种情况的原因,就是实际的结果 197,作为一个有符号数,在 8 位寄存器 al 中存放不下。

  由于在进行有符号数运算时,可能发生溢出而造成结果的错误。所以 CPU 需要对指令执行后是否产生溢出进行记录。因此有了 OF

记住,一定要注意 CF 和 OF 的区别

  1. CF 是对无符号数运算有意义的标志位
  2. 而 OF 是对有符号数运算有意义的标志位

  对于无符号数运算,CPU 用 CF 位来记录是否产生了进位;

  对于有符号数运算,CPU 用 OF 位来记录是否产生了溢出,

  当然,还要用 SF 位来记录结果的符号。

对于有无符号,计算机是分不清楚状况的,因此他必须两种都记载着,要怎么用,看的是你当他是什么!

  例如

mov al,98d
add al,99d

  对于无符号数运算,98+99 没有进位,CF=0;

  对于有符号数运算,98+99 发生溢出,OF=1。

11.6 adc 指令

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

  1. 格式:adc 操作对象 1,操作对象 2
  2. 功能:操作对象 1=操作对象 1+操作对象 2+CF
  3. 比如:adc ax,bx 实现的功能是:(ax)=(ax)+(bx)+CF

adc 指令示例

mov ax,2
mov bx,1
sub bx,ax
adc ax,1     # 执行后,(ax)=4
adc 执行时,相当于计算:(ax)+1+CF=2+1+1=4

mov ax,1
add ax,ax
adc ax,3     # 执行后,(ax)=5
adc 执行时,相当于计算:(ax)+3+CF=2+3+0=5

mov al,98H
add al,al
adc al,3     # 执行后,(ax)=34H
adc 执行时,相当于计算:(ax)+3+CF=30H+3+1=34H

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

add al,bl
adc ah,bh

  看来 CPU 提供 adc 指令的目的,就是来进行加法的第二步运算的。

  adc 指令和 add 指令相配合就可以对更大的数据进行加法运算。

Avatar

Hui.Ke

❤ Cyber Security | Safety is a priority.