[Intel汇编-MASM]标志寄存器

1. 标志寄存器的功能:

    1) 即SF寄存器(16位),Sign Flag Register,用于存放程序运行时的一些状态信息以及一些运算的临时结果等,该寄存器中的信息称为程序状态字PSW(Program Status Word,因为是16位字型的);

    2) 该寄存器和其它通用寄存器和专用寄存器有明显的区别,首先它不是用来存放数据和地址的,它是按位起作用的,每一位保存着不同意义的信息(比如保存加法进位信息、运算是否溢出等信息),并且该寄存器无法直接访问,它的功能是隐藏在普通的指令中的,可以通过一些指令间接地用到该寄存器中的位信息;

    3) 该寄存器是基于CPU的,不同CPU结构和数量都不同(比如相同的标志位对于不同的CPU其在SF中位于第几位可能不同,并且有用的标志位的数量可能也不尽相同,有的多有的少,并不是所有16位都是有用的,只有部分有用),因此这里不讨论也无需记忆每种标志位位于SF的第几位,只需要知道几种重要的标志位的作用就行了;

    4) 这里最主要介绍8个标志位,每个标志位都有自己的名字,分别是ZF、PF、SF、CF、OF、DF、TF、IF,这几个标志位的具体作用和含义下面会具体分解;


2. ZF:

    1) Zero Flag,判零标志位;

    2) 基本上所有的运算指令都会影响ZF位,就是指add、sub、and、or、mul、div、inc等指令;

    3) 作用规则:计算结果(即目的操作数最终的值)为0则ZF为1,不为0则ZF为0,即等价于函数isZero( )的作用;


3. PF:

    1) Parity Flag,奇偶标志位;

    2) 检查运算指令结果(目的操作数)的奇偶性以及数据传送时查错(也是判断结果的奇偶性,比如奇偶校验);

    3) 作用规则:如果指令运行结果的二进制位中1的个数为偶则PF为1,否则为0;


4. SF:

    1) Sign Flag,符号标志位;

    2) 检查运算指令的结果中最高位(即符号位)是否为1;

    3) 作用规则:如果指令运行结果的最高位为1则SF为1,否则为0;

!注意:在汇编这种低级语言中,数据仅仅就是二进制单元中的0和1,因此对于一个数既可以看成是有符号数也可以看成是无符号数,如果是有符号数则最高位必须看作是符号位并且要把它看做补码,如果是无符号数则最高位不是符号位并且要看成普通二进制编码(不用看成是补码表示);

!因此,不管你把运算看做是有符号运算还是无符号运算都会影响到SF位,但是只有看作有符号运算时SF位的内容对你来说才会有意义;


5. CF标志位和adc、sbb指令:

    1) Carry Flag,进位/借位符号位;

    2) 专门用于检查加法指令和减法指令的进位和借位状况;

    3) 作用规则:只有当你看成是无符号加减法运算时才有意义(虽然无论如何都会对CF位产生影响),加法运算时如果结果有进位则CF为1,否则为0,而减法运算时如果有借位则CF为1,否则为0;

    4) 作用是可以解决CPU宽度不足所造成的限制,比如,如果两个8bit数相加但结果超出了8bit则会产一个进位,而该进位就能保存在CF中了,而剩下的还是保存在8bit寄存器中,同时也能实现超长位数的加减法运算;

    5) 用adc指令实现长位数加法运算:

        i. adc即为add with carry flag的缩写,用法和add一样,只不过它是这样运作的:adc op1, op2 == add op1, op2, CF,即adc为带进位的加法运算;

        ii. 用adc实现两个32位数的加法:001EF000H + 00201000H,其中两个操作数的低16位相加时会产生一位进位,因此可以先对两个数的低位用add相加,然后再用adc对其高位进行相加,这样高位就能携带上从低位而来的进位了;

assume cs:code

code segment
	mov		ax, 001EH ; high
	mov		bx, 0F000H ; low
	add		bx, 1000H ; low add
	adc		ax, 0020H ; add high with carry

	mov		ax, 4C00H
	int		21H
code ends

