Advertisement

王爽 《汇编语言》 读书笔记 十一 标志寄存器

阅读量:

第十一章 标志寄存器

标志寄存器

1)用来存储相关指令的某些执行结果

2)用来为cpu执行的相关指令提供行为依据

3)用来控制cpu的相关工作方式

标志寄存器flag存储程序状态字(PSW)

8086点flag寄存器各位有不同的含义

CF,PF,AF,ZF,SF,TF,IF,DF,OF

11.1 ZF标志

flag的第六位是ZF,0标志位。记录相关指令执行后,其结果是否为0.如果为0则ZF = 1

例如

mov ax, 1

sub ax, 1

执行以后结果为0 zf = 1

mov ax, 2

sub ax, 1

执行后结果不为0,zf = 0

有些指令会影响zf的比如add, sub, mil, div, inc, or, and等运算指令

mov, push, pop对ZF没有影响不会修改其值,保留原值

11.2 PF标志

奇偶标志位,表示进行相关运算以后,其结果所含的bit为重1的个数是否为偶数,

如果1的个数为偶数则PF=1,如果为奇数,则PF=0

mov al, 1

add al, 10

执行结果为00001011B 含有奇数个1 PF = 0

mov al, 1

or al, 2

执行结果为00000011B 含有偶数个1 则PF = 1

11.3 SF标志

表明相关指令执行后,结果是否为负。如果为负sf=1,如果非负,sf=0

有些指令会影响flag的多个标记为

例如sub al, al

ZF, PF, SF都要收到影响 分别是 1, 1, 0

11.4 CF标志

进行无符号运算的时候,最高位是否进位,或者从更高位借位。

mov al, 98h

add al, all 执行后 al=30h, cf=1,cf记录了从最高有效位向更高位的进位值。

add al, al 执行后 al = 60h, cf = 0

当两个数执行减法的时候,有可能向更高位借位。比如,两个8位数据:97h - 98h CF也记录了这个借位值。

mov al, 97h

sub al, 98h ; 执行后al = ffh, CF = 1 ,CF记录了向更高位借位值

sub al, al ;执行后al=0, cf=0

11.5 OF标志

记录了有符号运算的结果是否发生了溢出。如果发生了溢出则OF=1 如果没有OF = 0

CF是对无符号数有意义的标志位,而OF是对有符号数有意义的标志位(判断两个操作数的符号,和结果的符号。如果两个操作数符号不同则OF必位0.如果结果的符号和两个操作数的符号不同则结果必为1)

SF记录结果的符号

11.6 adc指令

带进位的加法指令,利用了CF位上记录的进位值(可以扩展成32位,64位加法使用)

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

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

比如 adc ax, bx (ax) = (ax) + (bx) + CF

mov ax, 2

mov bx, 1

sub bx, ax ; bx = 0ffh, cf = 1

add ax, 1 ; ax = 2 + 1 + 1(CF) = 4

mov ax, 1

add ax, ax ; ax = 2, cf = 0

add ax, 3 ; ax = 5 ,cf = 0

mov al, 98H

add al, al ; al = 30h, cf = 1, of = 1

add al, 3 ; al = 30h+3+1 = 34h

以下指令具有和add ax, bx相同的效果

add al, bl

add ah, bh

例如计算 1ef000h + 201000h 结果放在ax(高16bit)和bx(低16bit)中

复制代码
    		mov ax, 001eh
    		mov bx, 0f000h
    		add bx, 1000h
    		adc ax, 0020h

adc也可能产生进位CF

计算 1E F000 1000 H + 20 10000 1EF0H 结果放在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指向存储第二个数的内存空间

复制代码
    add128:	push ax
    		push cx
    		push si
    		push di
    		
    		sub ax, ax	; set CF to Zero
    		
    		mov cx, 8
    	s:	mov ax, [si]
    		adc	ax, [di]
    		mov [si], ax
    		inc si
    		inc si
    		inc di
    		inc di
    		loop s
    		
    		pop di
    		pop si
    		pop cx
    		pop ax
    		ret

inc 和 loop不影响标志位CF

11.7 sbb指令

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

指令格式:sbb操作对象1, 操作对象2

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

比如sbb ax, bx ; (ax) = (ax) - (bx) - CF

例如计算003E 1000H - 0020 2000H

