汇编语言(王爽)第十一章

第十一章

8086CPU的标志寄存器(简称flag)有16位,其中存储的信息称为程序状态字(PSW),其作用主要有3个

1、存储相关指令的某些存储结果

2、为CPU执行相关指令提供行为依据

3、控制CPU 的相关工作方式

其他寄存器存放数据时,是整个寄存器具有一个含义,而flag寄存器按位起作用,即每一位都有专门的含义,下图为8086CPU的flag寄存器结构

在这里插入图片描述
某些空白位不具有任何含义

11.1 ZF标志

flag的第6位,零标志位,相关指令执行后,若结果为0,zf=1,否则zf=0

在8086CPU的指令集中,有些指令的执行影响标志寄存器,如add、sub等,而mov、push、pop等即转移指令则没有影响

mov ax,1
and ax,0	; 执行后zf=1

11.2 PF标志

flag的第2位,奇偶标志位,相关指令执行后,其结果的所有bit位中1的个数若为偶数,pf=1,否则pf=0

mov al,1
add al,10		; 结果为00001011b,其中有3个1,则pf=0

sub al,al		; 结果为00000000b,0个1,pf=1

11.3 SF标志

flag的第7位,符号标志位,相关指令执行后,如果结果为负,sf=1,否则sf=0

SF标志,是CPU对有符号数运算的记录,如果我们把数据当作无符号数来运算,则SF的值没有意义,虽然相关的指令势必会影响它的值

某些指令会影响标志寄存器的多个标记位,如

sub al,al		; ZF=1 PF=1 SF=0

11.4 CF标志

flag的第0位是CF,进位标志位,在进行无符号运算时,记录了运算结果的最高有效位向更高位的进位值,或从更高位的借位值

在这里插入图片描述

两个数据相加时,如98H+98H,将产生进位,这个进位值在8位数中无法保存,但是会由CF位来记录这个进位值

mov al,98H
add al,al		; 执行后,(al)=30H,CF=1
add al,al		; 执行后,(al)=60H,CF=0

当两个数据做减法的时候,有可能向更高位借位,如97H-98H,借位后,相当于计算197H-98H,CF位记录这个借位值

mov al,97H
sub al,98H		; 执行后,(al)=FFH,CF=1
sub al,al		; 执行后,(al)=0,CF=0

11.5 OF标志

flag的第11位是OF,溢出标志位,OF记录有符号数运算的结果是否发生了溢出,如果发生溢出,OF=1,否则OF=0

注意CF是对无符号数运算有意义的标志位

mov al,98		; CF=0 OF=1
add al,99		; 看作无符号数运算,没有产生进位
				; 看作有符号数,结果197超出了最大8位有符号数127,有溢出
		
mov al,0F0H		; CF=1 OF=1
add al,88H		; 看作有符号数,按照十进制结果-136,超过-128,溢出

mov al,0F0H		; CF=1 0F=0
add al,88H		

11.6 adc指令

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

格式 adc 操作对象1,操作对象2

mov ax,2
mov bx,1
sub bx,ax	; CF=1
adc ax,1	; (ax)=4 (ax)+1+CF=2+1+1=4

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

计算1EF000H+201000H,结果放在ax(高16位)和bx(低16位)

两个数都大于16位,不能直接用add

mov ax,001EH
mov bx,0F000H
add bx,1000H
adc ax,0020H		; 两个数据的低16位运算结束后会设置CF的值为0或1

处理更大的数据也可以

计算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位数据进行相加

ds:si指向存储第一个数的内存空间,ds:si指向存储第二个数的内存空间,由低地址单元到高地址单元依次存放128位数据由低到高的各个字,运算结果存储在第一个数的存储空间中

add128:		push ax			; 子程序中用到的寄存器可能对下面程序有影响
			push cx			; 用栈暂存
			push si
			push di
			
			sub ax,ax		; 将CF设置为0
			
			mov cx,8
	s:		mov ax,[si]
			adc ax,[di]
			mov [si],ax
			
			inc si			; 不能改成add si,2,会产生进位影响CF的值
			inc si
			inc di
			inc di
			
			loop s
			
			pop di			; 注意出栈顺序
			pop si
			pop cx
			pop ax
			
			ret

关于inc指令:将指定的操作数的内容加一,再将结果送回到该操作数

inc指令影响SF、AF、ZF、PF、OF标志位,但不影响CF标志位

对于内存单元,要指明是字节还是字操作

11.7 sbb指令

带借位减法指令,利用CF位上记录的借位值

sbb 操作对象1,操作对象2

功能:操作对象1=操作对象1-操作对象2-CF

利用sbb指令可以对任意大的数据进行减法运算

计算003E1000H-00202000H,结果存放再ax,bx中

mov bx,1000H
mov ax,003EH
sub bx,2000H
sbb ax,0020H

11.8 cmp指令

比较指令,功能相当于减法指令,但不保存结果 ,对标志寄存器产生影响

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

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

cmp ax,ax	; 结果为0,但不在ax中保存
			; zf=1 pf=1 sf=0 cf=0 of=0

可以根据运算后标志寄存器的结果来得出两个操作数的大小

对于cmp,也有无符号和有符号数两种理解

