汇编语言-标志寄存器
CPU内部的寄存器中,有一个特殊的寄存器,叫标志寄存器,它具有以下三种作用:
- 用来存储相关指令的某些执行结果
- 用来为CPU执行相关指令行为提供行为依据
- 用来控制CPU的相关工作方式
flag和其他寄存器不一样,其他寄存器是用来存放数据的,都是整个寄存器具有一个含义。
而flag寄存器是按位起作用的,也就是说,它的每一位都有专门的含义,记录特定的信息。
标记寄存器内部结构及其功能简介
ZF标志
flag的第6位是ZF,零标志位。它记录相关指令执行后,其结果是否为0。如果结果为0,那么ZF=1,如果结果不为0,那么ZF=0。
代码示范
mov ax,1
sub ax,1
执行后,结果为0,则ZF=1,表示“结果是0”。
注意,在8086CPU的指令集中,有的指令的执行是影响标志寄存器的,比如:add、sub、mul、div、inc、or、and等,它们大都是运算指令(进行逻辑或自述运算);有的指令的执行对标志寄存器没有影响,比如:mov、push、pop等,它们大都是传送指令。
PF标志
flag的第2位是PF,奇偶标志位。它记录相关指令执行后,其结果的所有二进制位中1的个数是否为偶数。如果1的个数为偶数,PF=1,如果为奇数,那么PF=0。
代码示范
mov al,1
add al,10
执行后,结果为00001011B,其中有3(奇数)个1,则PF=0。
SF标志
flag的第7位是SF,符号标志位。它记录相关指令执行后,其结果是否为负。如果结果为负,SF=1,如果非负,SF=0。
代码示范
mov al,10000001B
add al,1
执行后,结果为10000010B,符号位为1,则SF=1。
CF标志
flag的第0位是CF,进位标志位。一般情况下,在进行了无符号运算的时候,它记录了运算结果的最高有效位向更高位的进位值,或从更高位的借位值。
代码示范
mov al,98H
add al,al ;执行后,(al) = 30H, CF=1, CF记录了从最高有效位向更高位的进位值
add al,al ;执行后,(al) = 60H, CF=0, CF记录了从最高有效位向更高位的进位值
mov al,97H
sub al,98H ;执行后,(al) = FFH, CF=1, CF记录了向更高位的借位值
sub al,al ;执行后,(al)=0,CF=0,CF记录了向更高位的借位值
OF标志
flag的第11位是OF,溢出标志位。一般情况下,OF记录了有符号数运算的结果是否发生了溢出。如果发生溢出,OF=1,如果没有,OF=0。
一定要注意CF和OF的区别:CF是对无符号数运算有意义的标志位,而OF是对有符号数运算有意义的标志位。
mov al,98
add al,99
add指令执行后:CF=0,OF=1。
adc指令
adc 操作对象1,操作对象2
功能:
操作对象1=操作对象1+操作对象2+CF
adc是带进位的加法指令,它利用了CF位上记录的进位值。
代码示范
mov ax,2
mov bx,1
sub bx,ax
adc ax,1
执行后,(ax) = 4。adc执行时,相当于计算:(ax) + 1 + CF=2+1+1=4。
sbb指令
使用方法和adc指令相似
cmp指令
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。
检测比较结果的条件转移指令
“转移”指的是它能够修改IP,而“条件”指的是它可以根据某种条件,决定是否修改IP。
比如:jcxz就是一个条件转移指令,它可以检测cx中的数值,如果(cx)=0,就修改IP,否则什么也不做。
所有条件转移指令的转移位移都是[-128~127]。
除了jcxz之外,CPU还提供了其他条件转移指令,大多数条件转移指令都检测标志寄存器的相关标志位,根据检测的结果来决定是否修改IP。
它们检测的是哪些标志位呢?就是被cmp指令影响的那些,表示比较结果的标志位。这些条件转移指令通常都和cmp相配合使用,就好像call和ret指令通常相配合使用一样。
因为cmp指令可以同时进行两种比较,无符号数比较和有符号数比较,所以根据cmp指令的比较结果进行转移的指令也分为两种,即:
- 根据无符号数的比较结果进行转移的条件转移指令,它们检测ZF、CF的值;
- 和根据有符号数的比较结果进行了转移的条件转移指令,它们检测SF、OF和ZF的值。
指令介绍:
代码示范
如果(ah)=(bh)则(ah)=(ah)+(ah),否则(ah)=(ah)+(bh)。
cmp ah,bh
je s
add ah,bh
jmp short ok
s:add ah,ah
ok:…
上面的程序执行时,如果(ah)=(bh),则cmp ah,bh 使ZF=1,而je检测ZF是否为1,如果为1,将转移到标号s处执行指令 add ah,ah。这也可以说,cmp比较ah、bh后所得到的相等的结果使得je指令进行转移。从而很好地体现了je指令的逻辑含义,相等则转移。
虽然je的逻辑含义是“相等则转移”,但它实际进行的操作是,ZF=1时则转移。
“相等则转移”这种逻辑含义,是通过和cmp指令配合使用来体现的,因为cmp指令为“ZF=1”赋予了“两数相等”的含义。
至于究竟在je之前使不使用cmp指令,在于我们在安排je检测的是ZF位置,不管je前面是什么指令,只要CPU执行je指令时,ZF=1,那么就会发生转移。
实例介绍
程序功能:将包含任意字符,以0结尾的字符串中的小写字母转变成大写字母
assume cs:code
data segment
db 'sfsd;++dfasd"fdsafsd_fdfdfdIIIIss',0
data ends
code segment
start: mov ax,data
mov ds,ax
mov si,0
call letterc
mov ax,4c00H
int 21
letterc:
push ax
push ds
push si
s:
mov al,ds:[si]
mov ah,'a'
cmp al,ah
jb next
mov ah,'z'
cmp al,ah
ja next
change:
and al,11011111B
mov ds:[si],al
next:
inc si
loop s
pop si
pop ds
pop ax
code ends
end start
效果图:
DF标志和串传送指令
DF标记
flag的第10位是DF,Direction Flag,方向标志位。
在串处理指令中,控制每操作后si,di的增减。
DF=0,每次操作后si,di递增;DF=1,每次操作后si,di递减。
DF相关指令
8086CPU提供下面两条指令对DF位进行设置:
cld指令:将标志寄存器的DF位置0;
std指令:将标志寄存器的DF位置1。
串传送指令
格式:movsb
功能介绍
功能:执行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的功能如下:
mov es:[di],byte ptr ds:[si] ;8086CPU并不支持这样的指令,这里只是个描述。
如果DF=0:
inc si
inc di
如果DF=1:
dec si
dec di
rep指令
rep的作用是根据cx的值,重复执行后面的串传送指令
movsb和movsw都和rep配合使用,格式如下:
mov cx,100
rep movsb
用汇编语法来描述rep movsb的功能就是:
mov cx,100
s:movsb
loop s
pushf和popf
pushf的功能是将标志寄存器的值压栈,而popf是从栈中弹出数据,送入标志寄存器中。
pushf和popf,为直接访问标志寄存器提供了一种方法。