汇编语言检测比较结果的条件转移指令

  比如,jcxz 就是一个条件转移指令,它可以检测 cx 中的数值,如果 (cx)=0,就修改 IP,否则什么也不做。所有条件转移指令的转移位移都是 [-128~127]。
  除了 jcxz 之外,CPU 还提供了其他条件转移指令,大多数条件转移指令都检测标志寄存器的相关标志位,根据检测的结果来决定是否修改 IP。它们检测的是哪些标志位呢?就是被 cmp 指令影响的那些,表示比较结果的标志位。这些条件转移指令通常都和 cmp 相配合使用,就好像 call 和 ret 指令通常相配合使用一样。
  因为 cmp 指令可以同时进行两种比较,无符号数和有符号数比较,所以根据 cmp 指令的比较结果进行转移的指令也分为两种,即根据无符号数的比较结果进行转移的条件转移指令(它们检测 zf、cf 的值)和根据有符号数的比较结果进行转移的条件转移指令(它们检测 sf、of 和 zf 的值)。
下面是常用的根据无符号数的比较结果进行转移的条件转移指令。

  指令        含义      检测的相关标志位

  je           等于则转移     zf=1
  jne          不等于则转移      zf=0
  jb           低于则转移    cf=1
  jnb          不低于则转移    cf=0
  ja          高于则转移     cf=0 且 zf=0
  jna          不高于则转移    cf=1 或 zf=1

  这些指令比较常用,它们都很好记忆,它们的第一个字母都是 j,表示 jump;后面的字母意义如下。

  e: 表示 equal
  ne:表示 not equal
  b: 表示 below
  nb:表示 not below
  a: 表示 above
  na:表示 not above

  注意一下它们所检测的标志位,都是 cmp 指令进行无符号数比较的时候,记录比较结果的标志位。比如 je,检测 zf 位,当 zf=1 的时候进行转移,如果在 je 前面使用了 cmp 指令,那么 je 对 zf 的检测,实际上就是间接地检测 cmp 的比较结果是否为两数相等。
下面看一个例子
编程实现如下功能:
如果(ah)=(bh)则(ah)=(ah)+(ah),否则(ah)=(ah)+(bh)

    cmp ah,bh
    je s
    add ah,bh
    jmp short ok
 s: add ah,ah
 ok:...

上面的程序执行时,如果(ah)=(bh),则cmp ah,bh使zf=l,而je检测zf是否为1,如果为1,将转移到标号s处执行指令add ah,ah。这也可以说,cmp比较ah, bh后所得到的相等的结果使得je指令进行转移。从而很好地体现了je指令的逻辑含义,相等则转移。虽然je的逻辑含义是“相等则转移”,但它进行的操作是zf--1时则转移。

虽然je的逻辑含义是“相等则转移”,但它进行的操作是zf=1时则转移。“相等则转移”这种逻辑含义,是通过和cmp指令配合使用来体现的,因为是cmp指令为zf=l”赋予了“两数相等”的含义。
至于究竟在Je之前使不使用cmp指令,在于我们的安排。je检测的是zf位置,不管je前面是什么指令,只要CPU执行je指令时,zf=l,那么就会发生转移,

比如:

    mov ax,0
    add ax,0
    je s
    inc ax
s:  inc cx

执行后,(axrl o add ax,0使得zf=1,所以je指令将进行转移。可在这个时候发生的转移的确不带有“相等则转移”的含义。因为此处的je指令检测到的z}l,不是由cmp等比较指令设置的,而是由add指令设置的,并不具有“两数相等”的含义。但无论"zf=l”的含义如何,是什么指令设置的,只要是z}l,就可以使得je指令发生转移。

CPU提供了cmp指令,也提供了je等条件转移指令,如果将它们配合使用,可以实现根据比较结果进行转移的功能。但这只是“如果”,只是一种合理的建议,和事实上常用的方法。但究竟是否配合使用它们,完全是你自己的事情。这就好像call和ret指令的关系一样。