对于无符号运算,根据是否借位以及结果是否为0判断大小

对于有符号数的运算,单凭一个标志无法判断两个操作数的大小,因为存在溢出

如(ah)=22H,(bh)=0A0H,则(ah)-(bh)=34-(-96)=82H,82H是-126的补码,sf=1,但不能说明(ah)<(bh)

应该在考察sf的同时考察of

以cmp ah,bh为例

1、sf=1,of=0

没有溢出,实际结果为负,所以(ah)<(bh)

2、sf=1,of=1

因为溢出而导致结果为负,所以(ah)>(bh)

3、sf=0,of=1

因为溢出而导致结果为正,说明(ah)<(bh)

4、sf=0,of=0

没有溢出,sf=0表示结果非负,所以(ah)>=(bh)

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

jcxz就是一种条件转移指令

所有条件转移指令的转移位移都是[-128,127]

大多数条件转移指令都检测标志寄存器上的相关标志位(被cmp影响的那些),来决定是否修改IP,这些条件转移指令通常都和cmp相配合使用

根据无符号和有符号数有两种检测方法

根据无符号数比较结果进行转移的条件转移指令(检测zf和cf)

指令 含义 检测的标志位
je 等於则转移 zf=1
jne 不等於则转移 zf=0
jb 低於则转移 cf=1
jnb 不低於则转移 cf=0
ja 高於则转移 cf=0 and zf=0
jna 不高於则转移 cf=1 or zf=1

记忆方法:j:jmp e:equal ne:not equal b:below nb:not below

a:above na:not above

编程实现如下功能:如果(ah)=(bh)则(ah)=(ah)+(ah),否则(ah)=(ah)+(bh)

	cmp ah,bh
	je s			; 检测zf是否为1
	add ah,bh
	jmp short ok
 s:	add ah,ah
ok:	……

je之前不一定要使用cmp,只关心zf的值

    mov ax,0
    add ax,0	; 执行后zf=1
    je s
    inc ax
s:	inc ax

cmp和je等指令配合使用类似IF语句

data segment
	db 8,11,8,1,8,5,63,54
data ends

编程,统计data段中数值为8的字节的个数,用ax保存统计结果

        mov ax,data
        mov ds,ax

        mov bx,0			; ds:bx指向第一个字节
        mov ax,0			; 初始化累加器

        mov cx,8
   s:	cmp byte ptr [bx],8
        jne next
        inc ax
next:	inc bx
		loop s
		
; 另一种写法
		mov ax,data
        mov ds,ax

        mov bx,0			; ds:bx指向第一个字节
        mov ax,0			; 初始化累加器

        mov cx,8
   s:	cmp byte ptr [bx],8
        je ok
        jmp short next
        
  ok:	inc ax
next:	inc bx
		loop s

有符号数的比较原理相同

11.10 DF标志和串传送指令

flag的第10位,方向标志位,在串处理指令中,控制每次操作后si、di的增减

df=0 每次操作后si、di递增

df=1 每次操作后si、di递减

格式:movsb

功能:用汇编语言描述

mov es:[di],byte ptr ds:[si] ;只是一个描述

如果df=0 inc si inc di

如果df=1 dec si dec di

将ds:si指向的内存单元中的字节送入es:di中,然后根据df的值进行si和di的递增或递减

也可以传送一个字 movsw 这种情况下,si和di每次加/减2

一般来说,movsb和movsw都和rep配合使用

rep movsb

用汇编语法解释

s: movsb

​ loop s

可见,rep根据cx的值,重复执行后面的串传送指令

同理也可以使用rep movsw

CPU提供相应的指令对df进行设置,从而能决定传送的方向

8086CPU提供两条指令

cld:将df置0

std:将df置1

编程,将data段中的第一个字符串赋值到后面的空间中

data segment
	db 'Welcome to masm!'
	db 16 dup (0)
data ends

分析可知cx=16 df=0

mov ax,data
mov ds,ax
mov si,0

mov es,ax
mov di,16

mov cx,16
cld		
rep movsb

编程,将F000H段中最后16个字符复制到data段中

data segemnt
	db 16 dup (0)
data ends

因为是最后16个字符,因此逆序输入更好

mov ax,0f00h
mov ds,ax
mov si,0ffffh

mov ax,data
mov es,ax
mov di,15		; 指向data段最后一个字节

mov cx,16
std
rep movsb

11.11 pushf和popf

pushf是将标志寄存器的值压栈,popf从栈中弹出数据,送入标志寄存器中

下面的程序执行后,(ax)=?

mov ax,0
push ax
popf				; 使得我们学到过的标志位为0
mov ax,0fff0h	
add ax,0010h		; 标志位的值发生改变
pushf
pop ax				; 标志寄存器的值赋给ax ax=000000**010*0101b
					; 用*屏蔽没学过的标志位
and al,11000101b	; 这两条将没学过的标志位置0,学过的标志位的值不变	
and ah,00001000b	; ah=45h al=0h

11.12 标志寄存器在Debug中的表示

在这里插入图片描述

标志 值为1的标记 值为0的标记
OF OV NV
SF NG PL
ZF ZR NZ
PF PE PO
CF CY NC
DF DN UP
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章