《汇编语言(第四版)》—王爽 第九章转移指令的原理
9.1、操作符offset
8086CPU的转移指令分为以下的几类:
- 无条件跳转指令(jmp指令)
- 条件跳转
- 循环指令
- 过程
- 中断
offset操作符在汇编语言中是由编译器处理的符号,他的功能时取得标号的偏移地址
将s处的代码复制给s0处
assume cs:code
code segment
s:mov ax,bx
mov si,offset s ;这个意思就是将s处的偏移地址给si
mov di,offset s0 ;这个意思就是将s0处额度偏移地址给di
mov ax,cs:[si] ;意思是将cs:ip这个关于代码的定位给到ax
mov cs:[di],ax ;将s处的代码复制给s0处
s0:nop ;nop 的机器码占一个zi'jie
nop
code ends
end
9.2、jmp指令
jmp是无条件跳转指令,可以只修改ip,也可以同时修改cs和ip
jmp指令要给出两种信息:
- 转移的目的地址
- 转移的举例(段间转移,段内短转移,段内近转移)
9.3、依据位移进行转移的jmp指令
jmp short 标号(转移到标号处执行指令)
这种格式的jmp指令实现的是段内短转移,他对于IP的修改范围为-128~127,也就是说,他向前转移可以最多越过128个字节,向后转移可以最大越过127个字节
start:mov ax,0
jmp short s
add ax,1
s:inc ax
分析:这里的jmp指令直接跳转至标号为s处,跳过了add ax,1所以这个汇编程序中只执行一次的ax = ax + 1
如果机器指令中不包含目的地址的话,那么也就是说COU不需要这个目的地址就可以实现对IP的修改
jmp short s指令的读取和执行的过程:
(1)(CS) = 0BBDH (IP) = 0006 ,CS:IP指向EB03(jmp short s 的机器码)
(2)读取指令码EB03进入指令缓冲器中
(3)(IP) = (IP) + 所读取的指令的长度 = (IP) +2 = 0008,CS:IP指向add ax,1
(4)CPU执行指令缓冲寄存器中的指令EB03,即将机器码中的偏移量给到IP中使得IP的值变为0008 + 03 = 0B
(5)指令EB03执行后,(IP) = 000BH,CS:IP指向INC AX
实际上,指令“jmp short 标号”的功能为 (IP) = (IP) + 8位的位移
- short指明此处的位移为8位位移
- 8位位移的范围为-128~127,用补码表示
- 8位位移由编译程序在编译时算出
jmp near ptr 标号
它实现的时段内近转移
指令的功能为:
- (IP) = (IP) + 16位位移
说明:
-
16位位移 = “标号”处的地址 - jmp指令后的第一个字节的地址
-
near ptr 指明此处的位移为16位位移,进行的是段内近转移
-
16位位移的范围为-32769~32767,用补码表示
-
16位位移由编译程序在编译时算出
9.4、转移的目的地址在指令中的jmp指令
前面讲的jmp指令,其对应的机器码中并没有转移的目的地址,而是相对于当前IP的转移指令
指令“jmp far ptr 标号”实现的是段间的转移,又称为远转移
功能:
- (CS) = 标号所在段的段地址
- (IP) = 标号所在段的偏移地址
- far ptr 指明了指令用标号的段地址和偏移地址修改CS和IP
assume cs:code
code segment
start: mov ax,0
mov bx,0
jmp far ptr s
db 256 dup(0)
S:add ax,1
inc ax
code ends
end start
可以看出在jmp指令其中为 0BBD:010B,表示的是CS的值为0BBD以及IP的值为010B,此时我们观察机器指令,机器指令中显示的是EA0B01BD0B此时这个机器码中表示的0B01其实是按照高位以及低位的方式
9.5、转移地址在寄存器中的jmp
指令格式:jmp 16位寄存器
功能:IP = (16位寄存器)
9.6、转移地址在内存中的jmp指令
转移地址在内存中的jmp格式有两种:
(1)jmp word ptr 内存单元地址(段内转移)
功能:从内存单元地址处开始存放着一个字,是转移的目的偏移地址
内存单元地址可用寻址方式的任一格式给出
示例
mov ax,0123H
mov ds:[bx],ax
jmp word ptr ds:[bx] ;表示的是偏移地址存储在ds:[bx]中
执行之后(IP) = 0123H
(2)jmp dword ptr 内存单元地址(段间转移)
功能:从内存单元地址处开始存放着两个字,高地址处的字位转移的目的段地址,低地址处是转移的目的偏移地址
(CS) = (内存单元地址 + 2)
(IP) = (内存单元地址)
内存单元地址可用寻址方式的任一格式给出
示例:
mov ax,0123H
mov ds:[0],ax ;ax为16位的寄存器存放[0][1]中
mov word ptr ds:[2],0 ;将0存储在[2][3]中
jmp dword ptr ds:[0]
分析:[2][3]相比[0][1]来讲是作为高位,高位存放的是目的地址的段地址,而低位存储的是偏移地址
执行之后
(CS) = 0
(IP) = 0123H
CS:IP指向的0000:0123H
9.7、jcxz指令
jcxz指令为有条件的跳转指令,所有的有条件跳转指令都是短转移,在对应的机器码中包含转移的位移,而不是目的的地址,对IP的修改范围位-128~127
指令格式:
jcxz 标号
如果(CX) = 0,则转移到标号处执行
- 当·(CX) = 0时,(IP) = (IP)+8位位移
- 8位位移 = “标号”处的地址 - jcxz指令后的第一个字节的地址
- 8位位移的范围为-128~127,用补码进行表示
- 8位位移是由编译器在编译时算出
- 当(CX) != 0,什么也不做
我们从jcxz的功能中可以看出,指令jcxz 标号的功能相当于一个判断语句
if((CX) = 0){
JMP short 标号;
}
9.8、loop指令
loop指令位循环指令,所有的循环指令都是段转移,对应的机器码中包含转移的位移,而不是目的地址
对IP的修改范围为-128~127
指令格式:loop 标号
((CX)) = (CX) -1,如果CX的值不为0,则转移到标号处执行
loop 标号 指令操作:
- (CX) = (CX) - 1
- 如果(CX) != 0,(IP) = (IP) + 8位位移
- 8位位移 = “标号”处的地址 - loop指令后的第一个字节的地址
- 8位位移的范围为-128~127,用补码表示
- 8位位移由编译器编译程序时算出
- 当(CX) = 0,什么也不做(程序向下执行)
loop指令就相当于
(CX)--;
if ((CX) != 0){
jmp short 标号;
}
9.9、根据位移进行转移的意义
我们前面学到的汇编指令中,它们对IP的修改是根据转移目的地址和转移起始地址之间的位移来进行的在他们对应的机器码中,不包含转移目的地址,而包含的时到目的地址的位移的距离
这样设计是为了方便车光绪段在内存中的浮动装配
例如:
mov cx,6
mov ax,10
s:add ax,ax
loop s
在这段程序中,在内存中的不同位置都可以执行,因为loop s只涉及到s的位移,而不是s的地址
如果将s固定为一个地址那么此时只能在某处进行执行,否则就会发生错误
注意:根据位移进行转移的指令,它们的转移范围受到转移位移的限制,如果在源程序中出现了转移范围超界的问题,在编译的时候,编译器将报错