cmp test指令 条件转移 FLAGS寄存器 机理探究

  之前,笔者使用C语言或进行逆向分析的时候,专注于高层逻辑,并没有对“条件判断是如何运行的”这类问题有过多考虑,也没有系统学习汇编语言。近来学习操作系统,MBR和Boot Loader处需要补充汇编知识,暴露了问题,也产生了一些比较绕的疑问。
  “条件判断如何区分操作数的符号?”、“Carry Flag 与 Overflow Flag 的区别是什么?”、“cmp指令是如何操作Flags寄存器的?”……
  经过查阅“大量”资料,以及自行设计实验验证,大致对以上问题有了较清晰的理解,故作文以记之,留日后回顾,也希望帮助读者解答“初学者的疑惑”。

基础资料

FLAGS 标志寄存器

  • Flags 寄存器,主要保存ALU指令执行状态,系统控制标志等。
  • Flags 寄存器(未拓展),与一般寄存器相同,长16b,其中按二进制位存储状态/控制信息。
  • 下表为寄存器各位的名称、功能、状态表示
Bit简称全称(助记)分类=1=0
0CFCarry Flag (进/借位标志)StatusCY(Carry)NC(No Carry)
1Reserved, always 1 in EFLAGS
2PFParity Flag (奇偶标志)*StatusPE(Parity Even)PO(Parity Odd)
3Reserved
4AFAdjust Flag (最低半字节(4b)有无进位/借位)*StatusAC(Auxiliary Carry)NAC
5Reserved
6ZFZero Flag (if operand is 0)StatusZRNZ
7SFSign FlagStatusNegativePositive
8TFTrap Flag (Single Step mode)Control
9IFInterrupt enable flagControlEnable
10DFDirection flag (串指令 MOVS等,Down:Address H2L)ControlDownUp
11OFOverflow FlagStatusOverflowNV
12IOPLI/O Privilege Level (286+Only)System
13IOPLI/O Privilege Level (286+Only)System
14NTNested Task Flag (286+ Only)System
15Reserved (1 on 8086 and 186, 0 later)
  • 奇偶校验位PF:统计计算结果低八位中置位(1)数量,奇数为0

    • 常用于数据传输的校验(奇偶校验)
  • 以下两组操作都将导致AF置1

    mov eax, 0b1111
    add eax, 1
    
    mov eax, 0b10000
    sub eax, 1
    
  • 12位及以上为286+特有,支持特权级和多任务。(保护模式下会用到)

条件转移指令

条件转移指令仅对标志位进行判断,标志位通过前面的测试指令进行置位。转移指令本身不进行算数逻辑运算

指令跳转条件全称(当满足时跳转)
jz/jeZF=1-
jnz/jneZF=0
jsSF=1sign (is set, same as negative)
jnsSF=0
joOF=1overflow
jnoOF=0
jp/jpePF=1Parity / Parity Even
jnp/jpoPF=0Not Parity / Parity Odd
jbe/jnaCF
jnbe/jaCF = ZF = 0Not Bellow or Equal / Above
jc/jb/jnaeCF = 1Carry / Below / Not Above or Equal
jnc/jnb/jaeCF = 0Not Carry / Not Bellow /Above or Equal
jl/jngeSF ≠ OFLess / Not Great Equal
jnl/jgeSF=OFNot Less / Great Equal
jle/jngSF ≠ OF or ZF=1Less Equal / Not Great
jnle/jgSF = OF and ZF = 0
JcxzCX = 0register CX’s value is Zero

测试指令 cmp & test

  • Intel语体中,Operand1 位于 Operand2 左侧,判断条件方式:Operand 1 判断 Operand 2
test op1, op2
cmp op1, op2
  • cmp指令:先运算op1 - op2,再对结果进行置位
  • test指令:先运算op1 & op2,再对结果进行置位

问题探究

下面,我们将沿着高级语言中,对两个数大小进行判断的底层流程,依次对各个环节的细节进行探索

测试指令

测试指令的作用在上一节已经说过了,下面则是它粒度更低的过程演示。

CMP:

  1. 计算 op1 - op2,设为temp变量(类似sub,不赋值给op1)
  2. 按照sub指令的置位方法,给Flags对应位置位
    1. CF、OF、AF由过程中状态置位
    2. ZF、SF、PF按照结果temp置位

TEST:

  1. 计算op1 & op2, 设为temp变量
  2. 按照and指令置位方法置位
    1. CF=OF=0
    2. ZF, SF, PF 按照temp值置位
    3. AF 未定义

