汇编语言第三版(王爽著)(第十章.call和ret指令)

call和ret指令都是转移指令,他们可以修改IP或同时修改IP和CS,它们经常被共同用来实现子程序的设计。
**//**此处注意复习栈的内容

10.1 ret和retf

ret指令用中的数据,修改IP的内容,从而实现近转移 段内转移
retf指令用中的数据,修改IP和cs的内容,从而实现远转移 段间转移
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)(IP)=((SS)*16+SP)
(3) (SP)=(SP)+2
相当于
pop IP
pop CS

先是IP再是CS

检测点10.1

补全程序,实现从内存1000:0000处开始执行指令
assume cs:code
stack segment
db 16 dup(0)
stack ends
code segment
start: mov ax,stack
mov ss,ax
mov sp,16
mov ax,1000h
push ax
mov ax,0
push 0
retf
code ends
end start

10.2 call 指令

CPU执行call指令时,进行两步操作:
(1)将当前的IP或CS和IP压入栈中
(2)转移
call不能实现短转移

10.3 依据位移进行转移的call指令(段内转移(近转移))没有短转移!!

call 标号(将当前的IP压栈,转到标号处执行指令)call标号的下一条指令入栈
相当于
push IP
jmp near ptr 标号
执行call指令时,进行如下操作:
(1)(sp)=(sp)-2
((ss)*16+(sp))=(IP)
(2)(SP) = (sp)+16位位移
16位的位移= 标号处的地址-call指令后的第一个字节的地址
16位位移的范围-32768-32767

检测点10.2

下面的程序执行后,ax的值是多少。
ax=6;

10.4 转移的目的地址在指令中的call指令(段间转移)

call far ptr 标号
相当于以下三条指令:
1.push cs
2.push ip
3.jmp far ptr 标号

执行call far ptr 标号时:执行以下操作:
(1)(sp)=(sp)-2
((ss)*16+(sp))=(CS)
(sp)=(sp)-2
((ss)*16+(sp))=(IP)
(2)(cs)=标号所在的段地址
(ip)=标号所在的偏移地址

检测点10.3

AX = 1010H

10.5 转移地址在寄存器中的call指令

指令格式: call reg
相当于
push IP
jmp reg

(sp)=(sp)-2
((ss)*16+(sp))=(IP)
(ip)=16位reg

10.6 转移地址在内存中的call指令

(1)call word ptr 内存单元地址
执行这条语句,相当于执行
push IP
jmp word ptr 内存单元地址
(2)call dword ptr 内存单元地址
push CS
push IP
jmp dword ptr 内存单元地址

检测点10.5

1.ax=3
2.ax=1 bx =0

10.7 call和ret的配合使用

//重点了解它们如何配合使用实现子程序的机制
实现n的m次方
assume cs:code
code segment
start:mov ax,1 ;给出n
mov cx,3 ;给出m
call s ;mov bx,ax的偏移地址入栈,执行s指令
mov bx,ax
mov ax,4c00h
int 21h
s:add ax,ax
loop s
ret ;pop IP,指向mov bx,ax指令
code ends
end start
///
子程序的框架如下:
标号:
指令
ret
具有子程序的源程序的框架如下
assume cs:code
code segment
main:
call s1
mov 4c00h
int 21h
s1:
call s2
ret
s2:
ret
code ends
end main

10.8 mul 指令

mul指令 是乘法指令
(1)两个相乘的数:要么都是8位,要么都是16位。
如果两个都是八位 一个默认在AL中,一个放在8位reg或内存字节单元中;
如果两个都是16位 一个默认在AX中,另一个在16位reg中或内存字单元中。
(2)结果 8位乘法放在AX中,16位高位在DX中,低位在AX中。
格式:mul reg
mul 内存单元

10.9 模块化程序设计

        利用call和ret指令,用简捷的方式,实现多个**相互联系,功能独立**的子程序来解决一个复杂的问题。

10.10 参数结果传递的问题

//重点掌握如何存储子程序需要的参数和产生的返回值
比如,设计一个子程序,可以根据提供的N,来计算N的3次方
这里面就有两个问题:
1.将参数N存储在什么地方
2.产生的结果应该放在哪里。
编程,计算data段中第一组数据的3次方,结果保存在后面一组dword单元中。
assume cs:code
data segment
dw 1,2,3,4,5,6,7,8
dd 0,0,0,0,0,0,0,0
data ends
code segment
start:mov ax,data
mov ds,ax
mov si,0
mov di,16
mov cx,8
s:mov bx,[si]
call cube
mov [di],ax
mov [di].2,dx
add si,2
add di,4
loop s
mov ax,4c00h
int 21h
cube:mov ax,bx
mul bx
mul bx
ret
code ends
end start

10.11 批量数据的传递

//当子程序中参数过多的时候,我们把批量数据放到内存中,然后将它们所在内存空间的首地址放在寄存器中,传递给需要的子程序。
例 将一个全是字母的字符串转换为大写
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 ;存放字符串的长度

call capital
mov ax,4c00h
int 21h
capital:and type ptr [si],11011111b
inc si
loop capital
ret

code ends
end start

10.12 寄存器冲突的问题

为了不让子程序中的寄存器和调用者使用的寄存器相冲突,解决这个问题方法:
在子程序的开始将子程序中所有用到的寄存器中的内容都保存起来
框架:
子程序的开始:
’子程序中使用的寄存器入栈
子程序内容
子程序中使用的寄存器出栈
返回(ret retf)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值