王爽《汇编语言》(第二版) 学习笔记 (第十章 CALL和RET指令 )

 

第十章 CALL和RET指令
本章概述:
call和ret指令都是转移指令,它们都修改IP,或同时修改CS和IP。它们经常被共同用来实现子程序的设计。
一、             ret 和retf
1.         ret指令用栈中的数据,修改IP的内容,从而实现近转移。
2.         retf指令用栈中的数据,修改CS和IP的内容,从而实现远转移。
3.         CPU执行ret指令时,进行下面两步操作:
1)        (IP)=((ss)*16+(sp))
2)        (sp)=(sp)+2
4.         CPU执行retf指令时,进行下面4步操作:
1)        (IP)=((ss)*16+(sp))
2)        (sp)=(sp)+2
3)        (CS)=((ss)*16+(sp))
4)        (sp)=(sp)+2
5.         CPU执行ret指令时,相当于进行:pop IP
6.         CPU执行retf指令时,相当于进行:pop IP pop CS
二、             call 指令
1.         CPU执行call指令时,进行两步操作:
1)        将当前的IP或CS和IP压入栈中;
2)        转移。
2.         call指令不能实现短转移,除此之外,call指令实现转移的方法和jmp指令的原理相同。
三、             依据位移进行转移的call 指令
1.         call 标号(将当前的IP压栈后,转到标号处执行指令)
2.         CPU执行此种格式的call指令时,进行如下的操作:
1)        (sp)=(sp)-2   
2)        ((ss)*16+(sp))=(IP)
3)        (IP)=(IP)+16位位移。
16位位移=标号处的地址-call指令后的第一个字节的地址;
16位位移的范围为-32768~32767,用补码表示;
16位位移由编译程序在编译时算出。
3.         CPU执行“call 标号”时,相当于进行:
push     IP
jmp near ptr 标号
四、             转移的目的地址在指令中的call 指令
1.         call far ptr 标号               实现的是段间转移
2.         CPU执行此种格式的call指令时,进行如下的操作。
1)        (sp)=(sp)-2
((ss)*16+(sp))=(CS)
(sp)=(sp)-2
((ss)*16+(sp))=(IP)
2)        (CS)=标号所在段的段地址
(IP)=标号所在段中的偏移地址
3.         CPU执行“call far ptr 标号”时,相当于进行:
push       CS
push         IP
jmp        far ptr 标号
五、             转移地址在寄存器中的call 指令
1.         指令格式:call 16位reg
功能:
(sp)=(sp)-2
((ss)*16+(sp))=(IP)
(IP)=(16位reg)
2.          CPU执行“call 16位reg”时,相当于进行:
push         IP
jmp  16位reg
六、             转移地址在内存中的call 指令
转移地址在内存中的call指令有两种格式:
1)        call word ptr 内存单元地址,相当于:
push      IP
jmp word    ptr   内存单元地址
2)        call dword ptr 内存单元地址,相当于进行:
push         CS
push         IP
jmp dword ptr    内存单元地址
七、             call 和ret 的配合使用
1.         具有一定功能的程序段,称之为子程序。在需要的时候,用call指令转去执行,call指令转去执行子程序之前,call指令后面的指令的地址将存储在栈中,所以可在子程序的后面使用ret指令,用栈中的数据设置IP的值,从而转到call指令后面的代码处继续执行。
2.         可以利用call和ret来实现子程序的机制。子程序的框架:
标号:
       指令
       ret
八、             mul 指令
1.         mul指令是乘法指令,使用mul做乘法时,需要注意一下两点:
1)        两个相乘的数:两个相乘的数,要么都是8位,要么都是16位。如果是8位,一个默认放在AL中,另一个放在8位reg活内存字节单元中;如果是16位,一个默认在AX中,另一个放在16位reg或内存字单元中。
2)        结果:如果是8位乘法,结果默认放在AX中;如果是16位乘法,结果高位默认在DX中存放,低位在AX中存放。
2.         内存单元可以用不同的寻址方式给出:
1)        mul          byte ptr   ds:[0]
2)        mul          word prt [bx+si+8]
九、             模块化程序设计
1.         call和ret指令共同支持了汇编语言编程中的模块化设计。在实际编程中,程序的模块化是比不可少的。因为现实的问题比较复杂,对现实问题进行分析时,把它转化成相互联系、不同层次的子问题,是必须的解决方法。
2.         call和ret指令对这种分析方法提供了程序实现上的支持。利用call和ret指令,我们可以用简捷的方法,实现多个相互联系、功能独立的子程序来解决一个复杂的问题。
十、             参数和结果传递的问题
1.         子程序一般都要根据提供的参数处理一定的事务,处理后,将结果(返回值)提供给调用者。
2.         用寄存器来存储参数和结果是最常见使用的方法。对于存放参数的寄存器和存放结果的寄存器,调用者和子程序的读写操作恰恰相反:调用者将参数送入参数寄存器,从结果寄存器中取到返回值;子程序从参数寄存器中取到参数,将返回值送入结果寄存器。
十一、      批量数据的传递
1.         如果子程序传递只有一个参数,放在某个寄存器中。但如果有两个参数,那么可以用两个寄存器来存放,可是如果需要传递的数据有3个、4个或更多直至N个,该怎么存放呢?寄存器的数量终究有限,我们不可能简单地用寄存器来存放多个需要传递的数据。对于返回值,也有同样的问题。
2.         在这种时候,我们将批量数据放到内存中,然后将它们所在内存空间的首地址放在寄存器中,传递给需要的子程序。对于具有批量数据的返回结果,也可用同样的方法。
3.         除了用寄存器传递参数外,还有一种通用的方法是用栈来传递参数。
十二、      寄存器冲突的问题
1.         子程序中使用的寄存器,很可能在主程序中也要使用,造成了寄存器使用上的冲突。
2.         解决这个问题的简捷方法是,在子程序的开始将子程序中所有用到的寄存器中的内容都保存起来,在子程序返回前再恢复。可以用栈来保存寄存器中的内容。
3.         编写子程序的标准框架如下:
子程序开始:子程序中使用的寄存器入栈
                     子程序内容
子程序中使用的寄存器出栈
返回(ret、retf)
十三、      实验10 编写子程序
十进制数码字符对应的ASCII码 = 十进制数码值 + 30H

课程设计

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值