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

第十章  CALLRET指令

本章概述:

callret指令都是转移指令,它们都修改IP,或同时修改CSIP。它们经常被共同用来实现子程序的设计。

一、             retretf

1.         ret指令用栈中的数据,修改IP的内容,从而实现近转移。

2.         retf指令用栈中的数据,修改CSIP的内容,从而实现远转移。

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)        将当前的IPCSIP压入栈中;

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 16reg

功能:

(sp)=(sp)-2

((ss)*16+(sp))=(IP)

(IP)=(16reg)

2.          CPU执行“call 16reg”时,相当于进行:

push        IP

jmp    16reg

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

转移地址在内存中的call指令有两种格式:

1)        call word ptr 内存单元地址,相当于:

push      IP

jmp  word   ptr   内存单元地址

2)        call dword ptr 内存单元地址,相当于进行:

push        CS

push        IP

jmp  dword  ptr   内存单元地址

七、             callret的配合使用

1.         具有一定功能的程序段,称之为子程序。在需要的时候,用call指令转去执行,call指令转去执行子程序之前,call指令后面的指令的地址将存储在栈中,所以可在子程序的后面使用ret指令,用栈中的数据设置IP的值,从而转到call指令后面的代码处继续执行。

2.         可以利用callret来实现子程序的机制。子程序的框架:

标号:

       指令

       ret

八、             mul指令

1.         mul指令是乘法指令,使用mul做乘法时,需要注意一下两点:

1)        两个相乘的数:两个相乘的数,要么都是8位,要么都是16位。如果是8位,一个默认放在AL中,另一个放在8reg活内存字节单元中;如果是16位,一个默认在AX中,另一个放在16reg或内存字单元中。

2)        结果:如果是8位乘法,结果默认放在AX中;如果是16位乘法,结果高位默认在DX中存放,低位在AX中存放。

2.         内存单元可以用不同的寻址方式给出:

1)        mul         byte ptr   ds:[0]

2)        mul         word  prt  [bx+si+8]

九、             模块化程序设计

1.         callret指令共同支持了汇编语言编程中的模块化设计。在实际编程中,程序的模块化是比不可少的。因为现实的问题比较复杂,对现实问题进行分析时,把它转化成相互联系、不同层次的子问题,是必须的解决方法。

2.         callret指令对这种分析方法提供了程序实现上的支持。利用callret指令,我们可以用简捷的方法,实现多个相互联系、功能独立的子程序来解决一个复杂的问题。

十、             参数和结果传递的问题

1.         子程序一般都要根据提供的参数处理一定的事务,处理后,将结果(返回值)提供给调用者。

2.         用寄存器来存储参数和结果是最常见使用的方法。对于存放参数的寄存器和存放结果的寄存器,调用者和子程序的读写操作恰恰相反:调用者将参数送入参数寄存器,从结果寄存器中取到返回值;子程序从参数寄存器中取到参数,将返回值送入结果寄存器。

十一、      批量数据的传递

1.         如果子程序传递只有一个参数,放在某个寄存器中。但如果有两个参数,那么可以用两个寄存器来存放,可是如果需要传递的数据有3个、4个或更多直至N个,该怎么存放呢?寄存器的数量终究有限,我们不可能简单地用寄存器来存放多个需要传递的数据。对于返回值,也有同样的问题。

2.         在这种时候,我们将批量数据放到内存中,然后将它们所在内存空间的首地址放在寄存器中,传递给需要的子程序。对于具有批量数据的返回结果,也可用同样的方法。

3.         除了用寄存器传递参数外,还有一种通用的方法是用栈来传递参数。

十二、      寄存器冲突的问题

1.         子程序中使用的寄存器,很可能在主程序中也要使用,造成了寄存器使用上的冲突。

2.         解决这个问题的简捷方法是,在子程序的开始将子程序中所有用到的寄存器中的内容都保存起来,在子程序返回前再恢复。可以用栈来保存寄存器中的内容。

3.         编写子程序的标准框架如下:

子程序开始:子程序中使用的寄存器入栈

                     子程序内容

子程序中使用的寄存器出栈

返回(retretf)

十三、      实验10编写子程序

十进制数码字符对应的ASCII = 十进制数码值 + 30H

十四、      课程设计

你可能感兴趣的:(王爽《汇编语言》(第二版) 学习笔记 (第十章 CALL和RET指令 ))