end
对于更长位数的加法操作也是同理,即一路从低位加到高位(利用adc携带进位往上加);

    6) 用sbb指令实现长位数减法运算:

        i. sbb即sub with borrow flag的缩写,即带借位的减法,运作实质:sbb op1, op2 == ( op1 = op1 - op2 - CF );

        ii. 用sbb实现两个32位数的减法:003E1000H - 00202000H,其中两数的低16位相减会产生借位,因为1000H < 2000H,因此先让低位用sub相减,然后高位相减的使用使用sbb携带刚刚低位相减时的借位,这样就能得到正确结果了;

assume cs:code

code segment
	mov		ax, 003EH ; high
	mov		bx, 1000H ; low
	sub		bx, 2000H ; outcome a borrow flag
	sbb		ax, 0020H ; sub with a borrow flag

	mov		ax, 4C00H
	int		21H
code ends

end
    7) 只有双操作符的加减法指令对CF起作用(包括adc和sbb),但是单操作符的inc和dec以及loop指令不能影响CF位,请看下例:

实现两个128位数据的加法,数据存放在内存中,以字的形式存放

assume cs:code, ds:data

data segment
	dw 16 dup(?)
	dw 16 dup(?)
data ends

code segment

start:
	mov		ax, seg data
	mov		ds, ax
	mov		ss, ax
	mov		bx, 2
	mov		bp, 32

	sub		ax, ax ; CF -> 0
	mov		cx, 8
lp:
	mov		ax, [bp]
	adc		[bx], ax
	inc		bx ; to keep CF safe, do not use 'add bx/bp, 2'!
	inc		bx
	inc		bp
	inc		bp
	loop	lp

	mov		ax, 4C00H
	int		21H
code ends

end start
一路加上去的途中必须保证CF不能被破坏,因此如果不能使用add对bx和bp进行递增,但是幸好inc和loop指令都不会对CF产生影响!

*同理,dec也不会对CF位产生影响;


6. OF:

    1) Overflow Flag,即溢出标志位;

    2) 只有加减运算会对产生影响,即检查运算结果是否超出规定的长度(8位或16位);

    3) 作用规则:如果运算结果发生溢出则OF为1,否则为0;

    4) 该标志位只对有符号数的加减运算有意义,因为如果你看成是无符号运算,即使发生溢出但是有CF位可以保证最后的结果是正确的,而对于有符号位的加减运算,一旦发生溢出则既不能通过CF也不能通过OF来确保最终结果是正确的(即一般认为有符号数加减如果发生溢出则结果必定是错的!因此需要报错!),因此OF位的作用就是检查有符号数的加减是否溢出,如果溢出就报错,否则就正常执行程序,用C语言伪代码来表示OF的作用就是:if ( 1 == OF( add/sub ) ) report_overflow_error;


7. cmp指令和与其有关的条件转移指令:

    1) cmp即compare的缩写,用于比较两个操作数之间的大小,用法就是:cmp opr1, opr2,两个操作数和mov的操作数差不多,支持寄存器、内存、立即数,涉及到内存时只要注意内存的访问规则就行;

    2) 但实质上仅仅就是做一个减法运算,即opr1 - opr2,并且不保存该减法运算的结果而仅仅根据运算结果影响标志寄存器SF;

    3) cmp最主要是配合一些条件转移指令使用,一般条件转移指令仅仅跟在cmp指令后面,根据cmp设置的标志位进行条件转移,这里就不提cmp是如何影响各个标志位的了,因为非常繁杂,其用来一系列手段保证再做opr1 - opr2时发生借位或者有符号数的溢出都能保证比较的结果是完全正确的,因此就没必要死记cmp的减法结果是如何影响各个标志位的了,只要知道cmp和条件转移指令如何配合使用就行了!

!注意:再次强调,为了能根据cmp的比较结果进行跳转一定不要在cmp和条件转移指令之间插入其它语句(即使是不影响SF的语句也最好不要插入);

    4) 和cmp配合使用的条件转移指令:用C语言的比较符号示意,其中j -> jump, e -> equal, n -> not

*和符号无关的转移

je : ==

jne : !=

*无符号比较的转移: b -> below, a -> above

