转移指令
修改IP,或者同时修改CS和IP的指令系统称为转移指令
内转移
只修改IP时,称为段内转移,比如:jmp ax
段间转移
同时修改CS和IP时,称为段间转移, 比如:jmp 1000:0
短转移
只修改IP的转移,范围为-128~127
近转移
只修改IP的转移,范围为:-32768~32767
转移指令的分类
- 无条件转移指令
- 条件转移指令
- 循环指令
- 过程
- 中断
操作符offset
取得标号的偏移地址
例如:
assume cs:codesg
codesg segment
start:
mov ax, offset start
s:
mov ax, offset s
codesg ends
endstart
nop
机器码占用一个字节
根据位移进行转移的jmp指令,short
jmp short 标号(转到标号处执行指令) (IP) = (IP) - 8位位移
- 8位位移=标号处的地址-jmp指令后的第一个字节的地址
- short指明此处的位移为8位位移
- 8位位移由编译程序在编译时算出
jmp 标号的机器码可以手动算出来,比如下面的例子
assume cs:codesg
codesg segment
start:
mov ax, offset start
s:
mov ax, offset s
jmp short start ; 对应的机器码就为 当前语句的IP地址 - start的IP地址,然后转换为补码
codesg ends
endstart
jmp near ptr 标号
它实现的是段内近转移
- 16位位移 = 标号处的地址-jmp指令后的第一个字节的地址
- near ptr指明此处的位移位16位位移,进行的是段内近转移
- 16位位移的范围为-32767~32767
- 16位位移由编译程序在编译时算出
jmp short 标号
和jmp near ptr
都是相对于当前IP的转移位移
jmp far ptr 标号
实现的是段间转移,又称为远转移
- CS = 标号所在段的段地址
- IP = 标号在段中的偏移地址
- far ptr 指明了用标号的短地址和偏移地址修改CS和IP
指令的地址在寄存器中jmp 16位reg
jmp 16位reg
功能:IP = 16位REG
转移地址在内存中的指令jmp word ptr 地址|[bx|idata]
从内存单元地址处开始存放着一个字,是转移的目的偏移地址
例如:
mov ax, 0123h
mov ds:[0], ax
jmp word ptr ds:[0]
执行后IP= 0123h
又比如
mov ax, 0132h
mov [bx], ax
jmp word ptr [bx]
执行后IP= 0123H
jmp dwrod ptr内存单元地址(段间转移)
功能:从内存单元地址处开始存放着两个字,高地址处的字是转移的目的段地址,低地址处是转移的目的偏移地址。
- CS = 内存单元地址 + 2
- IP = 内存单元地址
例如:
mvo ax, 0123h
mov ds:[0], ax
mov word ptr ds:[2], 0
jmp dword ptr ds:[0]
执行后,CS = 0, IP= 0123H,CS:IP指向0000:0123
又比如
mov ax, 0123h
mov [bx], ax
mov word ptr [bx + 2], 0
jmp dword ptr [bx]
执行后:CS = 0, IP = 0123H, CS:IP指向:0000:0123
条件转移指令 jcxz
jcxz为有条件转移指令,所有的条件转移指令都是短转移,在对应的机器码中包含转移的位移,而不是目的地址。对IP的修改范围为
-128-127
指令格式: jcxz 标号(如果(cx)=0,转移到标号处执行)
操作:当(cx)=0时,(IP)=(IP) + 8 位位移
8位位移=标号处的地址-jcxz指令后的第一个字节地址
8位位移的范围为-128-127,用补码表示
8位位移由编译程序在编译时算出
jcxz 标号相当于
if ((cx) == 0) jmp short 标号;
例如:
assume cs:code
data segment
db 1, 1, 1, 0
data ends
code segment
start:
mov ax, data
mov ds, ax
mov bx, 0
s:
mov cx, [bx]
jcxz ok ; 判断cx是否为0
inc bx
jmp short s
ok:
mov dx, bx
mov ax, 4c00h
int 21h
code ends
end start
loop指令
loop指令为循环指令,所有的循环指令都是短转移, 在对应的机器码中包含转移的位移,而不是目的地址。对IP的修改范围为:-128~127
指令格式: loop 标号((cx) = (cx) - 1, 如果(cx)不等于0,则转移到标号处执行)
指令相当于
(cx)--
if ((cx) != 0) jmp short 标号
根据位移的指令
jmp short 标号
jmp near ptr 标号
jcxz 标号
loop 标号
位移如果复制到其他地方执行,一定要考虑好距离,否则会发生乱跳的结果
他们对IP的修改是根据转移目的地址和转移其实地址之间的位移来进行的。他们对应的机器码中不包含转移的目的地址,而包含的是目的地址的位移。这样设计,方便了程序段在内存中的浮动装配。
CALL 和 RET 指令
ret指令用栈中的数据,修改IP的内容,从而实现 近转移
CPU执行RET指令的时候需要进行两步操作
(IP)=((ss) * 16 + (SP))
(sp) = (sp) + 2
相当于执行
POP IP
retf指令用栈中的数据,修改CS和IP的内容,从而实现远转移
CPU在执行retf指令时,进项下面4步操作
(IP) = ((SS) * 16 + (SP))
(SP) = (SP) + 2
(CS) = ((SS) *16 + (SP))
(SP) = (SP) + 2
相当于执行
pop IP
pop CS
call 指令
CPU执行call指令时,进行两部操作
- 将当前的
IP
或CS
和IP
压入栈中 - 转移
注意:
- call指令不能实现短转移
- call和jmp指令的原理相同
依据位移进行转移的call指令
call 标号(将当前的IP压栈后,转到标号处执行指令)
CPU执行此种格式的CALL指令时,进行如下操作
(SP) = (SP) - 2
((SS) * 16 + (SP)) = (IP)
(IP) = (IP) + 16
位位移
16位位移 = 标号处的地址 - call指令后的第一个字节的地址
16位位移的范围为-32768~32767, 用补码表示
16位位移由编译程序在编译时算出
call 标号相当于执行
push IP
jmp near ptr 标号
转移的目的地址在指令中的call指令
语法
call far ptr 标号
CPU执行此种格式的call指令时,进行如下操作
(SP) = (SP) - 2
((SS) * 16 + (SP)) = (CS)
(SP) = (SP) - 2
((SS) * 16 + (SP)) = (IP)
(CS) = 标号所在段的段地址
(IP) = 标号在段中的偏移地址
CPU执行call far ptr 标号
时, 相当于进行
PUSH CS
PUSH IP
jmp far ptr 标号
转移地址在寄存器中的call指令
指令格式:call 16位reg
CPU执行此种格式的call指令时,进行如下操作
(sp) = (sp) - 2
((ss) * 16 + (SP) = (IP))
(IP) = (16位reg)
相当于执行了
push IP
jmp 16位reg
转移地址在内存中的call指令
两种格式
call word ptr 内存单元地址
相当于执行
push IP
jmp word ptr 内存单元地址
比如下面的指令:
mov sp, 10h
mov ax, 0123h
mov ds:[0], ax
call word ptr ds:[0]
执行后,(IP) = 0123H, (SP) = 0EH
call dword ptr 内存单元地址
用汇编语法来解释此种格式的call
指令,则:
CPU执行call dword ptr 内存单元地址
时相当于执行:
push CS
push IP
jmp dword ptr 内存单元地址
比如下面的指令
mov sp, 10h
mov ax, 0123h
mov ds:[0], ax
mov word ptr ds:[2], 0
call dword ptr ds:[0]
执行后,(CS) = 0, (IP) = 0123H, (SP) = 0CH