[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 endsend7) 只有双操作符的加减法指令对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++looplp6) 手动设置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
- [Intel汇编-MASM]标志寄存器
- [Intel汇编-MASM]程序中可用的寄存器
- [Intel汇编-MASM]用DS寄存器定义一段数据
- [Intel汇编-MASM]栈
- [Intel汇编-MASM]转移指令
- [Intel汇编-MASM]内中断
- [Intel汇编-MASM]端口通信
- [Intel汇编-MASM]外中断
- 汇编标志寄存器
- 汇编标志寄存器
- 标志寄存器 x86汇编
- [Intel汇编-MASM]Debug的使用
- [Intel汇编-MASM]与或以及乘除
- [Intel汇编-MASM]内存单元访问扩展
- [Intel汇编-MASM]嵌套循环问题
- p217 8086汇编FLAG寄存器中的OF标志 | 8086汇编标志寄存器 | 标志寄存器OF标志
- 汇编学习--7.13--标志寄存器
- 汇编学习历程(标志寄存器)
- 用HtmlCleaner抓取新闻
- EditPlus配置c++运行环境
- XPath详解及Java示例代码
- Linux 配置收集 - Some Configuration In Linux - By黑月君
- 02分布式数据仓库 HIVE -- 表的相关操作
- [Intel汇编-MASM]标志寄存器
- JVM之判断一个对象是否存活
- 谁能帮我把这个变换做一下?
- 国产好日历:WeCal 微历
- linq to sql 时间类型的查询
- codevs1074食物链
- Linux开发平台的搭建之SecureCRT
- ListView原理简单介绍(着重介绍getView被调用的一系列过程)
- quick-cocos2d-x里的MVC