8086MASM汇编深入理解指令对标志位的影响
文章目录
- 8086MASM汇编深入理解指令对标志位的影响
- 0. 指令对标志位影响
- 1. 指令对标志位影响速查表
- 2. flags标志寄存器: 标志位含义解读
- `flags`
- 1. 状态标志cf, pf, af, zf, sf, of
- 2. 控制标志df, if, tf
 
 
- 详解:
- 1. 传送指令
- 2. 算术指令
- 3. 逻辑/位指令
- 4. 移位指令
- 5. 分支指令: 标志位的应用
- 1. cmp
- 2. jmp label/r16/m16
- 3. jcc label
- (1) 功能:满足条件"cc"则跳转到label,否则执行下一条指令
- (2)分类掌握
- 1. 检查单个标志位
- 2. 大小关系
- 答疑:
 
 
 
 
0. 指令对标志位影响
1. 指令对标志位影响速查表
| CF | OF | SF | ZF | PF | AF | |
|---|---|---|---|---|---|---|
| 传送指令 mov,xchg,lea,push,pop,in,out | x | x | x | x | x | x | 
| 算术指令 add,adc,sub,sbb,cmp,neg | o (当成无符号数运算有进位借位则CF=1) | o (当成有符号数运算溢出则OF=1) | o | o | o | o(低8位产生进位/高8位产生借位则AF=1) | 
| 算术指令 inc,dec | x | o | o | o | o | x | 
| 逻辑指令 and,test,or,xor | 置cf=0 | 置of=0 | o | o | o | x | 
| 逻辑指令 not | x | x | x | x | x | x | 
| 移位指令 shl=sal,shr,sar | o (无论左移右移算数逻辑移出了1就CF=1) | o (移位后最高位改变则OF=1) | o | o | o | x | 
| 循环移位 rol,ror,rcl,rcr | o (无论左移右移算数逻辑移出了1就CF=1) | o (移位后最高位改变则OF=1) | x | x | x | x | 
2. flags标志寄存器: 标志位含义解读
flags
 
flags = [x, x, x, x, of(11), df(10), if(9), tf(8), sf(7), zf(6), x, af(4), x, pf(2), x, cf(0)]
1. 状态标志cf, pf, af, zf, sf, of
| 标志位 | 功能和取值 | 
|---|---|
| cf | 进位标志(Carry Flag) | 
| pf | 奇偶标志(Parity Flag)。若PF=1,表示操作结果中“1”的个数为偶数,否则PF=0。这个标志位主要用于检查数据传送过程中的错误, 和方便软件实现奇偶校验。 | 
| af | 辅助进位标志(Auxiliary Carry Flag)也叫半进位标志, 若AF=1表示字节运算产生低半字节向高半字节的进位或借位,否则AF=0. 主要用于BCD码运算的十进制调整。 | 
| zf | 全零标志(Zero Flag)。若ZF=1,表示操作结果全为零 | 
| sf | 符号标志(Sign Flag)。若SF=1,表示符号数运算后的结果为负数 | 
| of | 溢出标志OF=1,表示当进行算术运算时,结果超过了最大范围 | 
2. 控制标志df, if, tf
| 标志位 | 功能和取值 | 
|---|---|
| df | 方向标志, 用于串指令, 若DF=1, 表示执行字符串操作时按着从高地址向低地址方向进行(si, di自减);否则DF=0。DF位可由指令控制。 | 
| if | 中断标志, 用于是否允许响应可屏蔽中断 | 
| tf | 
详解:
1. 传送指令
传送类指令都不影响标志位
| 操作数形式 | 功能 | 对标志的影响 | |
|---|---|---|---|
| mov | mov dest, src(不限制宽度) 限制: 1. seg间传送 2. mem间传送 3. 立即数传给seg 4. cs出现 | 传送 | 不影响任何 | 
| xchg | xchg dest, src(不限制宽度) 限制: 1. seg间传送, 2. mem间传送, 3. 立即数出现 | 交换两操作数 | 不影响任何 | 
| lea | lea r16, mem | 获取有效地址 | 不影响任何 | 
| push | push r16/m16/i16/seg | 进栈 | 不影响任何 | 
| pop | pop r16/m16/seg | 出栈 | 不影响任何 | 
2. 算术指令
都不允许
- op imm, imm
- op mem, mem
- op seg, xxx
CF, OF深入理解
-  CF: 当成无符号数时, 加有进位则CF=1, 被减数小于减数(注意是当成无符号数时有借位)CF=1 举例: 真值:1 - (-2) = 3, 补码: 0x01H - 0xFEH: 标志: OF= 0(真值为3没溢出),CF= 1(解释为无符号数时0x01H小于0xFEH, 产生借位)
-  OF: 用双符号位判断, 或者用真值有没有超过表示范围判断 
| 操作数形式 | 功能 | 对标志影响 | |
|---|---|---|---|
| add | add dest, src | dest << dest + src | 全影响 | 
| adc | adc dest, src | dest << dest + src + cf | 全影响 | 
| inc | inc r/m | r/m << r/m + 1 | 除cf 全影响 | 
| sub | sub dest, src | dest << dest - src | 全影响 | 
| sbb | sbb dest, src | dest << dest - src - cf | 全影响 | 
| dec | dec r/m | r/m << r/m - 1 | 除cf 全影响 | 
| neg | neg r/m | r/m << 0 - r/m | 全影响(等于用0减) | 
| cmp | cmp dest, src | dest - src | 全影响 | 
-  MUL IMUL MUL指令若高一半不为0则of=cf=1 IMUL指令若高一半是低一半的符号扩展则of=cf=1 乘法指令只影响OF位和CF位,对其他位没定义 
-  DIV IDIV 除法指令对6个标志位均没定义 
3. 逻辑/位指令
都不允许
- op imm, imm
- op mem, mem
- op seg, xxx
| 操作数形式 | 功能 | 对标志的影响 | |
|---|---|---|---|
| and | and dest, src | 逻辑与 | 置cf=of=0, sf, zf, pf, 对af无定义 | 
| test | test dest, src | 逻辑与(但不改变寄存器值) | 置cf=of=0, sf, zf, pf, 对af无定义 | 
| or | or dest, src | 逻辑或 | 置cf=of=0, sf, zf, pf, 对af无定义 | 
| xor | xor dest, src | 异或 | 置cf=of=0, sf, zf, pf, 对af无定义 | 
| not | not r/m | 取反 | 不影响任何 | 
4. 移位指令
- 移出1则cf=1
- 最高位改变则of=1(有实际意义)
- 对af无定义
sf, zf, pf循环移位不影响, 其他移位影响
| 功能 | 对标志的影响 | |
|---|---|---|
| shl = sal(没有任何区别) | 为什么算术左移和逻辑左移是一样的, 因为无论是有符号还是无符号数, 左移进来的一定是0(无论从标志含义还是结果角度都是一样的,这正是补码设计的精妙之处) | 移出1则cf=1 最高位改变则of=1(有实际意义) sf,pf,zf 对af无定义 | 
| shr | 逻辑右移 | 移出1则cf=1 最高位改变则of=1(有符号负数必溢出) sf,pf,zf 对af无定义 | 
| sar | 算术右移 | 移出1则cf=1 最高位改变则of=1(实际上不可能溢出) sf,pf,zf 对af无定义 | 
| rol | 循环左移 | 移出1则cf=1 最高位改变则of=1(有实际意义) 对sf,pf,zf无影响 对af无定义 | 
| ror | 循环右移 | 移出1则cf=1 最高位改变则of=1(有实际意义) 对sf,pf,zf无影响 对af无定义 | 
| rcl | 带cf循环左移 | 移出1则cf=1 最高位改变则of=1(有实际意义) 对sf,pf,zf无影响 对af无定义 | 
| rcr | 带cf循环右移 | 移出1则cf=1 最高位改变则of=1(有实际意义) 对sf,pf,zf无影响 对af无定义 | 
5. 分支指令: 标志位的应用
1. cmp
2. jmp label/r16/m16
(1) 功能: ip << label/r16/m16
(2) 扩展:
jmp short ptr xxx 跳转范围-128~127
jmp near ptr xxx 跳转范围-32768~32767
jmp far ptr xxx
这个不止会修改ip还会修改cs, 由于代码段过长,可能导致一个段放不下的跳转
ip修改为xxx的偏移地址
cs修改为xxx的段地址, 只有jmp far ptr label, 或者jmp 段地址:偏移地址, 两种会改变cs的值
3. jcc label
(1) 功能:满足条件"cc"则跳转到label,否则执行下一条指令

