汇编语言指令 jmp:jmp short、jmp near ptr、jmp far ptr

引言:

        在8086CPU中,可以修改IP(Instruction Pointer ,指令指针寄存器)或同时修改CS(Code Segment,代码段寄存器)和IP的指令称为转移指令,更通俗的说,转移指令就是控制CPU执行内存中某处代码的指令。jmp 指令就属于转移指令中其中的一员,而且是无条件转移的。

        为了更加清晰明了的解读汇编语言中的转移指令 jmp,我们还需要了解一下CPU执行指令的过程:

(1)从CS:IP指向的内存单元中读取指令,读取的指令放入CPU的指令缓冲区中;

(2)修改IP的值,(IP) = (IP) + 所读取到指令的指令的长度(以字节为单位),从而使IP指向下一条指令;

(3)执行指令缓冲区中的指令

(4)转到步骤(1),重复执行这个过程

1. 根据位移进行转移的 jmp 指令

        根据位移进行转移的 jmp 指令是段内转移指令,即只修改IP的转移指令,位移是相对于当前 IP 的转移位移,根据转移的位移范围,分为段内短转移(jmp short 标号)和段内近转移(jmp near ptr 标号)

1.1 jmp short 标号

        jmp short 标号是段内短转移指令,该汇编指令的功能是转到标号处执行指令,其对应的机器指令码由2个字节表示,低8位表示该指令是段内短转移指令,高8位表示位移,位移范围在 -128 ~ 127 之间,也就是向前转移时,最多越过128个字节,向后转移时最多越过127个字节。基本原理如下:

(1) short指明此处的位移为8位位移,8位位移用补码形式表示,位移范围在 -128 ~ 127 之间;

(2)(IP)=(IP)+8位位移(补码形式表示);

(3)8位位移由编译程序在编译时算出,8位位移 = 标号所在处的指令的首地址 - jmp指令所在处的下一条指令的首地址(因为根据文章开头所描述的CPU执行指令的过程可以知道,CPU执行存储在指令缓冲区中的 jmp 指令前,IP已经指向 jmp 指令的下一条指令)。

;jmp short 标号     基本原理
                    ;1. short指明此处的位移为8位位移,8位位移用补码形式表示,位移范围在 -128 ~ 127 之间
                    ;2. (IP)=(IP)+8位位移(补码形式表示)
                    ;3. 8位位移由编译程序在编译时算出,8位位移 = 标号所在处的指令的首地址 - jmp指令所在处的下一条指令的首地址
assume cs:code
code segment
start:
    mov ax, 0       ;机器码:B80000,3字节
    jmp short s     ;机器码:EB03,2字节
    add ax, 2       ;机器码:050200, 3字节
s:  inc ax          ;机器码:40h,1字节

    mov ax, 4c00h   ;机器码:B8004C, 3字节
    int 21h         ;机器码:CD21, 2字节
code ends
end start

注意到红长方形框出来的机器指令了吧,汇编指令:jmp short s 被编译器预编译后生成:JMP     0008(jmp s标号指令所在的首地址),编译最后生成的机器指令为:03EB,低8位 EBh 代表的是jmp的段内短转移指令(参考8086CPU的对应的指令编码表可知),高8位 03h 就是要转移的位移。

(1)标号所在处的指令的首地址 - jmp指令所在处的下一条指令的首地址 = 8位位移,

即 0008h - 0005h = 03h;

(2)明白:jmp short 标号 为什么叫段内短转移指令,转移的位移范围为:-128 ~ 127 了吧,因为该汇编指令对应的机器指令的低8位表示的就是段内短转移指令,而且只有一个字节(即8位)来表示位移信息,用补码的形式表示,能够表达的范围就是:-128 ~ 127。

补充知识点

原码:数据在计算机中的二进制表示形式,即用最高位存放符号,正数为0,负数为1。其余位表示值。例如,一个字节的十进制数,3 的原码:0000,0011。 一个字节的十进制数,-3 的原码:1000,0011。 

反码: 正数的反码就是它的原码;

         负数的反码是在其原码的基础上, 符号位不变,其余各个位取反。

例如,一个字节的十进制数,3 的反码:0000,0011。 一个字节的十进制数,-3 的反码:1111,1100。

