汇编语言指令学习之跳转指令JMP和循环指令LOOP

在汇编指令中跳转指令分为两种,一种是无条件跳转指令,一种是有条件跳转指令。

对于前者无条件跳转指令有点类似于高级语言C中的goto语句,goto标志符,无跳转指令的格式也是类似JMP 标号;

对于有条件跳转指令通常都是根据FLAG寄存器的相关状态值SF,OF,AF,PF,CF是否被设置为1或者是0来进行跳转的选择,这个就可以实现相关的分支语句。类似于高级语言中的if等。

(1)无条件跳转指令JMP

基本格式如下:

JMP 标号;

因为在操作系统中我们一般对程序进行分段处理,那么在不同的段就会设置不同的CS寄存器,执行不同指令的过程中实质是设置CS与IP寄存器的值,然后CPU以此来进行指令的取出,由此对于跳转指令我们就分为段内跳转和段间跳转,前者是在一个代码段中,后者是实现不同的代码段的跳转。

首先说一下段间无条件跳转。

段间的无条件跳转的实现原理是:汇编器根据JMP后面设置的标号,计算出标号对应的段内偏移与此时IP寄存器中的值得差值,然后让IP加上该差值,实质就是设置IP的值为该标号对应的段内偏移值。

根据差值所占位的大小我们又分为:无条件段内近转移和无条件段内短转移。

对于前者,偏移与IP的差值大小只占2个字节,后者占1个字节

指令格式分别如下:

无条件段内短转移:JMP SHORT 标号

无条件段内近转移:JMP NEAR PTR 标号

对于这个PTR什么时候需要添加我也不是很清楚,到后面的学习过程中明了后在进行修改。

 

对于无条件转移指令,此时的IP值是通过标号直接设置的,在汇编器解析的时候进行设置,但是有时候我们可以把需要设置的IP值放到通用寄存器或者是存储器中,那么这样就可以实现无条件段内间接跳转指令。

指令的格式如下:

JMP OPRD

其中OPRD可以是通用寄存器,也可是存储单元,寻址方式除了是立即数寻址外,可以是其它的寻址方式。

例如:

JMP AX;JMP [AX];JMP WORD PTR [1234H]等

 

(2)无条件段间跳转

所谓的无条件段间跳转就是通过相关的操作直接设置CS和IP寄存器的值,使得执行不同代码段中的代码

指令格式和上面的大同小异,但是汇编器在进行解析的时候会设置CS和IP的值。

指令分为两种:一种是直接跳转

JMP FAR PTR 标号

一种是间接跳转,通过直接寻址的方式,把存储器中的低字放到IP中,高字放到CS中,指令格式如下

JMP DWORD PTR OPRD

例如:JMP DWORD PTR [1234H],则执行后IP = DS*16+[1234H],CS = DS*16+[1236H]

 

总结了一些JMP跳转指令的相关格式:

格式

描述

举例

类别

说明

jmp 16位寄存器

以16位寄存器的值改变IP

jmp ax

段内转移

 

jmp 段地址:偏移地址

以立即数改变段地址和偏移地址

jmp 0045H:0020H

段间转移

 

jmp short 标号

以标号地址后第一个字节的地址来改变IP,实际上这个功能可以作如下描述:
(IP)=(IP)+8bit位移
8bit位移指的是从jmp指令后第一个字节开始算起

jmp short sign

段内短转移

对IP的修改范围是-128->127,实际算法是编译器根据当前IP指针的指向来计算到底偏移多少个字节来指向下一条指令,下面这段代码就会出编译错误
jmp short s
dw 200 dup(2)
s: mov ax,4
因为跳转超过了范围

jmp near ptr 标号

以标号地址后第一个字的地址来改变IP,
实际上这个功能可以作如下描述:
(IP)=(IP)+16bit位移
16bit位移指的是从jmp指令后第一个字节开始算起

jmp near ptr sign

段内近转移

对IP的修改范围是-32768->32767

jmp far ptr标号

以标号的段地址和指令地址同时改变CS和IP

jmp far ptr sign

段间转移

 

jmp word ptr 内存地址

以内存地址单元处的字修改IP,内存单元可以以任何合法的方式给出

jmp word ptr ds:[si]
jmp word ptr ds:[0]
jmp word ptr [bx]
jmp word ptr [bp+si+idata]

段内转移

 

jmp dword ptr内存地址

以内存地址单元处的双字来修改指令,高地址内容修改CS,低地址内容修改IP,内存地址可以以任何合法的方式给出

jmp dword ptr [bx]

段间转移

s1 segment
dw 0a0bh, 0c0dh
s1 ends

mov ax,s1
mov ds,ax
jmp dword ptr ds:[0]

对于JMP 段地址:偏移地址,并不是所有的MASM都支持的,需要依据实际的形式来判断。

 

 

上面我们看到了段内的无条件跳转指令,但是和很多高级语言进行对比,我们在很多时候都是通过条件的判断来决定是否需要进行跳转,同样在汇编指令中也提供了相关的条件跳转指令,我们现在一一进行介绍:

 

明确一下,在汇编指令中N代表的是否。同时进行条件跳转的指令都是段内跳转,因此有短和近跳转了撒!