(2)分类掌握
1. 检查单个标志位
J[flag]/JN[flag]
考察flag位为1(J[flag])或为0(JN[flag])
其中特别的有JZ=JE(cmp后zf为1等价于两数相等), JC=JB(cmp后cf为1等价于两数看成无符号数时被减数小于减数即below)
2. 大小关系
below => B: 无符号数的小于
less => L: 有符号数的小于
greater => G: 有符号数的大于
equal => Z: 等于, 加在大小关系的后面
答疑:
-  为什么没有无符号数的大于? 因为光凭标志位CF无法判断被减数是否大于减数, 但是通过SF和OF可以判断, 因此有符号数和无符号数的"大于"关系合并为用SF和OF判断 
-  为什么SF不等于OF代表小于? SF不等于OF分两种情况 -  SF=1, OF=0, 表示结果为负数, 结果没溢出. 这种情况大家一般都能理解: OF=0说明运算结果的真值是正确的, 此时两数相减结果为负数说明被减数小于减数, 这是数学常识 
-  SF=0, OF=1, 表示结果为正数, 但是发生了溢出, 这是对被减数小于减数的一种特殊情况的补充 先给结论: 这是在考虑负数减正数但是结果溢出了的情况 我们来考虑怎样的情况会产生这样的标志. 以八位的减法运算来举例, 分类讨论, 先考察哪些减法会产生溢出, 再来考察SF是否=0, 揪出这种特殊的减法 - 正数减正数: 不可能出现溢出. 原因: 正数减正数想要溢出一定是下溢, 考虑最极端情况, 最小的正数减去最大的正数: 1 - 127 = -126 > -128没有溢出
- 正数减负数: 可能出现溢出. 原因: 正数减负数想要溢出一定是上溢, 考虑极端情况, 最小的正数减去最小的负数(绝对值最大): 真值: 1- (-128) = 129 > 127 确实产生了溢出, 但是相减后SF=1(01H - 80H = 81H, SF=1), 不满足条件
- 负数减负数: 不可能溢出, 同正数减正数
- 负数减正数: 可能出现溢出, 负数减正数如果溢出一定是下溢, 考虑极端情况, 最小的负数减去最大的正数: -128 - 127 = -255 < -128 狠狠的溢出了, 再考察SF, SF=0 (80H - 7FH = 01H, SF=0). 那有的同学会问了, 那要是没溢出怎么办, 那就回到了SF=1, OF=0的情况
 过程中还产生了个二级结论, 若OF=1, 1. SF=1一定是正数减负数 2. SF=0一定是负数减正数 
 
-  



















