我是靠谱客的博主 简单棒棒糖,最近开发中收集的这篇文章主要介绍子程序结构,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

子程序结构
子程序又称为过程,相当于高级语言中的过程和函数,是模块化程序设计的基础
1、过程定义伪操作
过程定义伪操作用在过程(子程序)前后,使整个过程形成清晰的、具有特定功能的代码块。其格式为:
procedure name PROC Attribute
    ….
procedure name ENDP
其中过程名为标识符,它又是子程序入口的符号地址。属性指类型属性,它可以是NEAR或FAR
CALL和RET指令都有NEAR和FAR属性,段内调用使用NEAR属性,段间调用使用FAR属性。为了方便用户,80x86的汇编程序用PROC伪操作的类型属性来确定CALL和RET指令的属性。用户只需在定义过程时考虑它的属性,而CALL和RET的属性可以由汇编程序来确定。用户对过程属性的确定原则很简单:
如调用程序和过程在同一个代码段中,则用NEAR属性
如调用程序和过程不在同一代码段中,则用FAR属性
过程定义可以嵌套
2、子程序的调用和返回
过程的正确执行是由子程序的正确调用和正确返回保证的。80x86的CALL和RET指令完成的就是调用和返回的功能。为保证其正确性,除PROC的属性要正确选择以外,还应该注意子程序运行期间的堆栈状态。由于CALL时已使返回地址入栈,所以RET时应该使返回地址出栈,如果子程序中不能正确使用堆栈而造成执行RET前SP并未指向进入子程序是的返回地址,则必然会导致运行出错。
3、保护和恢复寄存器
一般来说,子程序中用到的寄存器是应该保存的。但是,如果使用寄存器在主程序和子程序之间传送参数的话,则这种寄存器就不一定需要保存,特别是用来向主程序回送结果的寄存器,就更不应该因保存和恢复寄存器而破坏了应该向主程序传送的信息
4、子程序的参数传递
调用程序在调用子程序时,经常需要传送一些参数给子程序;子程序运行完后也经常要回送一些信息给调用程序。这种调用程序和子程序之间的信息传送称为参数传送。参数传送方式有以下几种
(1)通过寄存器传送参数
(2)如过程和调用程序在同一源文件中,则过程可直接访问模块中的变量
(3)通过地址表传送参数地址
在主程序中建立一个地址表,把要传送给子程序的参数都存放在地址表中,然后把地址表的首地址通过寄存器BX传送到子程序中去。子程序通过地址表取得所需参数,并把结果存入指定的存储单元中去
(4)通过堆栈传送参数或参数地址
在主程序里把参数地址保存到堆栈中,在子程序里从堆栈中取出参数以达到传送参数的目的。子程序结束时的RET指令应适用带常数的返回指令,以便返回主程序后,堆栈能恢复原始状态不变
(5)多个模块之间的参数传送问题
外部符号:从连接的角度看,在源程序中用户定义的符号可以分为局部符号和外部符号两种。在本模块中定义,又在本模块中引用的符号称为局部符号;在某一个模块中定义,而又在另一个模块中引用的符号称为外部符号。有两个伪操作与外部符号有关:
PUBLIC symbol[,…]
EXTRN symbol name : type[,]
在一个模块中定义的符号(包括变量、标号、过程名)在提供给其他模块使用时,必须要用PUBLIC定义该符号为外部符号
在另一个模块中定义而要在本模块中使用的符号必须使用EXTRN伪操作。如符号为变量,则类型应为byte,word,dword等;如符号为标号或过程名,则类型应为near或far
这两个伪操作的使用必须相匹配,连接程序会检查每个模块中的EXTRN语句中的每个符号是否能和与其相连接的其他模块中的PUBLIC语句中的一个符号相匹配。
局部符号是在汇编时就确定了其二进制值,所以并不影响模块的连接,不同模块中的局部符号是允许同名的,但要连接模块的外部符号却不允许同名,如有同名,连接将显示错误。外部符号在汇编时是不可能确定其值的,连接程序可分配段地址、确定外部符号及浮动地址值,连接完成后建立了装入模块,再由装入程序把该模块装入内存等待执行
多个模块之间的参数传送方法:
模块之间使用公用数据段
在引用外部符号时,把相应的段地址放入段寄存器中,如果程序中要访问的变量处于不同的段时,动态地改变寄存器的内容
5、增强过程定义伪操作
从MASM5.1版开始为用户提供了增强功能的过程定义伪操作,其格式为:
procname PROC [attributes field][USES register list][,parameter field]
    ….
procname ENDP
其中属性字段由以下几项组成:
distance language type visibility prologue
distance就用NEAR或FAR
language type说明党该过程作为某种高级语言程序的子过程时所用的高级语言
visibility说明该过程的可见性,可用Private和Public。如用Private,则该过程的可见性只能是当前的源文件,如用Public,则允许其他模块调用该过程
prologue是一个宏的名字,允许用户用宏来控制过程的入口和出口相关的代码
USES字段允许用户指定所需保存和恢复的寄存器表,MASM程序将在过程的入口自动生成push指令来保存这些寄存器,并在过程出口的ret指令前自动生成pop指令来恢复这些寄存器
参数字段允许用户指定该过程所用参数,其格式为:
identifier:type [,identifier:type]
其中,identifier给出参数的符号名,type给出参数的类型。参数之间用逗号隔开。MASM将自动把这些参数转换为 [BP+4]、[BP+6]等形式
C near调用:
(BP-4)——>需要保存和恢复的寄存器
(BP-2)——>局部变量区
(BP)——>原始BP
(BP+2)——>返回地址IP
(BP+4)——>par1
(BP+6)——>par2
(BP+8)——>par3
C far调用:
(BP-4)——>需要保存和恢复的寄存器
(BP-2)——>局部变量区
(BP)——>原始BP
(BP+2)——>返回地址IP
(BP+4)——>返回地址CS
(BP+6)——>par1
(BP+8)——>par2
(BP+A)——>par3
增强功能的过程定义伪操作除具有以上功能外,还可在过程中定义局部变量
局部变量是指在过程内部使用的变量。它是在过程被调用时在堆栈中建立的,在退出过程时被释放。在过程调用期间位于BP指针的正偏移量区是返回地址和参数区,而BP指针的负偏移量区则是局部变量区
MASM规定,在过程内可以用LOCAL为局部变量申请空间,其格式为:
LOCAL vardef [,vardef]
其中,变量定义可用的格式为:
label
label:type
label[count]:type
LOCAL语句必须紧跟在过程定义伪操作之后,并在任何80x86指令或可以产生任何代码的MASM语句之前出现。MASM将为所定义的变量在堆栈中的BP负偏移量区生成空间,并为每个局部变量名生成如[BP-2],[BP-4]等代码

最后

以上就是简单棒棒糖为你收集整理的子程序结构的全部内容,希望文章能够帮你解决子程序结构所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(68)

评论列表共有 0 条评论

立即
投稿
返回
顶部