汇编基础(4) 程序控制转移

 

程序控制转移

 

 

对于编程来说控制程序走向是非常重要的事情,它是你的程序根据条件

 

作出判断,跳转到相应的位值。

  • 无条件跳转

    控制程序转向的最基本的指令是jJMP
    .

    使用形式如下:
    JMP label

    在程序中声明/label/的方法很简单,只要在它名字后面加上“:”,
    label可以由任何字符混合而成但是不能由数字开头,例如,下面
    是3个合法的label
    label1:
    label2:
    a:
    label可以在一条指令的前面声明,例如:
    x1:
    MOV AX, 1

    x2: MOV AX, 2
    下面是一个 JMP
    指令的例子:

ORG 100h

MOV AX, 5 ; 将 AX 设置为 5.
MOV BX, 2 ; 将 BX 设置为 2.

JMP calc ; 跳转到 'calc'.

back: JMP stop ; 跳转到 'stop'.

calc:
ADD AX, BX ; 将 BX 加到 AX.
JMP back ; 返回 'back'.

stop:

RET ; 返回操作系统

END

当然有更简单的计算这两个数字之和的方法,但是

 

上面是一个JMP指令的很好的例子。

从例子中可以看出,JMP可以控制向前和向后。它可以

 

转移到当前代码段的任意位置(65535字节)。

 

短条件转移

 

 

JMP这一无条件转移指令不同,还有一些有条件跳转

 

指令(只有在条件成立的时侯才跳转)。这些指令分为

 

三组,第一组是只检测单独标记位,第二组比较有符

 

号数,第三组比较无符号数。

 

检测单独标记位的转移指令

 

指令

说明

条件

相反指令

JZ , JE

如果为0(相等),转移 .

ZF =1

JNZ, JNE

JC , JB, JNAE

如果进位 (小于, 不大于等于),转移

 CF = 1

JNC, JNB, JAE

JS

如果是负数,转移

 SF = 1

JNS

JO

如果溢出,转移

 OF = 1

JNO

JPE, JP

如果是偶数,转移

 PF = 1

JPO

JNZ , JNE

如果不为0(不相等),转移

 ZF = 0

JZ, JE

JNC , JNB, JAE

如果没有进位(大于, 大于等于),转移

 CF = 0

JC, JB, JNAE

JNS

如果不是负数,转移

 SF = 0

JS

JNO

如果没有溢出,转移

 OF = 0

JO

JPO, JNP

如果不是偶数,转移

 PF = 0

JPE, JP

 

可以看到一些指令功能相同,对,他们编译之后生成

 

相同机器码所以很容易理解为什么你编译 JE 指令

 

而反编译得到的却是JZ.使用不同的名称是为了使程序更容易理解。

 

比较有符号数的转移指令

 

 

指令

说明

条件

相反指令

JE , JZ

如果等于 (=),如果为0,跳转

ZF = 1

JNE, JNZ

JNE , JNZ

如果不等于 (<>),如果不等于0,跳转

ZF = 0

JE, JZ

JG , JNLE

如果大于 (>) 如果不小于等于 (not <=),跳转

ZF = 0

SF = OF

JNG, JLE

JL , JNGE

如果小与Jump if Less (<) 如果不大于等于 (not >=),跳转

SF <> OF

JNL, JGE

JGE , JNL

如果大于等于 (>=),如果不小于 (not <),跳转

SF = OF

JNGE, JL

JLE , JNG

如果小于等于 (<=),如果不大于 (not >),跳转

ZF = 1

或者

SF <> OF

JNLE, JG

 

<> - 符号表示不等于.

 

 

比较无符号数转移指令

 

 

指令

说明

条件

相反指令

JE , JZ

如果等于 (=).,如果为0,跳转

ZF = 1

JNE, JNZ

JNE , JNZ

如果不等于(<>),如果不为0,跳转

ZF = 0

JE, JZ

JA , JNBE

如果大于 (>),如果不小于等于(not <=),跳转

CF = 0

and

ZF = 0

JNA, JBE

JB , JNAE, JC

如果小于 (<),如果不大于等于(not >=),如果进位,跳转

CF = 1

JNB, JAE, JNC

JAE , JNB, JNC

如果大于等于(>=),如果不小于 (not <),如果没有进位,跳转

CF = 0

JNAE, JB

JBE , JNA

如果小于或者等于(<=),如果不大于 (not >),跳转

CF = 1

or

ZF = 1

JNBE, JA

一般来说,需要使用CMP指令来比较数值(该指令与 SUB(减法)

指令相近,只不过不保存结果,而只修改标值位)

 

上面说法的意思是,例如:

 

需要比较5 和2, 5-2 =3

 

结果不是0(0标值位设置为 0)

 

另一个例子

 

比较 7和7

 

7 - 7 = 0

 

结果为0! (0标值位设置为1JZ 或者 JE 会转移).

 

下面是一个 CMP 指令和条件转移指令的例子:

 


include emu8086.inc
include emu8086.inc

ORG 100h

MOV AL, 25 ; 设置AL为 25.
MOV BL, 10 ; 设置BL为10.

CMP AL, BL ; 比较 AL - BL.

JE equal ; 如果 AL = BL (ZF = 1) 跳转

PUTC 'N' ; 如果到这里,说明 AL <> BL,
JMP stop ; 打印'N', 跳转到结束

equal: ; 如果到这里
PUTC 'Y' ; 则 AL = BL,打印'Y'.

stop:

RET

END

 

 

请用用不同的数字试验取代上述 ALBL,点击[FLAGS]键

 

打开标志,使用[Single Step]观察发生了什么,不要忘记

 

每一次修改之后重新编译运行(快捷键F5)。


全部的条件转移指令都有一个很大的限制,就是与 JMP 指令

 

不同,他们只能向前跳转127字节或者向后跳转128字节(注意

 

大多数指令编译之后是3个或者更多字节)

 

我们可以用如下小技巧解决这一问题:

  • 从上述表中找到一条相反条件的转移指令,令其跳转到 label_x.
  • JMP指令跳转到你想要的地方
  • JMP指令后面定义label_x:

 

label_x: - 可以是任意合法标号.

 

下面是一个例子:

 

 

include emu8086.inc

ORG 100h

MOV AL, 25 ; 设置 AL 为 25.
MOV BL, 10 ; 设置 BL 为 10.

CMP AL, BL ; 比较 AL - BL.


JNE not_equal ; 如果 AL <> BL (ZF = 0),转移
JMP equal
not_equal:


; 假定这里还有编译之后超过127字节的程序


PUTC 'N' ; 如果执行到这里,说明 AL <> BL,
JMP stop ; 打印 'N', 转移到程序结束。

equal: ; 如果执行到这里,
PUTC 'Y' ; 说明 AL = BL, 打印 'Y'.

stop:

RET ; 上述都要执行这一条

END

 


另外,可以使用立即数来代替标号。立即数前使用“$”

 

编译器将直接得到偏移。例如:

 

 

ORG 100h

; 无条件向前转移
; 跳过后面2字节
JMP $2
a DB 3 ; 1 byte.
b DB 4 ; 1 byte.

; JCC 跳过 7 字节:
; (JMP 本身占用 2 字节)
MOV BL,9
DEC BL ; 2 bytes.
CMP BL, 0 ; 3 bytes.
JNE $-7

RET

END

阅读更多
个人分类: 汇编
上一篇汇编基础(3) 运算与逻辑指令
下一篇[推荐] 七个受用一生的心理寓言
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