赞
踩
call和ret指令都是转移指令,它们都修改IP,或者同时修改CS和IP。它们经常被用作实现子程序的设计。
ret指令用栈中的数据,修改IP的内容,实现近转移。
retf指令用栈中的数据,修改CS和IP的内容,实现远转移。
CPU在执行ret指令时,进行两步操作:
(1)(IP) = ((ss)*16+(sp)).
(2)(sp)=(sp)+2.
相当于:
pop IP.
CPU在执行retf指令时,进行四步操作:
(1)(IP) = ((ss)*16+(sp)).
(2)(sp)=(sp)+2.
(3)(CS)=((ss)*16+(sp)).
(4)(sp)=(sp)+2.
相当于:
pop IP
pop CS.
assume cs:code
stack segment
db 16 dup (0)
stack ends
code segment
mov ax, 4c00h
int 21
start: mov ax, stack
mov ss, ax
mov sp, 16
mov ax, 0
push ax
mov bx, 0
ret
code ends
end start
例如这个程序,ret语句执行后,(IP)=0,CS:IP指向代码第一条指令。
CPU执行call指令时,进行两部操作:
(1)将当前的IP或CS和IP压入栈中;
(2)转移。
call不能实现短转移。
call 标号:将当前的IP压栈后,转到标号处执行指令。
CPU执行此种形式的call指令时,进行如下操作:
(1)(sp)=(sp)-2.
(2)((ss)*16+(sp))=(IP).
相当于
push IP
Jmp near ptr 标号
call for ptr 标号 实现的是段间转移。
CPU执行此种形式的call指令时,进行如下操作:
(1)(sp)=(sp)-2.
((ss)*16+(sp))=(CS).
(sp) = (sp)-2.
((ss)*16+(sp))=(IP).
.
(2)(CS)=标号所在段的段地址。
(IP)=标号所在段的偏移地址。
CPU执行“call for ptr 标号”时,相当于:
push CS
push IP
jmp far ptr 标号
格式:
call 16位reg
功能:
(sp) = (sp) - 2
((ss)*16+(sp))=(IP)
(IP) = (16位reg)
CPU执行“call 16位reg”时,相当于:
push IP
jmp 16位reg
转移地址在内存中的call指令有两种格式:
(1)call word ptr 内存单元地址
CPU执行“call word ptr 内存单元地址”时,相当于进行:
push IP
jmp word ptr 内存单元地址
(2)call dword ptr 内存单元地址
CPU执行“call dword ptr 内存单元地址”时,相当于进行:
push CS
push IP
jmp dword ptr 内存单元地址
assume cs:code
code segment
start: mov ax, 1
mov cx, 3
call s
mov bx, ax
mov ax, 4c00h
int 21h
s: add ax, ax
loop s
ret
code ends
end start
我们拿这个程序为例,看一下call指令和ret指令的搭配使用,程序中bx的值是8。我们发现,可以写一个具有一定功能的程序段,我们称之为子程序,在需要的时候,使用call指令转去执行,在子程序的后面使用ret指令,用栈中的数据设置IP的值,从而转到call指令后面的代码处继续执行。
使用mul做乘法运算时,注意两点:
(1)两个数相乘,要么都是8位,要么都是16位。如果是8位,一个默认放在AL中,一个放在8位reg或内存字节单元中。如果是16位,一个放在AX中,一个放在16位reg或内存单元中。
(2)结果:8位乘法,结果放在AX中;16位乘法,结果的高位放在DX中,低位在AX中。
格式:
mul reg
mul 内存单元
内存单元可以用不同的寻址方式给出,为了熟练使用mul运算,我们来看两个例子:
(1) mul byte ptr ds:[0]
含义:(ax) = (al)*((ds)*16+(bx)+(si)+8)
(2) mul word ptr [bx+si+8]
含义:
(ax) = (ax)*((ds)16+(bx)+(si)+8)结果的低16位
(ds) = (ax)((ds)*16+(bx)+(si)+8)结果的高16位
当问题复杂,可以设计子程序,达到一个结构性的设计求解。而call和ret提供了技术上的支持。
这个问题的实质就是在探讨如何存储子程序需要的参数和产生的返回值。
对于要存储多个数据的问题,我们将批量数据放在内存中,然后将它们所在的内存空间的首地址放在寄存器中,传递给需要的子程序。
例如将单词字母转为大写的程序:
assume cs:code
data segment
db 'conversation'
data ends
code segment
start:mov ax, data
mov ds, ax
mov si, 0
mov cx, 12
call capital
mov ax, 4c00h
int 21h
capital:and byte ptr [si],11011111b
inc si
loop capital
ret
code ends
end start
数据存放在内存中,数据的后面可以使用一个特殊的有区分的字符表示结束条件。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。