《汇编语言10分析解析》由会员分享,可在线阅读,更多相关《汇编语言10分析解析(74页珍藏版)》请在金锄头文库上搜索。
1、第10章 call 和 ret 指令,10.1 ret 和 retf 10.2 call 指令 10.3 依据位移进行转移的call指令 10.4 转移的目的地址在指令中的call指令 10.5 转移地址在寄存器中的call指令 10.6 转移地址在内存中的call指令 10.7 call 和 ret 的配合使用 10.8 mul 指令 10.9 模块化程序设计 10.10 参数和结果传递的问题 10.11 批量数据的传递 10.12 寄存器冲突的问题,引言,call和ret 指令都是转移指令,它们都修改IP,或同时修改CS和IP。 它们经常被共同用来实现子程序的设计。,10.1 ret 和
2、retf,ret指令用栈中的数据,修改IP的内容,从而实现近转移; 操作 retf指令用栈中的数据,修改CS和IP的内容,从而实现远转移; 操作,10.1 ret 和 retf,CPU执行ret指令时,进行下面两步操作: (1)(IP)=(ss)*16+(sp) (2)(sp)=(sp)+2,10.1 ret 和 retf,CPU执行retf指令时,进行下面两步操作: (1)(IP)=(ss)*16+(sp) (2)(sp)=(sp)+2 (3)(CS)=(ss)*16+(sp) (4)(sp)=(sp)+2,10.1 ret 和 retf,可以看出,如果我们用汇编语法来解释ret和retf指
3、令,则: CPU执行ret指令时,相当于进行: pop IP CPU执行retf指令时,相当于进行: pop IP pop CS,10.1 ret 和 retf,示例程序 ret指令 程序中ret指令执行后,(IP)=0,CS:IP指向代码段的第一条指令。 retf指令 程序中retf指令执行后,CS:IP指向代码段的第一条指令。,特别提示,检测点10.1 没有完成此检测点,请不要向下进行。,10.2 call 指令,CPU执行call指令,进行两步操作: (1)将当前的 IP 或 CS和IP 压入栈中; (2)转移。 call 指令不能实现短转移,除此之外,call指令实现转移的方法和 jm
4、p 指令的原理相同。,10.3 依据位移进行转移的call指令,call 标号(将当前的 IP 压栈后,转到标号处执行指令) CPU执行此种格式的call指令时,进行如下的操作: (1) (sp) = (sp) 2 (ss)*16+(sp) = (IP) (2) (IP) = (IP) + 16位位移,10.3 依据位移进行转移的call指令,call 标号 16位位移=“标号”处的地址call指令后的第一个字节的地址; 16位位移的范围为 -3276832767,用补码表示; 16位位移由编译程序在编译时算出。 演示,10.3 依据位移进行转移的call指令,如果用汇编语法来解释此种格式的
5、call指令,则: CPU 执行指令“call 标号”时,相当于进行: push IP jmp near ptr 标号,特别提示,检测点10.2(p181) 没有完成此检测点,请不要向下进行。,10.4 转移的目的地址在指令中的call指令,前面讲解的call指令,其对应的机器指令中并没有转移的目的地址 ,而是相对于当前IP的转移位移。 指令“call far ptr 标号”实现的是段间转移。 操作,10.4 转移的目的地址在指令中的call指令,CPU执行“call far ptr 标号”这种格式的call指令时的操作: (1) (sp) = (sp) 2 (ss) 16+(sp) = (C
6、S) (sp) = (sp) 2 (ss) 16+(sp) = (IP) (2) (CS) = 标号所在的段地址 (IP) = 标号所在的偏移地址,10.4 转移的目的地址在指令中的call指令,如果用汇编语法来解释此种格式的 call 指令,则: CPU 执行指令 “call far ptr 标号” 时,相当于进行: push CS push IP jmp far ptr 标号,特别提示,检测点10.3 没有完成此检测点,请不要向下进行。,10.5 转移地址在寄存器中的call指令,指令格式:call 16位寄存器 功能: (sp) = (sp) 2 (ss)*16+(sp) = (IP)
7、(IP) = (16位寄存器),10.5 转移地址在寄存器中的call指令,指令格式:call 16位寄存器 汇编语法解释此种格式的 call 指令,CPU执行call 16位reg时,相当于进行: push IP jmp 16位寄存器,特别提示,检测点10.4 没有完成此检测点,请不要向下进行。,10.6 转移地址在内存中的call指令,转移地址在内存中的call指令有两种格式: (1) call word ptr 内存单元地址 (2) call dword ptr 内存单元地址,10.6 转移地址在内存中的call指令,(1) call word ptr 内存单元地址 汇编语法解释: pu
8、sh IP jmp word ptr 内存单元地址 示例,10.6 转移地址在内存中的call指令,(1) call word ptr 内存单元地址(示例) 比如下面的指令: mov sp,10h mov ax,0123h mov ds:0,ax call word ptr ds:0 执行后,(IP)=0123H,(sp)=0EH,10.6 转移地址在内存中的call指令,(2) call dword ptr 内存单元地址 汇编语法解释: push CS push IP jmp dword ptr 内存单元地址 示例,10.6 转移地址在内存中的call指令,(2) call dword pt
9、r 内存单元地址(示例) 比如,下面的指令: 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 的配合使用,assume cs:code code segment start: mov ax,1 mov cx,3 call s mov bx,ax ;(bx) = ? mov ax,4c00h int 21h s: add ax,ax loo
10、p s ret code ends end start,问题10.1 右面程序返回前,bx中的值是多少? 思考后看分析。,10.7 call 和 ret 的配合使用,问题10.1分析 CPU 执行这个程序的主要过程: (1)CPU 将call s指令的机器码读入,IP指向了call s后的指令mov bx,ax,然后CPU执行call s指令,将当前的 IP值(指令mov bx,ax的偏移地址)压栈,并将 IP 的值改变为标号 s处的偏移地址; (2)CPU从标号 s 处开始执行指令,loop循环完毕,(ax)=8;,10.7 call 和 ret 的配合使用,问题10.1分析(续) (3)C
11、PU将ret指令的机器码读入,IP指向了ret 指令后的内存单元,然后CPU 执行 ret 指令 ,从栈中弹出一个值(即 call 先前压入的mov bx,ax 指令的偏移地址)送入 IP 中。则CS:IP指向指令mov bx,ax; (4)CPU从 mov bx,ax 开始执行指令,直至完成。,10.7 call 和 ret 的配合使用,程序返回前,(bx)=8 。从标号s 到ret的程序段的作用是计算2的N次方,计算前,N的值由CX提供。 下面的程序,10.7 call 和 ret 的配合使用,10.7 call 和 ret 的配合使用,程序的主要执行过程: (1)前三条指令执行后,栈的情
12、况如下:,10.7 call 和 ret 的配合使用,程序的主要执行过程: (2)call 指令读入后,(IP) =000EH,CPU指令缓冲器中的代码为 B8 05 00; CPU执行B8 05 00,首先,栈中的情况变为: 然后,(IP)=(IP)+0005=0013H。,10.7 call 和 ret 的配合使用,程序的主要执行过程: (3)CPU从cs:0013H处(即标号s处)开始执行。 (4)ret指令读入后:(IP)=0016H,CPU指令缓冲器中的代码为 C3;CPU执行C3,相当于进行pop IP,执行后,栈中的情况为: (IP)=000EH;,10.7 call 和 ret
13、 的配合使用,程序的主要执行过程: (5)CPU回到 cs:000EH处(即call指令后面的指令处)继续执行。 从上面的讨论中我们发现,可以写一个具有一定功能的程序段,我们称其为子程序,在需要的时候,用call指令转去执行。,10.7 call 和 ret 的配合使用,可是执行完子程序后,如何让CPU接着call指令向下执行? call指令转去执行子程序之前,call指令后面的指令的地址将存储在栈中,所以可以在子程序的后面使用 ret 指令,用栈中的数据设置IP的值,从而转到 call 指令后面的代码处继续执行。,10.7 call 和 ret 的配合使用,这样,我们可以利用call和ret
14、来实现子程序的机制。 子程序的框架,10.7 call 和 ret 的配合使用,子程序的框架: 标号: 指令 ret,具有子程序的源程序的框架:,10.8 mul 指令,因下面要用到,我们介绍一下mul指令,mul是乘法指令,使用 mul 做乘法的时候: (1)相乘的两个数:要么都是8位,要么都是16位。 8 位: AL中和 8位寄存器或内存字节单元中; 16 位: AX中和 16 位寄存器或内存字单元中。,10.8 mul 指令,使用mul做乘法的时候: (2)结果 8位:AX中; 16位:DX(高位)和AX(低位)中。 格式如下: mul reg mul 内存单元,10.8 mul 指令,
15、内存单元可以用不同的寻址方式给出,比如: mul byte ptr ds:0 含义为: (ax)=(al)*(ds)*16+0); mul word ptr bx+si+8 含义为: (ax)=(al)*(ds)*16+(bx)+(si)+8)结果的低16位; (dx)=(al)*(ds)*16+(bx)+(si)+8)结果的高16位;,10.8 mul 指令,例如: (1)计算100*10 100和10小于255,可以做8位乘法,程序如下: mov al,100 mov bl,10 mul bl 结果: (ax)=1000(03E8H),10.8 mul 指令,例如: (1)计算100*10
16、000 100小于255,可10000大于255,所以必须做16位乘法,程序如下: mov ax,100 mov bx,10000 mul bx 结果: (ax)=4240H,(dx)=000FH (F4240H=1000000),10.9 模块化程序设计,call 与 ret 指令共同支持了汇编语言编程中的模块化设计。在实际编程中,程序的模块化是必不可少的。 因为现实的问题比较复杂,对现实问题进行分析时,把它转化成为相互联系、不同层次的子问题,是必须的解决方法。,10.9 模块化程序设计,而call和ret 指令对这种分析方法提供了程序实现上的支持。利用 call和ret指令,我们可以用简洁的方法,实现多个互相联系、功能独立的子程序来解决一个复杂的问题。 子程序设计中的相关问题和解决方法:。,10.10 参数和结果传递的问题,子程序一般都要根据提供的参数处理一定的事务,处理后,将结果(返回值)提供给调用者。 讨论参数和返回值传递的问题,实际上就是在探讨,应该如何存储子程序需要的参数和产