子程序的基本格式和有关指令.ppt

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

6.1.1 堆栈段
图6.1是堆栈的物理结构示意图,图中标出的SS和SP是与 堆栈密切相关的寄存器,SS存放堆栈所占用内存区域的段地 址,SP所指向的位置称为栈顶。
SS:SP
栈顶指针
栈的空闲区
已入栈的数据存放区
一个程序如果要使用堆栈,必须先留出一片连续内存区 域,方法是在程序中定义一个堆栈段。
【基本格式】 段名 SEGMENT STACK DW n DUP(?) 段名 ENDS 【说明】
6.2.2 子程序相关指令
6.2.2.1 CALL指令
【指令格式】CALL 子程序名
【功能】这是调用子程序的指令。根据被调用的子程序的 类型不同,CALL指令的功能分为两种情况:
(1)如果被调用的子程序是NEAR类型,则先把当前指令指 针IP的值入栈,这会使SP的值减2,然后把IP改成子程序的第 1条指令的偏移地址。
【例6.2】分析下面的程序段的执行过程,以及在执行过 程中堆栈及指令指针IP的变化情况,并假设在执行CALL指令 前,SP的值是0FEH。
subp PROC NEAR
INC AL ;假设本指令所在的偏移地址是1234H
RET
subp ENDP
5678H
CALL MOV
subp AX,BX
;假设本指令所在的偏移地址是
PUSH AX
PUSH BX
POP AX
POP BX
【解】堆栈变化见图6.2,程序段执行完后AX=307CH, BX=4F8AH。
SP→
XX 0FFC
XX
XX 0FFD
XX
XX 0FFE SP→ 8A
XX 0FFF
4F
YY 1000
Байду номын сангаас
YY
0FFC SP→ 0FFD 0FFE 0FFF 1000
7C 30
(6)执行完RET指令后,IP的值已经变成5678H,CPU 按新的IP值,在CS段下取出一条指令,即MOV AX, BX指 令,并继续执行下去。
XX XX XX XX SP→ YY
00FA 00FB 00FC SP→ 00FD 00FE
XX 00FA
XX 00FA
XX 00FB
XX 00FB
78 00FC
栈顶所指位置以上的部分是堆栈的空闲区,以下部分是 已入栈的数据存放区(见图6.1),例6.1用来说明PUSH指令和 POP指令对堆栈的影响。
【例6.1】设AX=4F8AH,BX=307CH,SP=1000H,分 别逐条执行下列指令,用内存图的形式画出堆栈的变化情况, 并分析程序段执行完后AX和BX寄存器的值。
(2)如果被调用的子程序是FAR类型,则先把当前CS寄存 器的值入栈,再把IP入栈,结果会使SP的值减4,然后把CS 和IP改为子程序第1条指令的逻辑地址。
CALL也是一种跳转指令,与无条件跳转及条件跳转指 令不同的是,CALL在跳转之前先预留了回来的方法,把IP 的当前值或CS与IP的当前值入栈保存。从CS与IP 的作用可 以知道,它们存放的是正在执行的指令的下一条指令的逻辑 地址,现在这一地址被保存在堆栈中。于是回来的方法就显 而易见了,只要从栈中取出逻辑地址值,送回IP或者CS与IP 即可。这种返回操作就是由RET指令实现的。
【解】
(1)当计算机把CALL subp对应的机器指令取到CPU中 时,IP的值已经是CALL的下一行的MOV指令所在的偏移地 址5678H,此时还未进栈,栈的情况如图6.3(a)所示。
(2)由于子程序subp是NEAR类型,按照CALL指令功能 的第一种情况执行CALL指令,把IP的值入栈,并把IP的值改 为subp子程序的入口地址1234H,此时堆栈的情况如图6.3(b) 所示。
格式中的首尾两行表示一个子程序的开始和结束,都 属于伪指令。“子程序名”是一个标识符,是编程者给子 程序起的名字。子程序名同时还代表子程序第一条指令所 在的逻辑地址,称为子程序的入口地址。“类型”只有 NEAR和FAR两种,它将影响汇编程序对子程序调用指令 CALL和返回指令RET的翻译方式。被夹在子程序起止伪指 令之间的指令序列是完成子程序固定功能的程序段,通常 指令序列的最后一条指令是返回指令RET。
(e)POP AX后
注:XX表示栈空闲区填充的无用数据,YY表示栈 中已存放的有效数据
图6.2 执行PUSH和POP指令对堆栈的影响
6.1.2.3 PUSHF和POPF指令 【指令格式】PUSHF 【功能】把SP的值减2,并把16位的标志寄存器送入 SS:SP所指向的内存,即把标志寄存器入栈。 【指令格式】POPF 【功能】把栈顶的一个16位的字型数据送入标志寄存器, 并把SP的值加2。
6.1.2 进栈与出栈指令
栈操作指令以它特有的方式存取数据,属于数据传递类 指令,但又与MOV等指令有很大的区别。
6.1.2.1 PUSH指令
【指令格式】PUSH d
【功能】先把SP的值减去2,然后把操作数d指明的字型 数据放入以SS为段地址、SP为偏移地址所对应的内存单元中。
【说明】
(1)这是单操作数指令,操作数d可以是包括段寄存器在 内的任何字型寄存器,或者内存型寻址方式,但不能是立即 寻址,当使用内存型寻址方式时可以使用段跨越。
8A 4F YY
0FFC 0FFD 0FFE 0FFF 1000
(a)执行前 (b)PUSH AX后 (c)PUSH BX后
SP→
XX 0FFC XX 0FFD 8A 0FFE 4F 0FFF YY 1000
XX 0FFC XX 0FFD XX 0FFE XX 0FFF SP→ YY 1000
(d)POP BX后
CALL指令和RET指令都具有跳转的能力,与条件跳转 及无条件跳转一样,都是通过修改IP或者CS与IP来实现的。 不论跳转是由哪一条指令造成的,对于只改变IP 的跳转, 跳转的目的地与跳转指令必然在同一个代码段内,这种跳 转称为段内跳转。相应地,CALL指令功能的第一种情况称 为段内调用,RET指令功能的第一种情况称为段内返回。 另一种跳转是同时改变了CS和IP的值,这就允许跳转指令 与跳转目的地不在同一个段中,使得跳转的目的地可以在 整个内存空间的任何位置,这一类跳转称为段间跳转。 CALL指令功能的第二种情况称为段间调用,RET指令功能 的第二种情况称为段间返回。
6.2.2.2 RET指令
【指令格式】RET
【功能】这是子程序返回指令,必须写在子程序的指令 序列之中。根据所在的子程序的类型不同,RET指令的功能 也分为两种情况:
(1)如果RET所在子程序是NEAR类型,则从堆栈中出 栈一个字(当然,SP会加2),送给IP。
(2)如果RET所在子程序是FAR类型,则先从堆栈中出 栈一个字送到IP,再出栈一个字送到CS,栈顶指SP的值加4。
(3)按基本格式定义的栈是一个空栈,栈中没有存放 有效数据。
(4)为了使SS和SP在程序执行时取得正确的值,必须 在源程序中写一条伪指令:
ASSUME SS:堆栈段段名
但不需要像DS和ES一样在程序中用指令进行赋值。 对SS和SP的赋值是由操作系统在把执行程序调入内存时 由DOS本身完成的,DOS将把SS赋值为堆栈段的段地址, 把SP赋值为2n。
MOV [SP], d
因为指令“MOV [SP], d”存在语法错误。
(4)PUSH指令会导致栈顶指针的移动,如果用PUSH指 令把很多数据进栈,使SP不断减2,就有可能超出栈的有效 范围。在一些高级语言中这种现象会导致堆栈溢出错误,但 8088对此并不做任何检测和警告。因此要求编程人员自己注 意控制堆栈的大小,估计可能进栈的数据量,以免由于栈溢 出导致一些不可预测的后果。
(1)保留字STACK是堆栈段的专用符号,SEGMENT后面 的保留字STACK表明这个段专供堆栈使用。
(2)段定义中用“DW n DUP(?)”说明堆栈所用内存区的 大小为2n字节,其中n是一个常量。可根据程序需要,调节堆 栈段的大小。因为堆栈只能存放字型数据,所以习惯上都是用 DW伪指令来定义栈的大小。这不并是说用其它伪指令不行。
子程序2 PROC NEAR
子程序2 ENDP
子程序n PROC
子程序n ENDP
NEAR
入口标号:
段名 ENDS
从入口标号起的程序段是主程序。RET指令必须出现在子 程序中,而CALL指令可以出现在代码段的任何地方。主程序 可以调用子程序,一个子程序可以调用另一个子程序,还可 以调用它自身,并且在书写次序上没有“先定义后调用”的 限制。
这两条指令相互配合可以设置标志寄存器中的任意一个 标志位,一般的做法是:
PUSHF
POP
AX
… 要,修改AX中的值
;按标志位的分布情况和实际需
PUSH
AX
POPF
6.2 子程序的基本格式和有关指令
6.2.1 汇编语言子程序格式 子程序是具有固定功能的程序段,并且有规定的格式。 不同的计算机语言对子程序格式的规定不同,汇编语言的子 程序基本格式如下: 子程序名 PROC 类型 指令序列 子程序名 ENDP
第6章 子程序
6.1 堆栈
6.2 子程序的基本格式和有关指令
6.3 应用子程序进行编程
6.4 整数输入与输出
6.5 子程序共享的方法
*6.6 递归
本章要点
习题六
返回章目录
6.1 堆栈
在汇编语言和机器语言中,堆栈在物理结构上是一段存 放数据的连续的内存区域,以及一个称为栈顶指针的专用存 储单元。堆栈中只能存入16位的字型数据,存入数据的操作 称为“进栈”或“压栈”,已存入的数据也可以取出,称为 “出栈”或“弹出”,数据的存取操作由专用指令完成。从 逻辑上说,堆栈是一种按“先进后出”原则进行操作的数据 结构,栈顶指针用于指出入栈操作和出栈操作的位置。
XX 00FC
56 00FD
XX 00FD
YY 00FE SP→ YY 00FE
(3)执行完CALL指令 IP的值已经变成1234H,CS没变, CPU按新的IP值,在CS段下取出一条指令,即INC AL指令。
(4)执行INC指令时,CPU自动把IP变成INC的下一行 指令的偏移地址,如此逐条执行子程序中的各指令,直至 遇到subp子程序的最后一条指令RET。
(5)执行RET指令时,堆栈中的情况仍然是图6.3(b), 因此执行RET就是取出栈顶所指的一个字,是5678H,并把 它送给IP,执行完RET指令后堆栈的情况如图6.3(c)所示。
源程序中的指令段在经过汇编程序的翻译后,所有伪指 令都不存在了。作为CALL指令的操作数,“子程序名”部分 会翻译成子程序第一条指令的逻辑地址。当计算机在执行 CALL 指令时,CS和IP已经是下一条指令的逻辑地址。CALL 指令具有保存当前IP或者CS和IP并修改它们的值的能力,因 此CALL执行完后,会按照新的CS及IP,转去执行子程序的第 一条指令,并依次执行后续指令,完成子程序的功能,直至 遇到RET指令。RET指令的执行效果是从栈中取出由CALL保 存的数据,恢复在执行CALL指令时的IP或者CS与IP值,从而 回到CALL指令的下一行继续执行。
6.2.3 子程序的调用与返回
在汇编语言程序中,子程序分为定义和使用两部分。在 较短的程序中,通常把子程序与其余指令写在同一个代码段 内,一个代码段中可以定义多个子程序,并且都定义成 NEAR类型。这样编写的代码段的基本结构如下:
段名 SEGMENT
子程序1 PROC NEAR
子程序1 ENDP
6.1.2.2 POP指令
【指令格式】POP d
【功能】从SS为段地址、SP为偏移地址对应的内存中取 出一个字型数据,送到操作数d指定的位置,然后把SP的值 加2。对操作数d的寻址方式要求与PUSH指令相同。
堆栈通常用于临时保存数据。一般做法是先用PUSH指 令把需要保存的数据入栈,然后完成一定的指令序列,再用 POP指令把原先保存的数据出栈。用堆栈保存数据的特点是 不用定义变量,不必关心被保存的数据到底在栈的什么位置, 只要保证出栈和进栈的对应关系即可。当CPU中的寄存器不 够使用时经常用堆栈临时保存数据。
(2)PUSH指令的功能包括移动栈顶和存入数据两部分, 两部分连续完成,密不可分。
(3)操作数d进栈是以减2以后的SP的值作为偏移地址, 但程序中不允许出现[SP]的写法。不要与基地址寄存器或变 址寄存器用作偏地址时的写法相混淆,也就是说,把PUSH 指令理解成下面两条指令的组合是不正确的:
SUB SP, 2
相关文档
最新文档