标志寄存器flag 和其他寄存器不一样,其他寄存器是用来存放数据的,都是整个寄存器具有一个含义。
而flag寄存器是按位起作用的,也就是说,它的每一位都有专门的含义,记录特定的信息。
8086CPU的flag寄存器的结构:
flag的1、3、5、12、13、14、15位在8086CPU中没有使用,不具有任何含义。而0、2、4、6、7、8、9、10、11位都具有特殊的含义。
11.1 ZF标志
flag的第6位是ZF,零标志位。
它记录相关指令执行后,
结果为0 ,ZF = 1
结果不为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”。
注意:
在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。
我们需要先来认识一下有符号数与补码
示例
mov al,10000001B
add al,1
结果: (al)=10000010B
有符号数与补码
我们知道计算机中通常用补码来表示有符号数据。计算机中的一个数据可以看作是有符号数,也可以看成是无符号数。
比如:
00000001B ,可以看作为无符号数 1 ,或有符号数+1;
10000001B ,可以看作为无符号数129,也可以看作有符号数-127。
我们可以将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在运算的时候,并不丢弃这个进位值,而是记录在一个特殊的寄存器的某一位上。
8086CPU 就用flag的CF位来记录这个进位值。
在Debug中,我们可以看到类似下面的信息:
比如,下面的指令:
mov al,98H
add al,al ;执行后: (al)=30H,CF=1,
;CF记录了最高有效位向更高位的进位值
add al,al ;执行后: (al)=30H,CF=0,
另外一种情况,而当两个数据做减法的时候,有可能向更高位借位。
比如,两个 8 位数据:97H-98H,将产生借位,借位后,相当于计算197H-98H。
而flag的CF位也可以用来记录这个借位值。
比如,两个 8 位数据:97H-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的区别:
CF是对无符号数运算有意义的标志位;
而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位上记录的进位值。
格式: adc 操作对象1,操作对象2
功能:
操作对象1=操作对象1+操作对象2+CF
比如:adc ax,bx 实现的功能是:
(ax)=(ax)+(bx)+CF
adc指令示例(一)
mov ax,2
mov bx,1
sub bx,ax
adc ax,l
执行后,(ax)=4。
adc执行时,相当于计算: (ax)+1+CF=2+1+1=4。
adc指令示例(二)
mov ax,1 add ax,ax adc ax,3
执行后,(ax)=5。
adc执行时,相当于计算: (ax)+3+CF=2+3+0=5。
在执行 adc 指令的时候加上的 CF 的值的含义,由 adc指令前面的指令决定的,也就是说,关键在于所加上的CF值是被什么指令设置的。
显然,如果CF 的值是被sub指令设置的,那么它的含义就是借位值;如果是被add指令设置的,那么它的含义就是进位值。
我们来看一下两个数据:0198H和0183H如何相加的:
01 98
+ 01 83
1
-----------------
03 1B
可以看出,加法可以分两步来进行:
(1)低位相加;
(2)高位相加再加上低位相加产生的进位值。
下面的指令和add ax , bx具有相同的结果: add al,bl adc ah,bh
看来CPU提供 adc 指令的目的,就是来进行加法的第二步运算的。
adc指令和add指令相配合就可以对更大的数据进行加法运算。
编程计算1EF000H+201000H,结果放在ax(高16位)和bx(低16位)中。
mov ax,001EH mov bx,0F000H add bx,1000H adc ax,0020H
adc 指令执行后,也可能产生进位值,所以也会对CF位进行设置。
由于有这样的功能,我们就可以对任意大的数据进行加法运算。
例如,编程计算
1EF0001000H+2010001EF0H,结果放在
ax(高16位),bx(次高16位),cx(低16位)中。
程序可以如此实现:
mov ax,001EH
mov bx,0F000H
mov cx,1000H
add cx,1EF0H
adc bx,1000H
adc ax,0020H
下面我们,编写一个子程序,对两个128位数据进行相加。
名称:add128
功能:两个128位数据进行相加
参数:
参数:
ds:si指向存储第一个数的内存空间,因数据为128位,所以需要8个字单元,由低地址单元到高地址单元依次存放 128位数据由低到高的各个字。运算结果存储在第一个数的存储空间中。
ds:di指向存储第二个数的内存空间
11.7 sbb指令
sbb是带借位减法指令,它利用了CF位上记录的借位值。
格式:sbb 操作对象1,操作对象2
功能:
操作对象1=操作对象1–操作对象2–CF
比如:sbb ax,bx
实现功能: (ax) = (ax) – (bx) – CF
利用sbb指令我们可以对任意大的数据进行减法运算。
计算003E100OH–00202000H,结果放在ax,bx中,程序如下:
mov bx,1000H
mov ax,003EH
sub bx,2000H
sbb ax,0020H
sbb和adc是基于同样的思想设计的两条指令,在应用思路上和adc类似。在这里,我们就不再进行过多的讨论。
通过学习这两条指令,我们可以进一步领会一下标志寄存器CF位的作用和意义。
11.8 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=0,
OF=0。
其实,我们通过cmp 指令执行后,相关标志位的值就可以看出比较的结果。
例如:cmp ax,bx
现在我们可以看出比较指令的设计思路
即:通过做减法运算,影响标志寄存器,标志寄存器的相关位记录了比较的结果。
反过来看上面的例子 cmp ax,bx
同 add、sub 指令一样,CPU 在执行cmp指令的时候,也包含两种含义:
进行无符号数运算和进行有符号数运算。
所以利用cmp指令可以对无符号数进行比较,也可以对有符号数进行比较。
下面我们再来看一下如果用cmp来进行有符号数比较时,我们要注意哪些标志位!
我们以cmp ah,bh为例进行说明:
如果(ah)=(bh) 则(ah)-(bh)=0,所以:ZF=1;
如果(ah)≠(bh) 则(ah)-(bh) ≠0,所以:ZF=0;
所以,我们根据cmp指令执行后ZF的值,就可以知道两个数据是否相等。
我们继续看,如果(ah)<(bh)则可能发生什么情况呢?
对于有符号数运算,在 (ah)<(bh) 情况下,(ah)-(bh)显然可能引起SF=1,即结果为负。
比如:
(ah) = 1,(bh) = 2:
则(ah)-(bh)=0FFH,0FFH 为 -1 的补码,因为结果为负,所以SF=1。
(ah)=0FEH,(bx)=0FFH:
则(ah)-(bh)=(-2)-(-1)=0FFH,因为结果为负,所以SF=1。
通过上面的例子,我们是不是可以得到这样的结论:
cmp 操作对象1,操作对象2 指令执行后,SF=1,就说明操作对象1<操作对象2?
当然不是。
我们再看下面这个例子。
(ah)=22H,(bh)=0A0H:
则(ah)-(bh)=34-(-96)=130=82H,82H是 -126的补码,所以SF=1。
这里虽然SF=1,但是并不能说明(ah)<(bh),因为显然34>-96。
两个有符号数A 和B 相减,得到的是负数,那么可以肯定A<B,这个思路没有错误;
关键在于我们根据什么来断定得到的是一个负数。
CPU将 cmp 指令得到的结果记录在flag的相关标志位中。
我们可以根据指令执行后,相关标志位的值来判断比较的结果。
单纯地考察SF 的值不可能知道结果的正负。因为SF 记录的只是可以在计算机中存放的相应位数的结果的正负。
比如add ah, al执行后,SF记录的是ah中的8位二进制信息所表示的数据的正负。
所得到的相应结果的正负,并不能说明,运算所应该得到的结果的正负。
这是因为在运算的过程中可能发生溢出。
如果有这样的情况发生,那么,SF的值就不能说明任何问题。
如果没有溢出发生的话,那么,实际结果的正负和逻辑上真正结果的正负就一致了。
所以,我们应该在考察SF(得知实际结果的正负)的同时考察OF(得知有没有溢出),就可以得知逻辑上真正结果的正负,同时就可以知道比较的结果。
下面,我们以cmp ah,bh为例,总结一下CPU执行cmp指令后,SF和OF的值是如何来说明比较的结果的。
(1)如果SF=1,而OF=0
OF=0,说明没有溢出,逻辑上真正结果的正负=实际结果的正负;
因SF=1,实际结果为负,所以逻辑上真正的结果为负,所以(ah)<(bh)。
(2)如果SF=1,而OF=1
OF=1 ,说明有溢出,逻辑上真正结果的正负≠实际结果的正负;
简单分析一下,就可以看出,如果因为溢出导致了实际结果为负,那么逻辑上真正的结果必然为正。这样,SF=1,OF = 1 ,说明了(ah)>(bh)。
(3)如果SF=0,而OF=1
OF=1 ,说明有溢出,逻辑上真正结果的正负≠实际结果的正负;
简单分析一下,就可以看出,如果因为溢出导致了实际结果为正,那么逻辑上真正的结果必然为负。这样,SF=0,OF = 1 ,说明了(ah)<(bh)。
(4)如果SF=0,而OF=0
OF=0,说明没有溢出,逻辑上真正结果的正负=实际结果的正负;
因SF=0,实际结果非负,所以逻辑上真正的结果必然非负。所以(ah)≥(bh)。
上面,我们深入讨论了cmp指令在进行有符号数和无符号数比较时,对flag 相关标志位的影响,和CPU如何通过相关的标志位来表示比较的结果。
在学习中,要注意领会8086CPU这种工作机制的设计思想。实际上,这种设计思想对于各种处理机来说是普遍的。
11.9 检测比较结果的条件转移指令
下面的内容中我们将学习一些根据cmp指令的比较结果(即,cmp指令执行后,相关标志位的值)进行工作的指令。
它们检测的是哪些标志位呢?
就是被cmp指令影响的那些,表示比较结果的标志位。
这些条件转移指令通常都和cmp相配合使用,就好像 call 和 ret 指令通常相配合使用一样。
这些指令比较常用,它们都很好记忆,它们的第一个字母都是j,表示jump;后面的:
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,bh
jmp short ok
s: add ah,ah
ok: ret
虽然 je 的逻辑含义是“相等则转移”,但它进行的操作是,ZF=1时则转移。
“相等则转移”这种逻辑含义,是通过和 cmp 指令配合使用来体现的,因为是cmp 指令为“ZF=1”赋予了“两数相等”的含义。
至于究竟在je之前使不使用cmp指令,在于我们的安排。
je检测的是ZF位置,不管je 前面是什么指令,只要CPU执行je指令时,ZF=1,那么就会发生转移。
比如:
mov ax,0
add ax,0
je s
inc ax
s: inc ax
执行后,(ax)=1。add ax,0使得ZF=1,所以je指令将进行转移。
可在这个时候发生的转移确不带有“相等则转移”的含义。因为此处的je指令检测到的ZF=1 ,不是由cmp等比较指令设置的,而是由add指令设置的,并不具有“两数相等”的含义。
但无论“ZF=1” 的含义如何,是什么指令设置的,只要是ZF=1,就可以使得je指令发生转移。
CPU提供了cmp指令,也提供了 je 等条件转移指令,如果将它们配合使用,可以实现根据比较结果进行转移的功能。
但这只是“如果”,只是一种合理的建议,和事实上常用的方法。
但究竟是否配合使用它们,完全是你自己的事情。
这就好像,call和ret指令的关系一样。
对于jne、jb、jnb、ja、jna等指令和cmp指令配合使用的思想和je相同,可以自己分析一下。
我们来看一组程序:
data段中的8个字节如下:
data segment
db 8,11,8,1,8,5,63,38
data ends
(1)编程:统计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 start
第二种方案:
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
mov ax, 4c00h
int 21h
code ends
end start
(2)编程:统计data段中数值大于8的字节的个数,用ax保存统计结果。
编程思路:初始设置(ax)=0,然后用循环依次比较每个字节的值,找到一个大于8的数就将ax的值加1。
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 ;如果大于8就将计数值加1
next: inc bx
loop s ;程序执行后: (ax)=3
mov ax, 4c00h
int 21h
code ends
end start
(3)编程:统计data段中数值小于8的字节的个数,用ax保存统计结果。
编程思路:初始设置(ax)=0,然后用循环依次比较每个字节的值,找到一个小于8的数就将ax的值加1。
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进行比较
jnb next ;如果不小于8转到next,继续循环
inc ax ;如果小于8就将计数值加1
next: inc bx
loop s ;程序执行后: (ax)=2
mov ax, 4c00h
int 21h
code ends
end start
上面讲解了根据无符号数的比较结果进行转移的条件转移指令。
根据有符号数的比较结果进行转移的条件转移指令的工作原理和无符号的相同,只是检测了不同的标志位。
我们在这里主要探讨的是cmp、标志寄存器的相关位、条件转移指令三者配合应用的原理,这个原理具有普遍性,而不是逐条讲解条件转移指令。
11.10 DF标志和串传送指令
flag的第10位是DF,方向标志位。
在串处理指令中,控制每次操作后si,di的增减。
DF = 0:每次操作后si,di递增;
DF = 1:每次操作后si,di递减。
格式1: 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递增或递减。
当然,也可以传送一个字: movsw
格式2:movsw
功能:(以字为单位传送)
将 ds:si指向的内存字单元中word送入es:di中,然后根据标志寄存器DF位的值,将si和di递增2或递减2。
movsb和movsw进行的是串传送操作中的一个步骤,一般来说,movsb 和 movsw 都和rep配合使用,格式如下: rep movsb rep的作用是根据cx的值,重复执行后面的串传送指令。
由于每执行一次movsb指令si和di都会递增或递减指向后一个单元或前个单元,则rep movsb就可以循环实现(cx)个字符的传送。
由于flag的DF位决定着串传送指令执行后,si和di改变的方向,所以CPU应该提供相应的指令来对DF位进行设置,从而使程序员能够决定传送的方向。
8086CPU提供下而两条指令对DF位进行设置:
cld指令:将标志寄存器的DF位置0 clear清0
std指令:将标志寄存器的DF位置1 set设置1
我们来看两个程序
编程1:
用串传送指令,将data段中的第一个字符串复制到它后面的空间中。
data segment
db ‘Welcome to masm!’
db 16 dup (0)
data ends
我们分析一下,使用串传送指令进行数据的传送,需要给它提供一些必要的信息,它们是:
① 传送的原始位置:ds:si;
② 传送的目的位置:es:di;
③ 传送的长度:cx;
④ 传送的方向:DF。
在这个问题中,这些信息如下:
① 传送的原始位置:data:0;
② 传送的目的位置:data:16;
③ 传送的长度:16;
④ 传送的方向: 因为正向传送(每次串传送指令执行后,si和di 递增)比较方便,所以设置DF=0。
明确了这些信息之后,我们来编写程序!
assume cs:code
data segment
db 'Welcome to masm!'
db 16 dup (0)
data ends
code segment
start: mov ax,data
mov ds,ax
mov si,0 ;ds:si指向data:0
mov es,ax
mov di,16 ;es:di指向data:16
mov cx,16 ;(cx)=16,rep循环16次
cld ;设置DF=0,正向传送
rep movsb
mov ax, 4c00h
int 21h
code ends
end start
编程2:
用串传送指令,将F000H段中的最后16个字符复制到data段中。
data segment
db 16 dup (0)
data ends
我们还是先来看一下应该为串传送指令提供什么样的信息:
要传送的字符串位于F000H段的最后16个单元中,那么它的最后一个字符的位置:F000:FFFF,是显而易见的。
我们可以将ds:si指向 F000H段的最后一个单元,将es:di指向data段中的最后一个单元,然后逆向(即从高地址向低地址)传送16个字节即可。
相关信息如下:
① 传送的原始位置:F000:FFFF;
② 传送的目的位置:data:15;
③ 传送的长度:16;
④ 传送的方向:因为逆向传送(每次串传送指令执 行后,si 和 di 递减)比较方便,所以设置 DF=1。
程序实现代码!
assume cs:code
data segment
db 16 dup (0)
data ends
code segment
start: mov ax,0f000h
mov ds,ax
mov si,0ffffh ;ds:si指向f000:ffff
mov ax,data
mov es,ax
mov di,15 ;es:di指向data:15
mov cx,16 ;(cx)=16,rep循环16次
std ;设置DF=1,逆向传送
rep movsb
mov ax, 4c00h
int 21h
code ends
end start
11.11 pushf和popf
pushf :将标志寄存器的值压栈;
popf :从栈中弹出数据,送入标志寄存器中。
pushf 和 popf,为直接访问标志寄存器提供了一种方法。