mov bx, 1000H

mov ax, 003eH

sub bx, 2000H

sub ax, 0020H

11.8 cmp指令

cmp是比较指令,相当于减法指令,只是并不保存结果。cmp指令执行以后,将对标志寄存器产生影响。

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

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

例如 cmp ax, ax ; Zf = 1, pf = 1, sf = 0, cf = 0, of = 0

下面指令:

mov ax, 8

mov bx, 3

cmp ax, bx ; zf = 0, pf =1, sf = 0, cf = 0, of = 0

例如 cmp ax, bx

如果 ax = bx, 则 ax - bx = 0; zf = 1

如果 ax != bx, 则 ax - bx != 0, 所以 zf = 0

如果ax < bx, 则 ax - bx < 0, 所以 cf = 1

如果ax >= bx, 则 ax - bx >=0, 所以 cf = 0

如果ax > bx, 则 ax- bx >0, cf = 0且 zf = 0

如果ax<= bx, 则 ax - bx <=0, cf = 1 或 zf = 1

执行cmp的时候:也可以表示进行无符号运算和 进行有符号运算

如果利用cmp进行有符号数的比较

cmp ah, bh

如果 ah == bh, 则 ah - bh = 0, 所以 zf = 1

如果 ah != bh, 则 ah - bh != 0, 所以 zf = 0

如果ah < bh, ah - bh <0 sf = 1

如果 ah = 22h, bh = 0a0h(-96)

ah - bh = 34 - (-96) = 82H (-126) < 0 但是实际上 ah > bh

如果运算结果发生了溢出则所得到的结果sf就不能说明问题

总结cmp ah, bh sf of是如何来说明比较结果的。

当of = 0 sf = 1 则 ah < bh

当of=0, sf = 0 则 ah >= bh

当of=1 sf = 1,因为溢出导致实际结果位负,那么逻辑上的真正结果必然为正。因此 ah > bh

当of =1, sf = 0,因为溢出导致了实际结果为正,那么逻辑上真正的结果必然为负,因此 ah < bh

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

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

常见的无符号数的比较结果进行转移的条件转移指令(zf cf)

je 等于则转移 zf = 1

jne 不等于则转移 zf = 0

jb 低于则转移 cf = 1 (below)

jnb 不低于则转移 cf = 0

ja 高于则转移 cf = 0 且 zf=0 (above)

jna 不高于则转移 cf = 1 或 zf = 1

编程实现如下功能

如果 ah == bh 则 ah = ah + ah

否则 ah = ah + bh

复制代码
    		cmp ah, bh
    		je s
    		add ah, bh
    		jmp short OK
    	s:	add ah, ah	
    	OK:	;...

在代码设计的时候可以将 cmp 和 jxx 联合一起使用相当于高级语言的if语句

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

复制代码
    assume cs:code
    
    data segment
    	db 8, 11, 8, 1, 8, 5, 63, 38
    data ends
    
    stack segment
    	db 32 dup (0)
    stack ends
    
    code segment
    start:		mov ax, data
    			mov ds, ax
    		
    			mov ax, stack
    			mov ss, ax
    			mov sp, 20h
    		
    			mov ax, 0
    			mov si, 0
    			mov cx, 8
    		
    	s:		cmp byte ptr ds:[si], 8
    			je cnt
    			jmp short next
    	cnt:	inc ax
    	
    	next: 	inc si
    			loop s
    		
    			mov ax, 4c00h
    			int 21h
    
    code ends
    end start

运行结果

2)编程,计算data段中数值大于8段字节的个数,用ax保存统计的结果

复制代码
    assume cs:code
    
    data segment
    	db 8, 11, 8, 1, 8, 5, 63, 38
    data ends
    
    stack segment
    	db 32 dup (0)
    stack ends
    
    code segment
    start:		mov ax, data
    			mov ds, ax
    		
    			mov ax, stack
    			mov ss, ax
    			mov sp, 20h
    		
    			mov ax, 0
    			mov si, 0
    			mov cx, 8
    		
    	s:		cmp byte ptr ds:[si], 8
    			jna next
    			inc ax
    	next: 	inc si
    			loop s
    		
    			mov ax, 4c00h
    			int 21h
    
    code ends
    end start

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

