x86条件转移指令loop和无条件转移指令jmp

默认情况下,CPU加载程序并按顺序执行其中的指令。但是,当前正在执行的指令有可能是条件处理指令,这也就意味着当前指令有可能会根据CPU的状态标志值(零标志、符号标志、进位标志等)把控制权转移到程序中的一个新的地址处。汇编语言程序使用条件处理指令实现高级语言中的条件处理(IF)语句和循环语句。每种条件处理语句都有可能导致控制转移到(跳转到)内存中的一个新地址处。控制转移(transfer of control),或者说分支转移(branch),是一种改变语句执行顺序的方法。控制转移可分为两种:

1.无条件转移:无论在何种情况下,程序都转移到一个新的地址,指令指针中装入一个新值,CPU在新的地址继续执行。JMP指令就是一个很好的例子。

2.条件转移:如果特定条件满足则程序转移。Intel提供了大量的条件转移指令,这些指令结合起来可以创建各种条件逻辑结构。CPU根据ECX寄存器和标志寄存器的内容解释条件的真或假。

 

下面分别介绍JMP指令和LOOP指令:

JMP指令:

JMP指令向代码段的目的地址做无条件转移。标识目的地址的代码标号将由汇编翻译成偏移地址,JMP指令的格式是:JMP 目的地址

CPU执行无条件转移指令时,目标标号的偏移地址被装入指令指针中,CPU立即开始在新的地址继续执行指令。通常情况下,JMP指令只能跳转到当前过程内的标号处。

  创建一个循环:JMP指令提供了一种创建循环的简单方法,只要跳到循环顶端的标号处就可以了:

 

top:

    .

    .

    jmp  top  ;无限循环

JMP指令是无条件的,因此循环会永无休止地持续下去,直到满足其他条件退出为止。

 

LOOP指令:

LOOP指令重复执行一块语句,执行的次数是特定的,ECX被自动用做计数器,在每次循环之后减1,格式如下:

LOOP  目的地址

LOOP指令的执行包含两步:首先,ECX减1,接着与0相比较。如果ECX不等于0,则跳转到目的地址(标号)处;如果ECX等于0,则不发生跳转,这时控制权将转移到紧跟在LOOP指令后面的指令处。

    在实地址模式下,用做默认循环计数器的是CX寄存器。不论是在实地址模式还是保护模式下,LOOPD指令总是使用ECX作为循环计数器,而LOOPW总是使用CX作为循环计数器。

 

如下例:每次执行循环时AX加1,当循环结束的时候AX=5,ECX=0:

mov ax,0

mov ecx,5

L1:

    inc ax

    loop L1

常见的变成错误时在循环开始之前将ECX初始化为0.这种情况下,LOOP指令执行后,ECX减1得到FFFFFFFFh,结果是循环将重复4294967296次!如果是用CX做循环计数器,循环将重复65535次。

 

循环的目的地址与当前地址只能在相距-128~+127字节的范围之内。机器指令的平均大小是2字节左右,因此一个循环平均最多只能包含大约42条指令。下面语句是由于LOOP指令的目的标号地址距离过远时MASM产生的错误信息:

error A2075:jump destination too far: by 14byte(s)

如果在循环内修改了ECX的值,LOOP指令就有可能无法正确工作了。下例中ECX在循环中加1,因此执行LOOP指令后ECX永远不会为0(ECX的初始值不为0),循环也就永远不会结束:

top:

     .

     .

inc ecx

loop top

如果用完了所有的寄存器,但又因为种种原因必须使用ECX寄存器的话,可以在循环的开始把ECX保存在变量中并在LOOP指令之前将其恢复:

.data

count dword ?

.code

      mov ecx,100  ;设置循环计数

top:

      mov count,ecx  ;保存循环计数

      .

      mov ecx,20   ;修改ECX

      .

      mov ecx,count  ;恢复循环计数

      loop top

循环的嵌套:在循环内创建另一个循环的时候,必修考虑ECX中的外层循环计数该如何处理。一个较好的解决方案是把外层循环的计数保存在一个变量中:

.data

count dword ?

.code

    mov ecx,100  ;设置外层循环计数

L1:

    mov count,ecx  ;保存完成循环计数

    mov ecx,20  ;设置内层循环计数

L2:

     .

     .

     loop L2 ;重复内层循环

     mov ecx,count  ;恢复外层计数

     loop L1  ;重复外层循环

作为一条一般性的规则,应尽量避免使用嵌套深度超过两层的循环。否则,管理循环计数将使人头痛。如果算法要求多层循环嵌套的话,可以把一部分内层循环代码移到子程序中。

下面给出两个例子:

1.整数数组求和

刚开始编程时,大概没有比计算数组元素之和更常见的任务了。在汇编语言中,可按照以下步骤:

1)把数组的起始地址送入一个寄存器,这个寄存器将用在变址操作数中。

2)ECX设置为数组中元素的数目(16位模式下使用CX)。

3)把另外一个寄存器清零用于保存累加和。

4)创建一个标号标识循环的开始。

5)在循环体中,用间接寻址方式把数组的每个元素同用于存放累加和的寄存器相加。

6)变址寄存器指向下一个数组元素。

7)使用LOOP指令重复执行由开始标号标明的循环体。

前3步的顺序可以任意调整。

.data

intarray word 100h,200h,300h,400h

.code

main proc

    mov edi,offset intarray ;intarray的地址

    mov ecx,lengthof intarray;循环计数器

    mov ax,0  ;累加器清零

L1:

    add ax,[edi]  ;加上一个整数

    add edi,type intarray ;指向下一个整数

    loop L1  ;重复循环直到ECX=0为止

    exit

main endp

end main

2.复制字符串

   程序经常要从一个地址向另一个地址复制大块的数据,数据通常是字符串,但也可能是任何其他类型的对象。通过下面的使用循环进行字符串复制的例子,让我们看看在汇编语言中如何实现类似的复制功能的。进行这种类型的操作很适合适合使用变址寻址,因为两个字符串都能用同一个变址寄存器来索引。目的串必须有足够的空间容纳复制过来的字符串,包括尾部的空字符:

.data

source byte "This is the source string",0

target byte sizeof source dup(0),0

.code

main proc

    mov esi,0  ;变址寄存器

    mov ecx,sizeof source ;循环计数器

L1:

    mov al,source[esi];从源中取一个字符

    mov target[esi],al;将该字符存储在目的中

    inc esi;移到下一个字符

    loop L1;重复复制整个字符串

    exit

main endp

end main

 

mov指令不能同时对两个内存操作数进行操作,因此每个字符首先从源字符串送至AL,然后再从AL送到目的字符串中。

 

 

 

---------------完毕。欢迎交流。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值