第10章 call和ret指令
引言:
call和ret都是转移指令,他们都修改ip,或同时修改cs和ip。
他们经常被共同用来实现程序的设计
10.1 ret和retf
ret指令用栈中的数据,修改ip的内容,从而实现近转移。
retf指令用栈中的数据,修改cs和ip的内容,从而实现远转移;
可以看出,如果我们用汇编语法来解释ret和retf指令,则
cpu执行ret指令时,相当于进行:
pop ip
cpu执行retf指令时,相当于进行:
pop ip
pop cs
10.2 call指令
cpu执行call指令,进行两步操作:
1)将当前的ip或cs和ip压入栈中;
2)转移
call指令不能实现短转移,除此之外,call指令实现转移的方法和jmp指令的原理相同,下面的几个小节中,我们以给出转移目的地址的不同方法为主线,讲解call指令的主要应用格式
10.3 依据位移进行转移的call指令
call标号(将当前的ip压入栈后,转到标号处执行指令)
cpu执行此种格式的call指令时,进行如下的操作:
1)sp=sp-2
2)ip=ip+16位位移
call标号
16位位移=标号处的地址--call指令后的第一个字节的地址;
16位位移的范围为-32768~32767,用补码表示
16位位移由编译程序在编译时算出。
从上面的描述中,可以看出,如果我们用汇编语法来解释此种格式的call指令,则:
cpu执行指令call标号时,相当于进行:
push ip
jmp near ptr 标号
10.4 转移的目的地址在指令中的call指令
前面讲解的call指令,其对应的机器指令中并没有转移的目的地址,而是相对于当前ip的转移位移。
指令call far ptr 标号 实现的是段间转移
cpu执行call fat ptr 标号这种格式的call指令时的操作:
1)sp=sp-2
ssx16+sp=cs
sp=sp-2
ssx16+sp=ip
2)cs=标号所在的段地址
ip=标号所在的偏移地址
cpu执行指令call far ptr 标号时,相当于进行:
push cs
push ip
jmp far ptr 标号
10.5 转移地址在寄存器中的call指令
指令格式:call 16位寄存器
功能:
sp=sp-2
ss*16+sp=ip
ip=(16位寄存器)
汇编语法解释此种格式的call指令,cpu执行call16位reg时,相当于进行:
push ip
jmp 16位寄存器
10.6 转移地址在内存中的call指令
转移地址在内存中的call指令有两种格式:
1)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
2)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
10.7 call和ret的配合使用
我们看一下call和ret如何配合使用来实现子程序的机制
我们来看以下cpu执行这个程序的主要过程:
1)cpu将call s指令的机器码读入,ip指向了call s后的指令mov bx, ax,然后cpu执行call s指令,将当前的ip值(指令mov bx,ax的偏移地址)压栈,并将ip的值改变为标号s处的偏移地址。
2)cpu从标号s处开始执行指令,loop循环完毕,ax=8
3)cpu将ret指令的机器码读入,ip指向了ret指令后的内存单元,然后cpu执行ret指令,从栈中弹出一个值(即call先前压入栈的mov bx, ax指令的偏移地址)送入ip中。则cs:ip指向指令mov bx ,ax
4)cpu从mov bx ,ax开始执行指令,直至完成。
10.8 mul指令
mul是乘法指令,使用mul做乘法的时候:
1)相乘的两个数,要么都是8位,要么都是16位
8位:al中的8位寄存器或内存字节单元中
16位:ax中的16位寄存器或内存字单元中。
2)结果
8位:ax中
16位:dx(高位)和ax(低位)中
格式如下:
mul reg
mul 内存单元
内存单元可以用不同的寻址方式给出,比如:
mul byte ptr ds:[0]
含义为:ax=al*(ds*16+0)
mul word ptr [bx+si+8]
含义为:
ax=al*(ds*16+bx+si+8)结果的低16位
dx=al*(dx*16+bx+si+8)结果的高16位
例如:
1)计算100*10
100和10小于255,可以做8位乘法,程序如下:
mov al,100
mov bl,10
mul bl
结果ax=1000
2)计算100*10000
100小于255,可10000大于255,所以必须做16位乘法,程序如下:
mov ax,100
mov bx,10000
mul bx
结果 ax=4240h,dx=000fh
(f4240h=1000000)
10.11批量数据的传递
当参数过多时,如何实现参数传递?
在这种时候,我们将批量数据放到内存中,然后将他们所在内存空间的首地址放在寄存器中,传递给需要的子程序。
对于具有批量数据的返回结果,也可用同样的方法。