引言
call和ret指令都是转移指令,他们都修改IP,或同时修改CS和IP。
它们经常被共同用来实现子程序的设计。
10.1 ret和retf
ret指令用栈中的数据来修改IP****的内容,从而实现近转移。
CPU执行ret指令时:
1、(IP)=((ss)*16+(sp)),指向栈顶
2、(sp)=(sp)+2
retf指令用栈中的数据,修改CS和IP****的内容,从而实现远转移。
CPU执行retf指令时:
1、(IP)=((ss)*16+(sp))
2、(sp)=(sp)+2
3、(CS)=((ss)*16+(sp))
4、(sp)=(sp)+2
用汇编的语法来解释ret和retf指令:
CPU执行ret指令相当于进行:pop IP
CPU执行retf指令相当于进行:pop IP和pop CS
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
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 cs push ax mov bx,0 retf
codesg ends
end start
retf指令执行后,CS:IP指向代码段的第一条命令。
检测点10.1
10.2 call指令
call指令经常跟ret指令配合使用,CPU执行call指令时:
1、将当前的IP或者CS和IP压入栈;
2、转移(jmp)。
call指令除了不能实现短转移之外,call指令实现转移的方法和jmp指令的原理相同。
call指令实现段间的转移(远转移)或近转移。
10.3 依据位移进行转移的call指令
call标号(将当前的IP压入栈后转到目标处执行指令)
call执行此种格式的call指令时,进行以下操作:
(1)(SP)=(SP)-2
((SS)*16+(SP))=(IP)
(2)(IP)=(IP)+16位位移;
16位位移=标号处的地址-call指令后的第一个字节的地址。
16位位移的范围是-32768~32767,用补码表示。
16位位移由编译程序在编译时算出。
用汇编语法解释call指令:
push IP
jmp near ptr 标号
检测点10.2
10.4 转移的目的地址在指令中的call指令
“call far ptr 标号”实现的是段间转移。
call执行此种格式的call指令时,进行以下操作:
(1)(sp)=(sp)-2
((ss)*16+(sp))=(CS)
(sp)=(sp)-2
((ss)*16+(sp))=(IP)
(2)(CS)=标号所在段的段地址
(IP)=标号所在段的偏移地址
用汇编语法解释call指令:
push CS
push IP
jmp far ptr 标号
检测点10.3
10.5 转移地址在寄存器中的call指令
指令格式是:call 16位reg
功能:
(1)(sp)=(sp)-2
(2)((ss)*16+(sp))=(IP)
(3)(IP)=(16位reg)
用汇编语法解释此种call指令,CPU执行“call 16位reg”时,相当于:
push IP
jmp 16位reg
检测点10.4
10.6 转移地址在内存中的call指令
转移地址在内存中的call指令有两种格式:
(1)call word ptr 内存单元地址;段内跳转
用汇编语法解释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 内存单元地址;段间跳转
用汇编语法解释call dword ptr 内存单元地址
push CS
push IP
jmp word 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.5
10.7 call和ret的配合使用
10.8 mul指令
mul是乘法指令,使用mul做乘法的时候应注意以下两点:
(1)两个相乘的数:两个相乘的数,要么都是8位,要么都是16位。如果是8位,一个默认放在AL中,另一个放在8位reg或内存字节单元中;如果是16位,一个默认在AX中,另一个放在16位reg或内存字单元中。
(2)结果:如果是8位乘法,结果默认放在AX中;如果是16位乘法,结果高位默认在DX中存放,低位在AX中存放。
格式:
mull reg
mull 内存单元
内存单元可以用不同的寻址方式给出,比如:
mull byte ptr ds:[0]
含义:(ax)=(al)*((ds)*16+0);
mull word ptr [bx+si+idata]
含义:(ax)=(ax)*((ds)*16+(bx)+(si)+idata)结果的低6位。
(dx)=(ax)*((ds)*16+(bx)+(si)+idata)结果的高6位。
例子:
(1)计算100*10
两个数都小于255,可以做8位乘法
mov al,100
mov bl,10
mul bl
结果(ax)=1000(03E8H)
(2)计算100*1000
1000都大于255,要做16位乘法
mov ax,100
mov bx,10000
mul bx
结果(ax)=4240H,(dx)=000FH,(F4240H=1000000)
10.9 模块化程序设计
cal和ret指令共同支持汇编语言编程中的模块化设计。
10.10 参数和结果传递的问题
用寄存器来存储参数和结果是最常用的方法。对于存放参数的寄存器和存放结果的寄存器,调用者和子程序的读写操作恰恰相反:
调用者将参数送入参数寄存器,从结果寄存器中取到返回值;
子程序从参数寄存器中取到参数,将返回值送入结果寄存器。
编程:计算data段中第一组数据的3次方,结果保存在后面一组dword单元中
assume cs:code
data segment
dw 1,2,3,4,5,6,7,8 dd 8 dup (0)
data ends
code segment
start: mov ax,data
mov ds,ax mov si,0 ;ds:si指向第一组word单元 mov di,16 ;ds:di指向第二组dword单元 mov cx,8 s: mov bx,[si] call cube mov [di],ax mov [di].2,dx add si,2 ;ds:di指向下一个word单元 add di,4 ;ds:di指向下一个dword单元 loop s mov ax,4c00h int 21h cube: mov ax,bx mul bx mul bx ret
code ends
end start
10.11 批量数据的传递
将批量数据放在内存中,然后将它们所在内存空间的首地址放在寄存器中,传递给需要的子程序,批量数据的返回结果也是采用同样的方法。除此之外还可以用栈来传递参数。
编程:将data段中的字符串转化为大写
assume cs:code
data segment
db 'conversation'
data ends
code segment
start: mov ax,data mov ds,ax mov si,0 ;ds:si指向字符串(批量数据)所在空间的首地址 mov cx,12 ;cx存放字符串的长度 call capital mov ax,4c00h int 21h
capital: add byte ptr [si],11011111B
inc si loop capital ret
code ends
end start
10.12 寄存器冲突的问题
编程:将一个全是字母,以0结尾的字符串转化为大写
capital: mov cl,[si] ;低8位
mov ch,0 ;高8位设置为0 jcxz ok ;如果(cx)=0则结束,如果不是0则处理 and byte ptr [si],11011111B inc si jmp short capital ok: ret
编程:将data段中的字符串全部转化为大写
assume cs:code
data segment
db 'word',0 db 'unix',0 db 'wind',0 db 'good',0
data ends
此程序有bug,cx有问题
assume cs:code
data segment
db 'word',0 db 'unix',0 db 'wind',0 db 'good',0
data ends
code segment
start: mov ax,data mov ds,ax mov bx,0 mov cx,4 s: mov si,bx call capital add bx,5 loop s mov ax,4c00h int 21h
capital: mov cl,[si]
mov ch,0 jcxz ok and byte ptr [si],11011111b inc si jmp short capital ok: ret
code ends
end start
版权归原作者 关了个尔 所有, 如有侵权,请联系我们删除。