第11章 标志寄存器
目前我们知道的寄存器有:ax,bx,cx,dx,si,di,ip,sp,bp,cs,ss,ds,es这13个寄存器了,而本章我们要学习的便是第14个寄存器也就是最后一共寄存器–flag寄存器
flag寄存器和前面的寄存器都不一样,它是按位存放数据,且每一位都有特定的含义
flag寄存器的结构:
11.1~11.5
这这里一共给我们介绍了ZF,PF,SF,CF,OF标志,总结来说就是:
标志位 名称 范围 特点
ZF 零标志位 结果为0则ZF=1,反之ZF=0
PF 奇偶标志位 结果的二进制位中1的个数为偶数则PF为1,反之为0
SF 符号标志位 有符号数 结果为0则SF=1,反之SF=0
CF 进位标志位 无符号数 运算过程中有进位或借位则CF=1,反之为0
OF 溢出标志位 有符号数 结果溢出的话则OF=1,反之为0
检测点11.1
sub al,al 1 1 0
mov al,1 1 1 0
push ax 1 1 0
pop bx 1 1 0
add al,bl 0 0 0
add al,10 0 1 0
mul al 0 1 0
注意:mov,push,pop等指令不会改变标志寄存器各位的值!
检测点11.2
CF OF SF ZF PF
sub al,al 0 0 0 1 1
mov al,10h 0 0 0 1 1
add al,90h 0 0 1 0 1
mov al,80h 0 0 1 0 1
add al,80h 1 1 0 1 1
mov al,0FCh 1 1 0 1 1
add al,05h 1 0 0 0 0
mov al,7DH 1 0 0 0 0
add al,0Bh 0 1 1 0 1
11.6 adc指令
adc指令和CF有联系:
adc ax,bx --> (ax) = (ax) + (bx) + CF
当上一步的运算结果有进位的时候CF=1,而我们可以利用这个指令实现对更大的数据进行加法运算
add ax,bx
上面的式子等价于下面的
add al,bl
adc ah,bh
大概就是这样,进位之后CF会存储,然后进行更高位运算的时候加上
回答一下p221的问题,能不能用add指令代替4个in指令:
不能,因为程序中用到了CF,使用add指令进行运算会导致CF的值发生变化!(重置为0)
11.7 sbb指令
sbb指令和adc指令很像,不过sbb指令利用的是CF上的借位
sbb ax,bx --> (ax) = (ax) - (bx) - CF
如计算003E1000H-00202000H等同于:
mov bx,1000H
mov ax,003EH
sub bx,2000H
sbb ax,0020H
11.8 cmp指令
cmp指令本质上是进行减法运算,并将结果的正负存储在标志寄存器中,但所得结果不会存储
cmp指令的作用便是比较两个数的大小,例如
jmp ax,bx
执行后ZF=1,说明结果为0,即ax=ax-bx=0,说明ax=bx
对于无符号数,看zf,cf,有符号数看sf,of,zf
我们目前学习cmp指令主要会和下面一些条件转移指令搭配:
je jne jb jnb ja jna
j-->jump
e-->equal
n-->not
a-->above
b-->below
cmp指令和je,ja等条件转移指令一起使用的时候,其实不必每个都去计算标志寄存器的值来判断运算数之间大小(这是计算机的判断方法),我们只需要当成C语言的if语句一样使用就可以了!
检测点11.3
mov ax,0f000h
mov ds,ax
mov bx,0
mov dx,0
mov cx,32
s:
mov al,[bx]
cmp al,32
jb s0
cmp al,128
ja s0
inc dx
s0:
inc bx
loop s
mov ax,0f000h
mov dx,ax
mov bx,0
mov dx,0
mov cx,32
s:
mov al,[bx]
cmp al,32
jna s0
cmp al,128
jnb s0
inc dx
s0:
inc bx
loop s
11.10 DF标志和串传送指令
DF 方向标志位
df=1则si,di递减,df=0则si,di递增
串传送指令:
movsb指令 ,执行后进行以下步骤:
1.mov es:[di],ds:[si]
2.通过DF值来对si和di递增递减
movsb每次复制的是一共byte字节,还有movsw指令,每次复制一个word字
使用串传送指令时会和rep搭配:
rep movsb执行后等同于:
s:movsb
loop s
可以看出loop指令参与运算,说明cx的值决定了rep movsb指令复制的次数
我们前面说到df=1则si和di递减,df=0则si和di递增。那df的值我们该如何控制呢?
cld df位置0
std df位置1
我们举一个简单的例子:
data segment
db 'welcome to masm!'
db 16 dup (0)
data ends
codesg segment
mov ax,data
mov ds,ax
mov si,0
mov es,ax
mov di,16
mov cx,16
cld ;执行cld指令df置0,下一条指令执行时si和di将递增,正向传送
rep movsb
codesg ends
11.11 pushf和popf
push和pop指令将数据压入栈中或出栈,而pushf和popf指令专门用于标志寄存器中的数据出入栈,让我们一起看看检测点11.4
检测点11.4
11.12 标志寄存器在Debug中的表示
实验11
在此附上我写的答案:
codesg segment
begin:mov ax,datasg
mov ds,ax
mov si,0
call letterc
mov ax,4c00h
int 21h
letterc:
cmp ds:[si],61H ;和a作比较
jb ok ;如果小于61则直接跳到标号ok处
cmp ds:[si],86H ;和z作比较
ja ok ;大于86则直接跳到ok处
and ds:[si],11011111B ;到这一步的都是大于等于61且小于等于86H的字符
;也就是a~z
ok: mov cx,ds,[si] ;如果是0,赋给cx,执行jcxz指令将会跳到标号s处直接结束程序
jcxz s
inc si
jmp short letterc ;开始处理下一个字符
s: ret
codesg ends
end begin