服务热线

13103866733
网站导航
主营产品:
产品展示
当前位置: 首页 > 案例展示

第6章子程序_

产品时间: 2024-12-14 08:39:31 |   作者: 乐鱼官网客户端

详细介绍

  SS:SP所指向的内存,即把标志寄存器入栈。 【指令格式】POPF 【功能】把栈顶的一个16位的字型数据送入标志寄存器, 并把SP的值加2。

  这两条指令除了用于临时保存标志寄存器的值之外, 还可以与PUSH、POP指令配合用于设置标志寄存器中的 任意一个标志位。一般的做法是先用两条指令 PUSHF

  图6.1是堆栈的物理结构示意图,图中标出的SS和SP是与 堆栈紧密关联的寄存器,SS存放堆栈所占用内存区域的段地 址,SP所指向的位置称为栈顶。 一个程序如果要使用堆栈,必须先留出一片连续内存区

  寻址,当使用内存型寻址方式时能够正常的使用段跨越。 (2)PUSH指令的功能包括移动栈顶和存入数据两部分, 两部分连续完成,密不可分。

  第6章 子 程 序 (3)操作数d进栈是以减2以后的SP的值作为偏移地址,

  址寄存器用作偏地址时的写法相混淆,也就是说,把PUSH 指令理解成下面两条指令的组合是不正确的: SUB SP, 2 MOV [SP], d 因为指令“MOV [SP], d”存在语法错误。

  的调用都是段间调用。子程序2是NEAR类型,对它的调 用都是段内调用,调用指令“CALL 子程序2”必须与子程 序2在同一段内,否则就没办法正确地实现转向及返回。在上 面的例子中,从子程序1中调用子程序2就是错误的。

  【例6.2】分析下面的程序段的执行过程,以及在执行过 程中堆栈及指令指针IP的变动情况,并假设在执行CALL指令 前,SP的值是0FEH。 subp PROC

  【指令格式】POP  d 【功能】从SS为段地址、SP为偏移地址对应的内存中取 出一个字型数据,送到操作数d指定的位置,然后把SP的值 加2。对操作数d的寻址方式要求与PUSH指令相同。 堆栈通常用于临时保存数据。一般做法是先用PUSH指 令把需要保存的数据入栈,然后完成一定的指令序列,再用

  第6章 子 程 序 一个程序如果要使用堆栈,必须先留出一片连续内存区 域,方法是在程序中定义一个堆栈段。 【格式】 段名 DW 段名 SEGMENT n DUP(?) ENDS STACK

  第6章 子 程 序 (3)按基本格式定义的栈是一个空栈,栈中没有存放 有效数据。 (4)为了使SS和SP在程序执行时取得正确的值,必须 在源程序中写一条伪指令:

  子程序具有固定的功能,这种功能在一个程序或多个程 序中经常反复使用。使用子程序的目的就在于编程时不愿意 把相同的程序段在每个需要使用的地方抄写一遍。在汇编语 言程序中,子程序分为定义和调用两种情况:子程序定义是 指按6.2.1节的格式编写程序段;而子程序调用是指用 “CALL 子程序名”告诉CPU在执行到此处时转到相应的子 程序去执行。在较短的程序中,可以把子程序定义与其余指 令写在同一个代码段内。一个代码段中可以定义多个子程序, 并且都定义成NEAR类型。对于代码较长的程序,可以把子 程序与主程序分别在不同的段中编写,并把允许段间调用的

  6.3 应用子程序进行编程 6.4 整数输入与输出 6.5 子程序共享的方法 *6.6 递归

  子程序是程序设计的重要方法与技术之一。程序设计中 经常会遇到重复出现的程序段,如果把这种程序段每次出现 时都抄写一遍,一方面会使程序冗长,不易于阅读,另一方 面则会给程序的调试和维护带来很多不便。通常,对于有规 律重复的程序段可以编制成循环程序,而无规律的重复就无 法用循环实现。比如,实现回车换行功能虽然是一个很短小 的程序段,却在很多程序中常常使用,并且在程序中的位置

  把标志寄存器的值复制到AX中,然后按标志位的分布情 况(见图2.3)和实际要,用AND、OR、XOR等指令修改 AX的相应位,再用两条指令 PUSH AX POPF 把修改后的值送到标志寄存器中。

  第6章 子 程 序 【解】 (1)当计算机把CALL subp对应的机器指令取到CPU中

  CALL也是一种跳转指令,与无条件跳转及条件跳转指 令不同的是,CALL在跳转之前先预留了回来的方法,把IP 的当前值或CS与IP的当前值入栈保存。从CS与IP 的作用可 以知道,它们存放的是正在执行的指令的下一条指令的逻辑

  而易见了,只要从栈中取出逻辑地址值,送回IP或者CS与IP 即可。这种返回操作就是由RET指令实现的。

  址5678H,此时还未进栈,栈的情况如图6.3(a)所示。 (2)由于子程序subp是NEAR类型,按照CALL指令功能 的第一种情况执行CALL指令,把IP的值入栈,并把IP的值改 为subp子程序的入口地址1234H,此时堆栈的情况如图6.3(b) 所示。 (3)执行完CALL指令 IP的值已经变成1234H,CS没变, CPU按新的IP值,在CS段下取出一条指令,即INC AL指令。

  序列之中。根据所在的子程序的类型不同,RET指令的功能 也分为两种情况: (1)如果RET所在子程序是NEAR类型,则从堆栈中出 栈一个字(当然,SP会加2),送给IP。

  第6章 子 程 序 从“入口标号”起编写主程序部分,整个程序从 “入口标号”所在的那条指令开始执行。主程序能调用

  序可以调用另一个子程序,还可以调用它自身,并且在书 写次序上没有“先定义后调用”的限制。子程序1是FAR

  由DOS本身完成的,DOS将把SS赋值为堆栈段的段地址, 把SP赋值为2n。

  栈操作指令以它特有的方式存取数据,属于数据传递类 指令,但又与MOV等指令有很大的区别。

  令之间的指令序列是完成子程序固定功能的程序段,通常 指令序列的最后一条指令是返回指令RET。

  不用定义变量,不必关心被保存的数据到底在栈的什么位置, 只要保证出栈和进栈的对应关系即可。当CPU中的寄存器不

  已入栈的数据存放区(见图6.1),例6.1用来说明PUSH指令和 POP指令对堆栈的影响。

  第6章 子 程 序 6.1.2.1 PUSH指令 【指令格式】PUSH  d 【功能】先把SP的值减去2,然后把操作数d指明的字型 数据放入以SS为段地址、SP为偏移地址所对应的内存单元中。

  程序基本格式如下: 子程序名 PROC 类型 指令序列 子程序名 ENDP

  第6章 子 程 序 格式中的首尾两行表示一个子程序的开始和结束,都 属于伪指令。“子程序名”是一个标识符,是编程者给子 程序起的名字。子程序名同时还代表子程序第一条指令所 在的逻辑地址,称为子程序的入口地址。“类型”只有 NEAR和FAR两种,它将影响汇编程序对子程序调用指令

  第6章 子 程 序 (4)PUSH指令会导致栈顶指针的移动,如果用 PUSH指令把很多数据进栈,使SP不断减2,就有可能超

  栈溢出错误,但8088对此并不做任何检测和警告。因此 要求编程人员自己注意控制堆栈的大小,估计可能进栈

  及无条件跳转一样,都是经过仔细修改IP或者CS与IP来实现的。 不论跳转是由哪一条指令造成的,对于只改变IP 的跳转,

  转称为段内跳转。相应地,CALL指令功能的第一种情况称 为段内调用,RET指令功能的第一种情况称为段内返回。 另一种跳转是同时改变了CS和IP的值,这就允许跳转指令 与跳转目的地不在同一个段中,使得跳转的目的地可以在 整个内存空间的任何位置,这一类跳转称为段间跳转。 CALL指令功能的第二种情况称为段间调用,RET指令功能 的第二种情况称为段间返回。

  别逐条执行下列指令,用内存图的形式画出堆栈的变动情况, 并分析程序段执行完后AX和BX寄存器的值。 PUSH AX PUSH BX POP AX POP BX

  第6章 子 程 序 【解】堆栈变化见图6.2,程序段执行完后AX=307CH, BX=4F8AH。

  (1) 如果子程序是NEAR类型,则先把当前指令指针IP的 值入栈,这会使SP的值减2,然后把IP改成子程序的第一条指

  (2) 如果子程序是FAR类型,则先把当前CS的值入栈, 再把IP的值入栈,结果会使SP的值减4,然后把CS和IP改为 子程序第一条指令的逻辑地址。这种同时修改CS和IP的子程 序调用称为段间调用。

 


关注我们