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

来源:互联网 发布:知远战略与防务论坛 编辑:程序博客网 时间:2024/04/29 19:56

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:codecode segmentmovax, 001EH ; highmovbx, 0F000H ; lowaddbx, 1000H ; low addadcax, 0020H ; add high with carrymovax, 4C00Hint21Hcode endsend
对于更长位数的加法操作也是同理,即一路从低位加到高位(利用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:codecode segmentmovax, 003EH ; highmovbx, 1000H ; lowsubbx, 2000H ; outcome a borrow flagsbbax, 0020H ; sub with a borrow flagmovax, 4C00Hint21Hcode endsend
    7) 只有双操作符的加减法指令对CF起作用(包括adc和sbb),但是单操作符的inc和dec以及loop指令不能影响CF位,请看下例:

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

assume cs:code, ds:datadata segmentdw 16 dup(?)dw 16 dup(?)data endscode segmentstart:movax, seg datamovds, axmovss, axmovbx, 2movbp, 32subax, ax ; CF -> 0movcx, 8lp:movax, [bp]adc[bx], axincbx ; to keep CF safe, do not use 'add bx/bp, 2'!incbxincbpincbplooplpmovax, 4C00Hint21Hcode endsend 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:datadata segmentdb 1, 2, 3, 4, 8, 8, 7, 14, 8, 0, 0, 8, 8, 3, 12, 8data endscode segmentstart:movax, seg datamovds, axmovax, 0movbx, 0movcx, 16lp:cmpbyte ptr [bx], 8jnenextincaxnext:incbxlooplpmovax, 4C00Hint21Hcode endsend 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. 使用方式如下:

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

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

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

movcx, lenlp:moves:[di], ds:[si]si++, di++looplp
    6) 手动设置DF的值:使用cld指令(即clean direction,清除为零,即清零的意思)将DF置0,使用std指令(即set direction,设置为1)将DF设置为1;

    7) 示例:

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

assume cs:code, ds:datadata segmentdb 'Welcome to MASM!'db 16 dup(0)data endscode segmentstart:movax, seg datamovds, axmoves, axmovsi, 0movdi, 16cldmovcx, 16repmovsbmovax, 4C00Hint21Hcode endsend start
将F000H段中最后16个字符复制到data段中

此时显然用倒叙串操作更方便

assume cs:code, ds:datadata segmentdb 16 dup(0)data endscode segmentstart:movax, 0F000Hmovds, axmovax, seg datamoves, axmovsi, 0FFFFHmovdi, 15stdmovcx, 16repmovsbmovax, 4C00Hint21Hcode endsend start

运行结果:



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


0 0
原创粉丝点击