补码:正数的补码就是它的原码;负数的补码 = 反码 + 1

例如,一个字节的十进制数,3 的补码:0000,0011。 一个字节的十进制数:-3 的补码:1111,1100 + 0000,0001 = 1111,1101。

1.2 jmp near ptr 标号

          jmp near ptr 标号是段内近转移指令,该汇编指令的功能是转到标号处执行指令,其对应的机器指令码由3个字节表示,低8位表示该指令是段内近转移指令,高16位表示位移,位移范围在 -32768 ~  32767 之间,也就是向前转移时,最多越过32768 个字节,向后转移时最多越过32767 个字节。其基本原理跟 jmp short 标号 的基本原理差不多:

(1) near ptr 指明此处的位移为16位位移,16位位移用补码形式表示,位移范围在 -32768 ~ 32767 之间;

(2)(IP)=(IP)+16位位移(补码形式表示);

(3)16位位移由编译程序在编译时算出,16位位移 = 标号所在处的指令的首地址 - jmp指令所在处的下一条指令的首地址(因为根据文章开头所描述的CPU执行指令的过程可以知道,CPU执行存储在指令缓冲区中的 jmp 指令前,IP已经指向 jmp 指令的下一条指令)。

;jmp near ptr 标号   基本原理
                    ;1. near ptr 指明此处的位移为16位位移,16位位移用补码形式表示,位移范围在 -32768 ~ 32767 之间
                    ;2. (IP)=(IP)+16位位移(补码形式表示)
                    ;3. 16位位移由编译程序在编译时算出,16位位移 = 标号所在处的指令的首地址 - jmp指令所在处的下一条指令的首地址
assume cs:code
code segment
start:
    mov ax, 0       ;机器码:B80000,3字节
    jmp near ptr s  ;编译器预编译后变成:jmp s标号所在处的地址
                    ;编译后生成的机器码有3个字节为:低8位表示段内近转移指令,高16位为转移位移
    dw 100 dup (0)
s:  inc ax          ;机器码:40h,1字节

    mov ax, 4c00h   ;机器码:B8004C, 3字节
    int 21h         ;机器码:CD21, 2字节
code ends
end start

从上面红色圈出的部分细节,我们可以知道,汇编指令:jmp near ptr s 被编译器预编译后生成:JMP     00CE(jmp s标号指令所在的首地址),编译最后生成的机器指令为:00C8E9,低8位 E9h 代表的是jmp的段内近转移指令(参考8086CPU的对应的指令编码表可知),高16位 00C8h 就是要转移的位移。

(1)标号所在处的指令的首地址 - jmp指令所在处的下一条指令的首地址 = 16位位移,

即 00CEh - 0006h = 00C8h;

(2)明白:jmp near ptr 标号 为什么叫段内近转移指令,转移的位移范围为:-32768 ~ 32767了吧,因为该汇编指令对应的机器指令的低8位表示的就是段内近转移指令,而且用2个字节(即16位)来表示位移信息,用补码的形式表示,能够表达的范围就是:-32768 ~ 32767。

可能好奇心比较强的你,会不会有个疑问,如果 jmp near ptr s 的转移范围在 -128 ~ 127 之间呢,答案是编译器会优化成段内短转移指令 jmp short s(2个字节),同时把多出来的一个高字节单元用 NOP 填充(因为jmp near ptr 标号其对应的机器指令码由3个字节表示,所以多出来的一个没用到的高字节单元用NOP指令填充)。注:NOP(no operation),汇编语言的字节填充指令,该指令占一个字节单元。

;jmp near ptr 标号   基本原理
                    ;1. near ptr 指明此处的位移为16位位移,16位位移用补码形式表示,位移范围在 -32768 ~ 32767 之间
                    ;2. (IP)=(IP)+16位位移(补码形式表示)
                    ;3. 16位位移由编译程序在编译时算出,16位位移 = 标号所在处的指令的首地址 - jmp指令所在处的下一条指令的首地址
assume cs:code
code segment
start:
    mov ax, 0       ;机器码:B80000,3字节
    jmp near ptr s  ;转移范围在 -128 ~ 127 之间,编译器会将该指令优化为:
                    ;jmp short s
                    ;NOP
    add ax, 2       ;机器码:050200, 3字节