本质上,测试指令进行了一次算数/逻辑运算,通过算数逻辑单元ALU,为标志寄存器置位,并丢弃运算结果。

部分寄存器置位条件

  对于状态寄存器,主要的置位来源有两种。一是按照算数/逻辑运算过程中发生的事件,而是按照算数/逻辑运算的结果。

按过程置位

  • CF: 按照运算过程中,算数逻辑单元是否发生超过其最高有效位的进位/借位事件
    • 最高有效位,是寄存器的实际长度的最高位,不考虑符号数问题
    • example: 在16位运算中
      • 0xffff + 0x1 = 0x(1)0000发生了进位
      • 0x(1)0001 - 0x0002=0xffff发生了借位
      • 对于 1- (-2) -> 0x(1)0001 - 0xfffe = 0x0003正数减负数同样发生借位
  • OF: 运算中,是否发生算数溢出。即在有符号运算中,两个同号操作数相加(或异号相减),所得结果为异号
    • 含义为,运算结果过长,无法按照有符号数形式装入结果载体中
    • OF仅考虑符号位问题,不考虑是否进/借位
    • 仅在同号相加/异号相减过程中,出现异号结果时才会置位
    • example:在16位运算中
      • (0x7fff - -1) ->0x7fff - 0xffff = 0x8000,正数减负数,结果异号,发生算数溢出
      • 0x7fff + 1= 0x8000,与上面相同,正数相加,异号,发生溢出
      • 0x1 - 0x2 = 0x7fff,两正数相减,不考虑溢出
      • 0x8000 + 0x8001 = 0x1,两负数相加,异号,发生溢出
  • AF: 见上一节基础资料,由于不太常用,就不详细介绍了

按结果置位

  • 此类标志只按照运算结果确定是否置位,判断较为简单
  • 具体判定方法基础资料中已经给出,这里不再冗述

CF 与 OF 功能差异

  从上面的置位条件中,我们已经可以看出CF与OF的表现差异。接下来,我们将从应用的角度区分这两个寄存器。

  **当需要进行有符号运算时,观察OF。**它标志着我们的运算结果(有符号)的符号位是否出错(由于溢出而反转)。此时,CF位没有作用

  **当无符号运算时,观察CF。**它标志着结果是否由于进位或借位发生 2 b 2^b 2b的偏移。此时,OF位没有作用。

条件转移指令的选择

  了解完CF与OF的特点以及适用场景后,我们应该如何选择条件跳转指令呢?这取决于我们进行的运算是有符号的还是无符号的。判断运算是否带符号是编译器的任务,在编译过程中,从源代码角度,我们自然可以得知这个运算是否带符号位,从而在判断时选择正确的条件转移指令

  算数比大小有关的条件跳转指令也分为两类(不包括判等)。

  • 无符号:以below, above标志,表示无符号操作数的大小比较
  • 有符号:以great, below标志,表示有符号数的大小比较

cmp 条件转移

  cmp指令常于条件转移连用,用于表达式的逻辑判断与跳转。相关指令的含义在前两节已经给出。

  ALU进行运算时,不会区分是否为有符号数运算,它只将对应的状态标志位置位,具体观察什么标志位(即采用何种条件转移指令),取决于程序员的选择。

  编译过程中,编译器保存了各个符号的属性,能够为某个条件判断分配正确的条件转移指令,从而提供了带符号标志位的条件转移支持。

下面给出有符号数cmp条件转移的具体判断

  • jge:op1 >= op2

    • 相减后出现两种情况
      • 发生溢出,OF=1,表示结果的符号与算数符号相反,若 op1 > op2, 则溢出后结果为负数,SF=1
      • 未发生溢出,OF=0,结果符号与实际符号相同。若两数相等,OF=0,SF=0
    • 我们的跳转条件为op1>= op2,即算数结果>0,SF=0。综上可得跳转条件:SF=OF
  • jle: op1 <= op2

    • 除了jge的条件取反(op1 >= op2,取反为 op1 < op2),还需要考虑相等情况
      • 若两数相等,结果为0,SF=0,OF=0,并不符合SF != OF条件,需要增加条件
    • 综上,跳转条件为:SF=OF or ZF = 1
  • 另两个条件转移是以上两种的取反,类推即可

  至此,我们已经成功解决了开头提出的三个问题,也对条件跳转、FLAGS寄存器和测试指令有了更深入的理解。希望对读者有所帮助,我们下期再见~

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值