(二十六)标志寄存器(flag)--汇编笔记

汇编语言

Posted by YiMiTuMi on April 17, 2020

标志寄存器(flag)

CPU内部的寄存器中,有一种特殊的寄存器(对于不同的处理机,个数和结构都有可能不同)具有以下3种作用。

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

 2)用来为CPU执行相关指令提供行为依据。

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

这种特殊的寄存器在8086CPU中,被称为标志寄存器。8086的标志寄存器有16位,其中状态的信息通常被称为程序状态字(PSW)。

标志位寄存器简称flag。

flag和其他寄存器不一样,其他寄存器都是用来存放数据的,都是整个寄存器具有一个含义。而flag寄存器是按位起作用的,也就是说,它的每一位都用专门的含义,记录特定的信息。

8086CPU的flag寄存器的结构:

15  14  13  12  11  10  09  08  07  06  05  04  03  02  01  00

                OF  DF  IF  TF  SF  ZF      AF      PF      CF

ZF标志(flag第6位,0标志位)

flag的第6位是ZF位, 零标志位。它记录相关指令执行后,其结果是否为0。如果结果为0,那么zf = 1,如果结果不为0,那么zf = 0。

例:

mov ax, 1
sub ax, 1

执行后,结果为0,则zf = 1。

mov ax, 2
sub ax, 1

执行后,结果为1,则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等,它们大都是传送指令。

PF标志(flag第2位,奇偶标志位)

flag的第2位是PF,奇偶标志位。他记录相关指令执行后,其结果的所有bit位中1的个数是否为偶数。如果1是偶数,pf = 1,如果为奇数,那么pf = 0。

例:

mov al, 1
add al, 10

执行后,结果为00001011B,其中有3个1,则pf = 0;

mov al, 1
or al, 2

执行后,结果为00000011B,其中有2个1,则pf = 1;

mov al, 1
sub al, al

执行后,结果为00000000B,其中有0个1,则pf = 1;

SF标志(flag第7位,记录结果是否为负)

flag的第7位是SF,符号标志位。它记录相关指令执行后,其结果是否为负。如果结果为负,sf = 1;如果非负,sf = 0。

计算机中通常用补码来表示有符号数据。计算机中的一个数据可以看作是有符数,也可以看成是无符号数。比如:

00000001B  可以看作为无符号数1,或有符号数 +1

10000001B  可以看作为无符号数129,也可以看作有符号数 -127

对于同一个二进制数据,计算机可以将它当作无符号数据来运算,也可以当作有符号数据来运算。

例:

mov al, 10000001B

add al, 1

结果:(al)= 10000010B

将add指令进行的运算当作无符号数的运算,那么add指令相当于计算129 + 1 = 130(10000010B)

将add指令进行的运算当作有符号数的运算,那么add指令相当于计算-127 + 1 = -126(10000010B)

CPU在执行add等指令的时候,就已经包含了两种含义,也将得到同一种信息来记录的两种结果,关键在于我们的程序需要哪一种结果。

SF标志,就是CPU对有符号数运算结果的一种记录,他记录数据的正负。

当我们将数据当作有符号数来运算的时候,可以通过他来得知结果的正负。

当我们将数据当作无符号数来运算,SF的值则没有意义,虽然相关的指令会改变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: 1 , PF = 1 , SF = 0

CF标志(flag的第0位,进位、借位标志位,对无符号数有意义)

flag的第0位是CF,进位、借位标志位。

在进行无符号数运算的时候,它记录了运算结果的最高有效位向更高位的进位值,或从更高位的借位值。

对于位数为N的无符号数来说,其对应的二进制信息的最高为,即第N-1位,就是他个最高有效位,而假象存在的第N位,就是相对于最高有效位的更高位。

当两个数据相加的时候,有可能产生从最高有效位向更高位的进位。例如,两个8位数据:98H + 98H,将产生进位。由于这个进位值在8位数中无法保存,我们会丢弃这个进位值。其实CPU在运算的时候,并不丢弃这个进位值,而是记录在一个特殊的寄存器的某一位上。8086CPU就用CF位来记录这个进位值。

例:

mov al, 98H

add al, al //执行后:(al)= 30H, CF = 1,CF记录了从最高有效位向更高位的进位值。

add al, al //执行后:(al)= 60H, CF = 0,CF记录了从最高有效位向更高位的进位值。

当两个数据做减法的时候,有可能向更高位借位。例如,8为数据:97H - 98H,将产生借位,借位后,相当于计算197H - 98H。而flag的CF位也可以用来记录这个借位值。

例:

mov al, 97H

sub al, 98H //执行后:(al)= FFH, CF = 1,CF记录了向更高位的借位值

sub al, al  //执行后:(al)= 0H, CF = 0,CF记录了向更高位的借位值

OF标志位(第11位,溢出标志位,对有符号数有意义)

在进行有符号数运算的时候,如结果超出了机器所能表示的范围称为溢出。

对于8位的有符号数据,机器所能表示的范围就是-128 ~ 127。