复制代码
    assume cs:code
    
    data segment
    	db 8, 11, 8, 1, 8, 5, 63, 38
    data ends
    
    stack segment
    	db 32 dup (0)
    stack ends
    
    code segment
    start:		mov ax, data
    			mov ds, ax
    		
    			mov ax, stack
    			mov ss, ax
    			mov sp, 20h
    		
    			mov ax, 0
    			mov si, 0
    			mov cx, 8
    		
    	s:		cmp byte ptr ds:[si], 8
    			jnb next
    			inc ax
    	next: 	inc si
    			loop s
    		
    			mov ax, 4c00h
    			int 21h
    
    code ends
    end start

11.10 DF标志和串传送指令

DF方向标志位,在串处理中,控制每次操作后si,di的递减。

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

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

movsb串传送指令

功能:执行movsb指令相当于以下几个步骤

1)((es)*16 + (di)) = ((ds)*16+(si)) 把ds:si的值传送到es:di

  1. 如果df=0, 则 (si)=(si)+1 , (di) = (di) + 1

反之 (si) = (si) - 1, (di) = (di) -1

也可以传送一个字

格式:movsw

将ds:si指向的内存字单元传入es:di中,然后根据标志寄存器将si和di 递增或递减2

movsb 和 movsw 要配合rep (还有一个传送双字的movsd)

rep movsb

相当于 s: movsb

loop s

也就是根据cx的值来执行循环 rep movsb 传送cx个字节

同理也可以传送 rep movsw 和 (rep movsd)

相当于 s:movsw

loop s

cld指令,可以将df设置位0 (递增)

std指令,可以将df设置位1 (递减)

movsX 系的指令需要用到的寄存器

DS,ES,SI,DI,CX(配合REP) 和标志寄存器的DF

1)将data段的字符传送到他后面的空间中

复制代码
    assume cs:code
    
    data segment
    	db 'Welcome to masm!'
    	db 16 dup (0)
    data ends
    
    stack segment
    	db 32 dup (0)
    stack ends
    
    code segment
    start:		mov ax, data
    			mov ds, ax
    			mov es, ax
    		
    			mov ax, stack
    			mov ss, ax
    			mov sp, 20h
    		
    			mov si, 0
    			mov di, 10h
    			mov cx, 10h
    			cld
    			rep movsb
    				
    			mov ax, 4c00h
    			int 21h
    
    code ends
    end start

执行结果

2)编程,用串传送指令,将F000H段中的最后16个字符复制到data段中。

复制代码
    assume cs:code
    
    data segment
    	db 16 dup (0)
    data ends
    
    stack segment
    	db 32 dup (0)
    stack ends
    
    code segment
    start:		mov ax, 0f00h
    			mov ds, ax
    			
    			mov ax, data
    			mov es, ax
    		
    			mov ax, stack
    			mov ss, ax
    			mov sp, 20h
    		
    			mov si, 0fffh
    			mov di, 15
    			mov cx, 16
    			std
    			rep movsb
    				
    			mov ax, 4c00h
    			int 21h
    
    code ends
    end start

运行结果

11.11 pushf和popf

pushf将标志寄存器压栈

popf将标志寄存器从栈中弹出

提供了一种间接访问标志寄存器的方法。

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

NV UP EI PL NZ NA PO NC

OF DF SF ZF PF CF

值为1 值为0

of OV NV

sf NG PL

zf ZR NZ

pf PE PO

cf CY NC

df DN UP

实验11 编写子程序

将包含人意字符,以0结尾的字符串中的小鞋字符转变成大写字母

名称:letterc

功能:将以0结尾的字符串中的小鞋字母转变成大写字母

参数:ds:di指向字符串首地址

复制代码
    assume cs:code
    
    datasg segment
    	db "Beginner's All-purpose Symbolic Instruction Code.", 0
    datasg ends
    
    stack segment
    	db 64 dup (0)
    stack ends
    
    code segment
    begin:		mov ax, datasg
    			mov ds, ax
    			
    			mov ax, stack
    			mov ss, ax
    			mov sp, 40h
    			
    			mov si, 0
    			
    			call letterc
    			
    			
    			mov ax, 4c00h
    			int 21h
    ;*****************************************************************************
    ; sub procedure letterc
    ;*****************************************************************************				
    letterc:	push si
    			push ax
    			pushf
    			
    	lts:	mov al, ds:[si]
    			cmp al, 0
    			je letterc_ok	; meet the end of the string '\0'
    			cmp al, 'a'
    			jb next
    			cmp al, 'z'
    			ja next
    			and al, 11011111B	; conver to upper case
    			mov ds:[si], al		; apply change to data
    	next:	inc si
    			jmp short lts		
    			
    letterc_ok:	popf
    			pop ax
    			pop si
    			ret
    code ends
    
    end begin

