call和ret都是转移指令,他们都修改IP,或同时修改CS和IP。他们经常被共同用来实现子程序的设计。
1.ret 和 retf
ret指令用栈中的数据,修改IP的内容,从而实现近转移。
retf指令用栈中的数据,修改CS和IP的内容,从而实现远转移。
CPU执行ret指令的时候,进行下面两步操作:
(1)(IP)=((ss)*16+(sp))
(2)(sp)=(sp)+2
CPU执行retf指令的时候,进行下面4步操作:
(1)(IP)=((ss)*16+(sp))
(2)(sp)=(sp)+2
(3)(CS)=((ss)*16+(sp))
(4)(sp)=(sp)+2
下面的程序,ret指令执行后,(IP)=0,CS:IP指向代码段的第一条指令
assume cs:code
stack segment
db 16 dup (0)
stack ends
code segment
mov ax,4c00h
int 21h
start : mov ax , stack
mov ss , ax
mov sp , 16
mov ax , 0
push ax
mov bx , 0
ret
code ends
end start
下面程序中,retf指令执行后,CS:IP指向执行代码的第一条指令
assume cs:code
stack segment
db 16 dup (0)
stack ends
codesegment
mov ax , 4c00h
int 21h
start : mov ax , stack
mov ss , ax
mov sp , 16
mov ax , 0
push cs
push ax
mov bx , 0
retf
code ends
end start
2.call 指令
CPU 执行call指令时,进行两步操作:
(1)当前的IP或CS和IP压入栈中;
(2)转移
call 指令不能实现短转移
3.依据位移进行转移的call指令
call 标号(将当前的IP压栈后 , 转到标号处执行指令)
CPU执行此种格式的call指令时,进行如下操作:
(1)(sp)= (sp)- 2
((ss)* 16 + (sp))= (IP)
(2)(IP)=(IP)+16位位移
4.前面的 call 指令,其对应的机器指令并没有转移的目的地址,而是相对于当前IP的转移位移。
“ call far ptr ”实现的是段间转移
5.转移地址在寄存器中的call指令
指令格式:call 16位reg
功能:
(sp) = (sp) + 2
((ss)*16+(sp))=(IP)
(IP)=(16位reg)
6.转移地址在内存中的 call 指令
两种格式:
(1)call word ptr 内存单元地址
(2)call dword ptr 内存地址单元
7.call 和 ret 的配合使用
我们可以利用call 和 ret 来实现子程序的机制,框架如下:
assume cs:code
code segment
main :
:
:
call sub1
:
:
mov ax , 4c00h
int 21h
sub1 :
:
:
call sub2
:
:
ret
sub2 :
:
:
ret
code ens
end main
8.mul 指令
mul是乘法指令,使用mul做乘法的时候,注意以下两点:
(1)两个相乘的数:要么都是8位,要么都是16位,如果是8位,一个默认放在AL中,另一个放在8位reg或者内存字节单元中;如果是16位,一个默认放在AX中,另一个放在16位reg或者内存单元中。
(2)结果:如果是8位乘法,结果默认放在AX中;如果是16位乘法,结果高位默认在DX中存放,低位在AX中存放。
例如:
(1)计算100 * 10
mov al , 100
mov bl , 10
mul bl
结果:(ax) = 1000(03E8H)
(2)计算100 * 10000
100小于255,可10000大于255,所以必须做16位乘法:
mov ax , 100
mob bx , 10000
mul bx
结果:(ax) = 4240H , (dx) = 000FH (F4240H = 100000)