s:  inc ax          ;机器码:40h,1字节

    mov ax, 4c00h   ;机器码:B8004C, 3字节
    int 21h         ;机器码:CD21, 2字节
code ends
end start

(1)标号所在处的指令的首地址 - jmp指令所在处的下一条指令的首地址 = 8位位移,

即 0009h - 0005h(即NOP指令的首地址) = 0004h;

(2)该汇编指令经过编译器生成的机器指令为:04EBh 和 1个字节填充指令NOP,即 90h 组成。

2. 根据目的地址进行转移的 jmp 指令

2.1 jmp far ptr 标号

        jmp far ptr 标号是段间转移指令(又称远转移指令),该汇编指令的功能是转到标号处执行指令,其对应的机器指令码由5个字节表示,低8位表示该指令是段间近转移指令,高16位表示段地址,中间16位表示偏移地址。其基本原理如下:

(1)far ptr 指明了该指令用标号的段地址和偏移地址修改CS和IP;

(2)(CS) = 标号所在段的段地址,(IP) = 标号在段中的偏移地址

assume cs:code
code segment
start:
    mov ax, 0
    jmp far ptr s   ;转到标号s处执行指令
    dw 100 dup (0)  ;定义100个dw类型数据,其值为0,占200个字节
s:  inc ax

    mov ax, 4c00h
    int 21h
code ends
end start

jmp far ptr s 被预编译成了 jmp 204D:00D0,最终生成的机器码为:204D00D0EA,低8位:EA是jmp的段间转移指令编码(参考8086CPU的对应的指令编码表可知),高16位:204D是标号s所在的段地址(CS = 204D),中间16位:00D0是标号S在所在段内的偏移地址(IP = 00D0)

现在有个疑问,如果 jmp far ptr s 的转移范围在 -128 ~ 127 之间呢,答案是编译器会优化成段内短转移指令 jmp short s(2个字节),同时把多出来的3个高字节单元用 NOP 填充(因为jmp far ptr 标号其对应的机器指令码由5个字节表示,所以多出来的3个没用到的高字节单元用NOP指令填充)。注:NOP(no operation),汇编语言的字节填充指令,该指令占一个字节单元。

assume cs:code
code segment
start:
    mov ax, 0
    jmp far ptr s   ;转到标号s处执行指令
    add ax, 2
s:  inc ax

    mov ax, 4c00h
    int 21h
code ends
end start

(1)标号所在处的指令的首地址 - jmp指令所在处的下一条指令的首地址 = 8位位移,

即 000Bh - 0005h(即NOP指令的首地址) = 0006h;

(2)该汇编指令经过编译器生成的机器指令为:06EBh 和 3个字节填充指令NOP,即 90h 90h 90h 组成。

3.总结

1. jmp short 标号 是根据位移进行转移的段内短转移指令,只修改IP的值,其机器码有2个字节,低8位是用于表示jmp的段内短转移指令的指令编码,高8位是用补码形式表示的位移信息,转移的范围:-128 ~ 127

2. jmp near ptr 标号 是根据位移进行转移的段内近转移指令,只修改IP的值,其机器码有3个字节,低8位是用于表示jmp的段内近转移指令的指令编码,高16位是用补码形式表示的位移信息,转移的范围:-32768 ~ 32767

3. jmp far ptr 标号 是根据目的地址进行转移的段间转移指令(又称为远转移指令),可以同时修改CS和IP,其机器码有5个字节,低8位用于表示jmp的段间转移指令的指令编码,高16位用于表示转移的目的段地址CS,中间16位用于表示转移的偏移地址IP

所以,在实际开发过程中

1. 如果只段内转移(只修改IP)时

(1)相对于当前 IP 的转移位移在 -128 ~ 127 之间时,选择用段内短转移指令 jmp short 标号,CPU的执行效率是最高的。

(2)相对于当前 IP 的转移位移在 -32768 ~ 32767 之间时,选择用段内近转移指令 jmp near ptr 标号,CPU的执行效率是最高的。

2. 如果是段间转移(同时修改CS和IP)时,那就选择用段间转移指令(远转移)jmp far ptr 标号

参考文献

《汇编语言(第4版)》王爽

  • 22
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值