对于jne. jb, jnb, ja, jna等指令和cmp指令配合使用的思想和je相同,可以自己分析一下。 虽然我们分别讨论了cmp指令和与其比较结果相关的有条件转移指令,但是它们经常在一起配合使用。所以我们在联合应用它们的时候,不必再考虑cmp指令对相关标志位的影响和je等指令对相关标志位的检测。因为相关的标志位,只是为cmp和Je等指令传递比较结果。我们可以直接考虑cmp和je等指令配合使用时,表现出来的逻辑含义。它们在联合使用的时候表现出来的功能有些像高级语言中的IF语句。我们来看下面的一组程序。
data段中的8个字节如下:

data segment
  db 8,11,8,1,8,5,63,38
data ends

(1)编程,统计data段中数值为8的字节的个数,用ax保存统计结果。

编程思路:初始设置(ax)=0,然后用循环依次比较每个字节的值,找到一个和8相等的数就将ax的值加1。程序如下。

   mov ax,data
   mov ds,ax
   mov bx,0            ;ds:bx指向第一个字节
   mov ax,0            ;初始化累加器
   moc cx,8

s: cmp byte ptr [bx],8     ;和8进行比较
   jne next                 ;如果不相等转到next,
   inc ax                   ;如果相等就将计数值加1
next:inc bx
     loo s                  ;程序执行后:(ax)=3

这个程序也可以写成这样:

mov ax,data
mov ds,ax
mov bx,0            ;ds:bx指向第一个字节
mov ax,0            ;初始化累加器
moc cx,8

s:cmp byte ptr [bx],8       ;和8进行比较
   je ok                     ;如果不相等转到next,
  jmp short next             ;如果不相等就转next,继续循环

ok:inc ax                    ;如果相等就将计数值加1

next:inc bx
     loo s                   ;程序执行后:(ax)=3

比起第一个程序,它直接地遵循了“等于8则计数值加1”的原则,用je指令检测等于8的情况,但是没有第一个程序精简。第一个程序用jne检测不等于8的情况,从而间接地检测等于8的情况。要注意在使用cmp和条件转移指令时的这种编程思想。

(2)编程,统计data段中数值大于8的字节的个数,用ax保存统计结果。

编程思路:初始设置(ax)=0,然后用循环依次比较每个字节的值,找到一个大于8的就将ax的值加1。程序如下。

mov ax,data
mov ds,ax
mov ax,0            ;初始化累加器
mov bx,0            ;ds:bx指向第一个字节

moc cx,8

s:cmp byte ptr [bx],8      ;和8进行比较
  jna next                  ;如果不大于8转到 next ,继续循环,
  inc ax                    ;如果大于8就技术组加1
next:inc bx
     loo s              

程序执行后:(ax)=3

(3)编程,统计data段中数值小于8的字节的个数,用ax保存统计结果。

编程思路:初始设置(ax)=0,然后用循环依次比较每个字节的值,找到一个小于8的就将ax的值加to程序如下。

mov ax,data
mov ds,ax
mov ax,0            ;初始化累加器
mov bx,0            ;ds:bx指向第一个字节

moc cx,8

s:cmp byte ptr [bx],8      ;和8进行比较
  jnb next                  ;如果不小于8转到 next ,继续循环,
  inc ax                    ;如果小于8就技术组加1
next:inc bx
     loo s              

程序执行后:(ax)=2
上面讲解了根据无符号数的比较结果进行转移的条件转移指令。根据有符号数的比较结果进行转移的条件转移指令的工作原理和无符号的相同,只是检测了不同的标志位。我们在这里主要探讨的是cmp、标志寄存器的相关位、条件转移指令三者配合应用的原理,这个原理具有普遍性,而不是逐条讲解条件转移指令。对这些指令感兴趣的读者可以查看相关的指令手册。


发布日期:

所属分类: 编程 标签:  


没有相关文章!