运行结果

将此实验和上一个单元中的show_str等例子集成

复制代码
    assume cs:code
    
    datasg segment
    	db "Beginner's All-purpose Symbolic Instruction Code.", 0
    datasg ends
    
    stack segment
    	db 64 dup (0)
    stack ends
    
    code segment
    begin:		mov ax, datasg
    			mov ds, ax
    			
    			mov ax, stack
    			mov ss, ax
    			mov sp, 40h
    			
    			mov si, 0
    			
    			call cls
    			
    			mov dh, 2			; line 2
    			mov dl, 0			; point the column 0
    			mov cl, 7			; 0 000 0 111B = 7 set the bkcolor(black) color(white)
    			mov si, 0			; point to the start of the string
    			call show_str		
    			call letterc
    			
    			mov dh, 3
    			call show_str
    			
    			
    			mov ax, 4c00h
    			int 21h
    ;*****************************************************************************
    ; sub procedure letterc
    ;*****************************************************************************				
    letterc:	push si
    			push ax
    			pushf
    			
    	lts:	mov al, ds:[si]
    			cmp al, 0
    			je letterc_ok	; meet the end of the string '\0'
    			cmp al, 'a'
    			jb next
    			cmp al, 'z'
    			ja next
    			and al, 11011111B	; conver to upper case
    			mov ds:[si], al		; apply change to data
    	next:	inc si
    			jmp short lts		
    			
    letterc_ok:	popf
    			pop ax
    			pop si
    			ret
    ;*****************************************************************************
    ; sub memset16
    ; di:si point to the start of the memory
    ; cx is the length of the memory
    ; ax is the value of the memory
    ;*****************************************************************************	
    memset16:		push si
    				push ax
    				push cx
    				
    				jcxz memret16		; if the cx is equal to zero just return
    	setvalue16:	mov ds:[si], ax
    				add si, 2
    				loop setvalue16
    		
    	memret16:	pop cx
    				pop ax
    				pop si
    				ret
    
    ;*****************************************************************************
    ; sub show_str
    ;*****************************************************************************	
    show_str:	push ax
    			push bx
    			push cx
    			push dx
    			push bp
    			push si
    			push di
    			push es
    			
    			mov ax, 0b800h	; load the first address to vram
    			mov es, ax
    			
    			mov bp, 0		; reset bp to 0
    			mov ax, 0		; reset al ah
    			mov al, dh
    			mov bl, 0a0h
    			mul bl			; dh x 160 = line offset
    			add bp, ax		; add the line offset
    			
    			mov ax, 0		; reset al ah
    			mov al, dl
    			mov bl, 2		
    			mul bl			; dl x 2 = column offset
    			add bp, ax		; add the column offset
    			
    			mov di, 0
    			mov ah, cl		; store the color info
    	change:	mov cl, [si]
    			mov ch, 0
    			jcxz ok			; check whether pointer to '\0'
    			mov al, cl		; store the char
    			mov es:[bp][di], ax ;
    			inc si
    			add di, 2
    			jmp short change
    					
    		ok:	pop es
    			pop di
    			pop si
    			pop bp
    			pop dx
    			pop cx
    			pop bx
    			pop ax
    			ret
    
    ;*****************************************************************************
    ; sub cls.
    ; clean the screen
    ;*****************************************************************************				
    cls:	push ds				; clean the screen
    		push ax
    		push cx
    		push si
    		
    		mov cx, 690h
    		mov ax, 0b800h
    		mov ds, ax
    		mov al, ' '
    		mov ah, 7
    		mov si, 0
    		call memset16
    		
    		pop si
    		pop cx
    		pop ax
    		pop ds
    		ret
    code ends
    
    end begin

运行结果

全部评论 (0)

还没有任何评论哟~