对于16位的有符号数据,机器所能表示的范围就是-32768 ~ 32767

如果运算结果超出了机器所能表达的范围,将产生溢出。

例:

mov al, 98

add al, 99

(al) = (al) + 99 = 99 + 98 = 197

执行后将产生溢出。

mov al, 0F0H  //F0H,为有符号数-16的补码

add al, 088H  //088H,为有符号数-120的补码

(al) = (al) + (-120) = -136

执行后将产生溢出。

由于在进行有符号数运算时,可能发生溢出而造成结果的错误。则CPU需要对指令执行后是否产生溢出进行记录。

flag的第11位是OF,溢出标记位。一般情况下,OF记录了有符号数运算的结果是否发生了溢出。如果发生溢出,OF = 1;如果没有,OF = 0;

CF和OF的区别:

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

OF是对有符号数运算有意义的标志位。

CF和OF所表示的进位和溢出,分别是对无符号数和有符号数运算而言的,它们之间没有任何关系。

DF标志(flag的第10位是DF,方向标志位)和串传送指令(movsb) 和 rep

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

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

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

格式: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

用汇编描述:

mov es:[di], byte ptr ds:[si]     //8086并不支持,这里只是描述

如果 df = 0:

inc si
inc di

如果 df = 1:

dec si
dec di

movsb的功能是将 ds:si 指向的内存单元中的字节送入 es:di中,然后根据标志寄存器df位的值,将si和di递增或递减。

格式:movsw

movsw 的功能是将ds:si指向的内存字单元中的送入es:di中,然后根据标志寄存器df位的值,将si和di递增2或递减2。

用汇编描述

mov es:[di], word ptr ds:[si]     //8086并不支持,这里只是描述

如果 df = 0:

add si, 2
add di, 2

如果 df = 1:

sub si, 2
sub di, 2

movsb 和 movsw进行的是串传送操作中的一个步骤,一般来说,movsb 和 movsw都和 rep 配合使用,格式如下:

rep movsb

用汇编描述:

s:  movsb
	loop s

rep的作用是根据 cx 的值,重复执行后面的串传送指令,由于每执行一次movsb指令si和di都会递增或递减指向后一个单元或前一个单元,则rep movsb就可以循环实现(cx)个字符的传送。

同理:rep movsw

相当于:

s:  movsw
    loop s

8086CPU提供了2条指令对df位进行设置:

cld 指令:将标志寄存器的 df 位置0

std 指令:将标志寄存器的 df 位值1

例:用传送指令,将data段中的第一个字符串复制到它后面的空间中。

assume cs:code, ds:data

data segment

	db 'Welcome to masm!'
	db 16 dup (0)

data ends

code segment 

	start:  mov ax, data
			mov ds, ax
			mov si, 0			

			mov ax, 0010H
			mov es, ax
			mov di, 0
			
			mov cx, 16
			
			cld         //设置df位  0 -> 递增
			rep movsb

code ends

end start

例:用传送指令,将F000H段中的最后16个字符复制到data段中。//逆向传送

assume cs:code, ds:data

data segment

	db 16 dup (0)

data ends

code segment 

	start:  mov ax, 0F000H
			mov ds, ax
			mov si, 0FFFFH  //ds:  0F000H:0FFFFH			

			mov ax, data
			mov es, ax
			mov di, 000EH
			
			mov cx, 16
			
			std         //设置df位 1 -> 递减
			rep movsb

code ends

end start

pushf 和 popf

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

pushf 和 popf,为直接访问标志寄存器提供了一种方法。

标志寄存器在Debug中的表示

AX = 0000  BX = 0000  CX = 0000  DX = 0000  SP = FFEE  BP = 0000  SI = 0000  DI = 0000

DS = ****  ES = ****  SS = ****  CS = ****  IP = ****  NV  UP  EI  PL  NZ  NA  PO  NC
                                                       ↑   ↑       ↑   ↑       ↑   ↑
                                                       OF  DF      SF  ZF      PF  CF

Debug对我们已知的标志位的表示

标志           值为1的标记          值为0的标记

of(溢出标志位)  OV                  NV

sf(负标志位)    NG                  PL

zf(0标志位)    ZR                  NZ

pf(奇偶标志位)  PE                  PO

cf(进、借标志位)CY                  NC

df(方向标志位)  DN                  UP

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

assume cs:codesg

datasg segment

	db "Beginner's All-purpose Symbolic Instruction Code.",0

datasg ends

codesg segment

	begin:  mov ax, datasg
			mov ds, ax
			mov si, 0
			call letterc

			mov ax, 4c00H
			int 21H

  letterc:  mov al, ds:[si]
			mov cl, al
			mov ch, 0
			jcxz return         //判断为零返回 and al, 11011111H
			cmp ax, 63
			jb s0               //小于跳转		
			cmp ax,	88
			ja s0
			
			add al, 11011111H
			mov ds:[si], al 		
		
	   s0: inc si
		    jmp short letterc

   return:  ret

codesg ends

end begin

山樱花 – 纯洁、高尚、淡薄