jb : <

jbe: <=

jnb : >=

ja : >

jae: >=

jna : <=

*有符号比较的转移:g -> greater, l -> lower

jl : <

jle : <=

jnl : >=

jg : >

jge : >=

jng : <=

!注意:以上都表示当比较条件成立时进行跳转;

!注意:由于都是条件转移指令,因此都是位移型的段内短转移,转移范围都是[-128, 127],因此只能用标号作为它们的唯一操作数;

    5) cmp和条件转移指令配合使用可以实现类似C语言if语句的功能!

    6) 示例:

统计data段中数值为8的字节的个数,结果存放在ax中

assume cs:code, ds:data

data segment
	db 1, 2, 3, 4, 8, 8, 7, 14, 8, 0, 0, 8, 8, 3, 12, 8
data ends

code segment

start:
	mov		ax, seg data
	mov		ds, ax

	mov		ax, 0
	mov		bx, 0
	mov		cx, 16
lp:
	cmp		byte ptr [bx], 8
	jne		next
	inc		ax
next:
	inc		bx
	loop	lp

	mov		ax, 4C00H
	int		21H
code ends

end start
!注意:这里有个技巧,就尽量使用“! to next"结构,即cmp之后跟”jnXXX next"跳转,因为这可以是代码最简洁最短!


8. DF和串传送指令:

    1) Direction Flag,即方向标志位;

    2) 这个标志位用于串操作,它将指示在进行串操作时串操作变址寄存器(即索引寄存器si和di)的增加;

    3) 作用规则:当进行串操作时如果DF为0则si和di将递增,当DF为1时si和di递减;

    4) 这里的串操作就是指在两个连续的空间内进行数据通信的操作,比如将一个数组中的内容复制到另一个数组中去等等,像这样的串操作指令就有movsb和movsw;

    5) movsb和movsw:

        i. 就是move string of bytes和move string of words的缩写,即批量传送字节和字;

        ii. 它们一定要和cx、ds:si、es:di以及rep指令配合使用;

        iii. 使用方式如下:

mov		cx, len
rep		movsX
!注意:其中rep就是repetition的意思(重复执行),rep命令的含义就是重复执行后面跟着的指令cx次,因此len也就是串操作的长度;

!注意:而movsX的含义就是:mov es:[di], ds:[si]; si++; di++,当DF为0的时候就是++,当DF为1的时候就是--

!因此将上述用法翻译成普通汇编伪代码就是:

	mov		cx, len
lp:	mov		es:[di], ds:[si]
	si++, di++
	loop	lp
    6) 手动设置DF的值:使用cld指令(即clean direction,清除为零,即清零的意思)将DF置0,使用std指令(即set direction,设置为1)将DF设置为1;

    7) 示例:

将data段中第一个字符串复制到它后面的空间中

assume cs:code, ds:data

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

code segment

start:
	mov		ax, seg data
	mov		ds, ax
	mov		es, ax
	mov		si, 0
	mov		di, 16
	
	cld
	mov		cx, 16
	rep		movsb

	mov		ax, 4C00H
	int		21H
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		ax, seg data
	mov		es, ax
	mov		si, 0FFFFH
	mov		di, 15
	
	std
	mov		cx, 16
	rep		movsb

	mov		ax, 4C00H
	int		21H
code ends

end start

运行结果:

[Intel汇编-MASM]标志寄存器_第1张图片


9. 保存和恢复SF:使用pushf和popf就可以利用栈了保存和恢复标志寄存器了,后缀f就代表flag register的意思(即标志寄存器),这也是唯一可以访问标志寄存器的手段了!


10. 标志寄存器在Debug中的表示:

    1) 位于右下角的位置;

    2) 具体表示的含义:

标志位                1                            0

   OF           OV(Overflow)       NV(Not Overflow)

   SF           NG(Negative)           PL(Positive)

   ZF               ZR(Zero)              NZ(Not Zero)

   PF         PE(Parity Even)      PO(Parity Odd)

   CF             CY(Carry)            NC(Not Carry)

   DF             DN(Down)                   UP


你可能感兴趣的:(masm,intel汇编,标志寄存器)