目录
引言
10.1 ret和retf
检测点10.1
10.2 call指令
10.3 依据位移进行转移的call指令
检测点10.2
10.4 转移的目的地址在指令中的call指令
检测点10.3
10.5 转移地址在寄存器中的call指令
检测点10.4
10.6 转移地址在内存中的call指令
检测点 10.5
10.7 call和ret的配合使用
10.8 mul指令
10.9 模块化程序设计
10.10 参数和结果传递的问题
10.11 批量数据的传递
10.12 寄存器冲突的问题
引言
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文章来源地址https://www.toymoban.com/news/detail-414899.html
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文章来源:https://www.toymoban.com/news/detail-414899.html
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
到了这里,关于汇编语言——第10章 CALL和RET指令的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!