(1)根据标识FLAG寄存器来判断是否需要进行跳转

我们根据前面的需要知道相关的算术运算、逻辑运算、移位运算(部分指令会影响CF)都会影响FLAG寄存器中的部分标识位的值,那么根据这些标志位我们可以判断是否需要进行跳转,譬如CMP AX,BX是判断AX和BX的大小,那么通过相关设置的标志位我们就可以判断是AX大还是BX大,然后决定是否需要转移嘛,这就是所谓的分支语句了撒!

对于有符号数分大于(G-great),等于(E-equal),小于(L-light)

对于无符号数分为大于(A),等于(E),小于(B)

根据标志位跳转的指令:

JE ;等于则跳转
JNE ;不等于则跳转
JZ ;为 0 则跳转 (ZF)
JNZ ;不为 0 则跳转 
JS ;为负则跳转 (SF)
JNS ;不为负则跳转 
JC ;进位则跳转 (CF)
JNC ;不进位则跳转 
JO ;溢出则跳转(OF)
JNO ;不溢出则跳转
JA ;无符号大于则跳转 
JNA ;无符号不大于则跳转 
JAE ;无符号大于等于则跳转 
JNAE ;无符号不大于等于则跳转 
JG ;有符号大于则跳转 
JNG ;有符号不大于则跳转 
JGE ;有符号大于等于则跳转
JNGE ;有符号不大于等于则跳转
JB ;无符号小于则跳转 
JNB ;无符号不小于则跳转
JBE ;无符号小于等于则跳转 
JNBE ;无符号不小于等于则跳转 
JL ;有符号小于则跳转 
JNL ;有符号不小于则跳转 
JLE ;有符号小于等于则跳转
JNLE ;有符号不小于等于则跳转 
JP ;奇偶位置位则跳转 (PF)
JNP ;奇偶位清除则跳转
JPE ;奇偶位相等则跳转 
JPO ;奇偶位不等则跳转
跳转相关的标志位:
11109876543210
OFDFIFTFSFZF AF PF CF

   







通过上面的跳转指令我们就可以实现简单的分支和循环,例如
MOV CX,10H

NEXT:

     ........

     DEC CX

     JNZ NEXT

实现的是执行NEXT中的代码段10次

 

但是通过自己手动的写相关的循环语句有时候很复杂,增加了编码的难度,因此在汇编指令中有了如下的专门的循环指令,如下所示:

LOOP = CX不为零的时候进行跳转

LOOPE/LOOPZ = CX不为零并且相等的时候跳转

LOOPNE/LOOPNZ = CX不为零并且不相等的时候跳转

LCXZ  CX为零的时候跳转

 

通过相关的循环+跳转语句就可以实现高级语言中的分支语句和循环语句的执行了

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
LOOP 指令的语法格式如下: ``` LOOP label ``` 其 `label` 是指定的标签名称,LOOP 指令的作用是将 CX 寄存器的值减 1,然后检查 CX 寄存器的值是否为 0,如果 CX 寄存器的值不为 0,则跳转到指定的标签处执行,否则继续执行下一条指令。 下面是一个简单的示例程序,使用 LOOP 指令实现从 10 数到 1: ``` section .data msg db 'Countdown: ', 0Ah ; 0Ah 表示换行符 section .text global _start _start: mov cx, 10 ; 将 CX 寄存器的值初始化为 10 mov ah, 0x0e ; 设置文本输出的功能号 jmp start_loop ; 跳转循环开始处 print_num: ; 输出当前的数字 add al, '0' ; 将数字转换为字符 int 0x10 ; 调用 BIOS 断显示字符 dec cx ; 将 CX 寄存器的值减 1 start_loop: mov al, cl ; 将 CX 寄存器的值存入 AL 寄存器 cmp al, 0 ; 比较 AL 寄存器的值是否为 0 jz exit ; 如果为 0,跳转到程序结束处 mov ah, 0x0e ; 设置文本输出的功能号 mov bl, 0 ; 将 BL 寄存器的值清零 div bl ; 将 AL 寄存器的值除以 BL 寄存器的值,余数存入 AH 寄存器 add al, '0' ; 将商转换为字符 int 0x10 ; 调用 BIOS 断显示字符 cmp cx, 1 ; 比较 CX 寄存器的值是否为 1 jnz print_num ; 如果不为 1,跳转到输出当前数字的代码处 exit: mov ah, 0x0e ; 设置文本输出的功能号 mov al, 0Ah ; 将换行符存入 AL 寄存器 int 0x10 ; 调用 BIOS 断显示字符 mov ah, 0x4c ; 设置程序结束的功能号 xor al, al ; 将 AL 寄存器的值设置为 0 int 0x21 ; 调用 DOS 断结束程序 ``` 在上面的代码,LOOP 指令被用来控制从 10 数到 1 的循环。具体来说,通过 MOV 指令将 CX 寄存器的值初始化为 10,然后在 start_loop 标签处使用 CMP 指令比较 AL 寄存器和 0,如果 AL 寄存器的值为 0,则跳转到程序结束处;否则使用 INT 0x10 断显示当前数字,然后使用 DEC 指令将 CX 寄存器的值减 1,再次使用 LOOP 指令跳转到 start_loop 标签处执行。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值