⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 汇007.txt

📁 会变语言实现的一些程序
💻 TXT
📖 第 1 页 / 共 3 页
字号:
.END 
7.5.10 局部变量的定义
局部变量的定义格式:

LOCAL 变量名[[数量]] [:数据类型] [,变量名[[数量]] [:数据类型]]...

伪指令LOCAL的作用是说明一个或多个临时的局部变量(位于堆栈中)。局部变量必须在任何指令之前加以说明,并可用多个LOCAL伪指令来说明其局部变量。

在子程序中,若说明了某个局部变量,则子程序体中的指令就可使用该局部变量。汇编程序会把对它的引用转换成用指针寄存器BP来访问其在堆栈中的实际存储单元。

在局部变量的作用域与高级语言中局部变量的作用域相一致,即:局部变量只能在当前子程序中使用,离开该子程序,它们就不能再被引用。但在局部变量的命名规则上有所不同,高级语言中的局部变量可与外层变量同名,而汇编语言中的局部变量不能与其它任何变量同名,否则,在汇编时,将会给出“重定义”(Symbol redefinition)的错误信息。

“数量”用来说明该变量所具有的元素个数。象高级语言的数组定义一样,该数量必须写在括号“[ ]”之中。“数量”说明项是可选项。

局部变量的类型说明符可以是任何合法的数据类型说明符。在16位段环境下,该缺省的数据类型是WORD,而在32位段环境下,该缺省的数据类型是DWORD。

此处伪指令LOCAL的作用与9.3.1节中伪指令LOCAL的作用是完全不同的,具体的差异请见9.3.1节中的比较。

例如:

LOCAL data[20]:BYTE, num:WORD

在上例的说明中,定义了二个局部变量:data和num。前者是字节类型,并有20个元素,后者是字类型,只有其自身1个元素。
7.6 子程序库
库文件对学过C/C++语言程序设计的读者来说应该是不会陌生的,该语言的程序设计环境提供了大量的库文件,也就是说,提供了大量的标准函数或过程。在本节里,介绍读者如何创建自己的库文件。

7.6.1 建立库文件命令LIB
宏汇编MASM系统提供了建立库文件的命令文件LIB.EXE。其通常是在命令行环境(MS-DOS方式)下使用的,当然,也可在Windows 95/98等环境下利用其“开始”菜单下的“运行”功能项来使用。

一、MS-DOS系统

显示命令LIB用法的命令如下:

…>lib /?

该命令的显示结果如图7.9中所示。

二、Windows系统



图7.8 运行LIB命令的画面



图7.9 显示LIB命令功能的画面

命令LIB的使用方式和显示结果如图7.8和7.9所示。

三、命令显示内容的解释

1)、各选项的解释

选项 含义 
/?、/HELP 显示LIB命令的用法,描述各命令行参数的含义 
/IGNORECASE 忽略子程序名中的大小写 在实践中,作用不明显 
/NOIGNORECASE 不忽略子程序名中的大小写 
/NOEXTDICTIONARY 不建立扩展的目录 
/NOLOGO 不显示版本号和版权信息 
/PAGESIZE:n 设置库文件的每页字节数为n 

2)、命令项的解释:

选项 含义 
+name 向库文件中加一个新的目标文件 
-name 从库文件中删除一个指定的目标文件 
-+name 用新的目标文件替换掉库文件中原有的目标文件 
*name 拷贝出指定的目标文件 
-*name 从库文件中移出指定的目标文件 

在弄懂了LIB的各项功能含义后,读者就可根据自己的需要来建立库文件了。

7.6.2 建立库文件举例
假设现有目标文件sub1.obj、sub2.obj和sub3.obj,要用它们建立库文件mylib.lib。可用下列方法来建立该库文件:

方法1:所有目标文件都准备好了,可一次性把它们加入到库文件中

…>lib  mylib +sub1 +sub2 +sub3

方法2:随着目标文件的逐个生成,而依次把它们加入到库文件中

…>lib  mylib +sub1
…>lib  mylib +sub2
…>lib  mylib +sub3

假如源文件sub3.asm已修改,并也生成了新的目标文件sub3.obj,这时,就需要把库文件mylib.lib中的sub3.obj替换成新的目标文件。于是,可用下面命令来实现替换:

…>lib  mylib  -+sub3

当提示输入目标库文件名(Output library)时,可按“回车”用默认的原库文件名。

如果想查看库文件mylib.lib中各文件的大小和存放的先后次序,可用下列命令:

…>lib  mylib, list     ;把库文件mylib.lib中的文件结构生成到文件list中
…>type  list
7.6.3 库文件的应用
在开发一个功能较弱的应用程序时,其执行文件通常可由一个目标文件连接而成,当开发一个功能较强、关系较复杂的应用程序时,其执行文件很难由一个目标文件连接而成,常常是由多个目标文件(模块)连接而成的。各模块之间无疑会存在着相互调用、相互访问数据单元等内在联系,各模块之间的相互联系就产生了这样的问题:程序员如何在源程序中来表达这种联系?

为了解决描述各模块之间的联系,汇编语言提供了二条伪指令PUBLIC和EXTRN,它们的作用有点象C/C++语言说明变量、过程和函数是“全局的”或“外部的”。

这二条伪指令的具体用法和含义如下:

1、伪指令PUBLIC

伪指令PUBLIC是用来说明:当前模块中哪些标识符是能被其它模块引用的公共标识符。其说明的一般格式如下:

PUBLIC 标识符1, 标识符2, ……

其中:“标识符”可以是变量名、过程名和程序标号,各标识符之间要用逗号分开。

上面说明语句说明了标识符1、标识符2等是公共标识符,可以被其它模块引用。在一个模块中,可用多条PUBLIC伪指令来说明公共标识符。

2、伪指令EXTRN

伪指令EXTRN是用来说明:在当前模块所使用的标识符中,哪些标识符是已在其它模块中被定义为指定类型的标识符。如果当前模块使用了其它模块的标识符,而对它又不加以说明的话,那么,在汇编时,汇编程序将会给出下列出错信息:

error nnnnn: undefined symbol : XXXXXX

其中:“nnnnn”是错误号,“XXXXXX”是当前模块中没有定义的标识符。

伪指令EXTRN的一般说明格式如下:

EXTRN 标识符1:类型1, 标识符2:类型2, ……

其中:“标识符”和“类型”之间要用冒号“:”连接。

上面语句说明了标识符1、标识符2等是外部标识符,它们在其它模块中已被分别定义为类型1、类型2等,该类型说明符可以是:NEAR、FAR、BYTE、WORD、DWORD等之一。如果在一条说明伪指令中说明了多个标识符,那么,各标识符之间要用逗号分开。

在一个模块中,可用多条EXTRN伪指令来说明本模块所引用的外部标识符。

注意:伪指令EXTRN中所说明的标识符必须在其定义的模块中被PUBLIC伪指令说明为公共标识符,并且其说明的标识符类型要与该标识符在定义是的类型相一致,否则,要么不能生成其可执行文件,要么其执行文件不能正确运行。
例7.7 把例7.3、7.4和7.5合并在一起生成一个可执行文件,假设它们所对应的源程序名分别为Count.ASM、DispBX.ASM和Main.ASM。

解:由于在源文件Count.ASM中调用了子程序UPPER,所以,例7.1的程序也必须加入到本题中。假设其源文件名为Upper.ASM。

由于生成本题的执行文件需要四个模块,模块之间存在着调用关系,所以,在有关源文件中需要说明某些标识符为外部属性,或说明其为公共属性。

为了把前面例子中的子程序改写成可汇编的程序,需要添加一些简单的说明语句或进行简单修改,其添加或改写的部分已在下面用“下划线”表示出来。  ;源文件Upper.ASM 
;子程序说明信息:…… 
PUBLIC UPPER 
SegUpr SEGMENT 'code' 
UPPER PROC FAR 
…… ;例7.1中的程序段,在此从略 
UPPER ENDP 
SegUpr ENDS 
END 
;源文件DispBX.ASM
;子程序说明信息:…… 
PUBLIC DISPBX 
SubData SEGMENT 
DB
 5 DUP('0'), 0ah, 0dh, '$' 
SubData ENDS 
SegDisp SEGMENT  'code' 
DISPBX PROC  FAR 
…… ;例7.3中的程序段,在此从略 
DISPBX ENDP 
SegDisp ENDS 
END 
;源文件Count.ASM
;子程序说明信息:……
 
PUBLIC COUNT 
EXTRN UPPER:FAR 
SegCount SEGMENT  'code' 
COUNT PROC  FAR 
…… ;例7.4中的程序段,在此从略 
COUNT ENDP 
SegCount ENDS 
END 
;源文件Main.ASM 
EXTRN COUNT:FAR, DISPBX:FAR 
.MODEL SMALL 
.DATA 
 STR DB 'KSDJ L0984/[]3oiu OIU OIU (*&(5341', 0 
.CODE 
 .STARTUP 
LEA DX, STR 
CALL COUNT ;调用子程序统计出各类字符的个数 
CALL DISPBX ;调用子程序显示数字字符的个数 
MOV BX, CX 
CALL DISPBX ;调用子程序显示字母的个数 
MOV BX, DI 
CALL DISPBX ;调用子程序显示其它字符的个数 
.EXIT 0 
END 


经过以上改写后,可用下列命令把它们分别汇编成目标文件(假设已安装了MASM编程环境):

…>MASM  upper
…>MASM  dispbx
…>MASM  count
…>MASM  main

有了这些目标文件后,可用以下二种方法来生成可执行文件。

方法1:把所有的目标文件连接在一起

…>link  main+upper+count+dispbx

方法2:把目标文件upper.obj、count.obj和dispbx.obj加到自己开发的库文件中,然后在连接时,与该库文件连接。

…>lib  mylib +upper +count +dispbx
…>link  main
Microsoft (R) Segmented Executable Linker  Version 5.31.009 Jul 13 1992
Copyright (C) Microsoft Corp 1984-1992.  All rights reserved.
Run File [main.exe]:
List File [nul.map]:
Libraries [.lib]: mylib      ;输入要连接的库文件,可用加号“+”连接多个库文件
Definitions File [nul.def]:
LINK : warning L4021: no stack segment

…>main            ;运行生成的文件

以上各步骤也可由集成开发环境PWB来完成,具体介绍请见附录1。另外,当模块的指令条数较少时,也可以把几个子模块合在一个源文件中。
7.6.4 库文件的好处
程序员在编写源程序时,通常采用模块化的思想来组织源程序:把各类不同的子程序分别编写在不同的源程序中,在各源程序中说明所用到的在其它模块中定义,或说明本模块的定义子程序可被其它模块调用。这样组织后,就可以分别汇编它们而得到其相应的目标文件,在有了这些目标文件后,就可生成最终的可执行文件,但可用不同的方法来生成最终的可执行目标文件。

方法1:直接连接目标文件而生成可执行文件(如上节例7.6中的方法1所示)

这种方法简单、方便,也是常用的一种方法,但在连接时,LINK程序会把目标文件中的所有代码都嵌入到执行文件中,从而使得:包含在某目标文件中、但并没有被调用的子程序代码也出现在执行文件中。这种情况无疑增加了执行文件的字节数。

方法2:采用子程序库的方法(如上节例7.6中的方法2所示)

库文件可以把它看成是子程序的集合。库文件中存储着子程序名、子程序的目标代码以及连接所需要的重定位信息。当某目标文件与库文件相连接时,LINK程序只把目标文件所用到的子程序从库文件中找出来,并合并到最终的可执行文件中,而不是把库中所含的全部子程序都纳入最后的可执行文件。

对照方法1和2可知:用库文件来存储子程序可生成较短的执行文件。
7.7 习题
7.1、汇编语言的子程序是如何定义的?所使用的关键字有哪些?
 
7.2、为了编写具有良好风格的子程序,一般需要书写哪些重要的说明性信息?
 
7.3、简述调用指令CALL和转移指令JMP之间的主要区别。
 
7.4、简述段内和段间子程序调用指令CALL的主要区别。
 
7.5、子程序返回指令RET的功能能否用JMP指令来模拟,若可以,请用段内子程序的返回加以说明,否则,说明理由。
 
7.6、子程序返回指令“RET 6”的功能是返回数值“6”给调用程序吗?若不是,那其作用是什么?
 
7.7、在子程序中要使其所用寄存器对调用者是透明的,请举例说明达到其目的的方法。
 
7.8、编写子程序实现下列功能,参数的传递方式可自行决定(假设所有变量都是字类型)。
 
1)、ABS(x)=|x|
2)、f(x)=3x2 + 5x – 8
3)、strlen(String)    //返回字符串String的长度,该字符串以0结束
4)、判断三条边a、b和c能否构成三角形,若能,CF为1,否则,CF为0
 
7.9、编写计算将CX值三次方的子程序,结果也存入CX(不考虑溢出问题)。
 
7.10、编写计算表达式AX=DI×SI/100H的子程序(不考虑溢出问题)。
 
7.11、编写计算EAX=EAX+EBX+ECX+EDX的子程序。在计算过程中,若产生进位,则EDI=1,否则,EDI=0。
 
7.12、在MASM 6.x编程环境下,简述子程序定义中USE说明语句的作用是什么?
 
7.13、调用子程序指令CALL和调用伪指令INVOKE的主要区别是什么?
 
7.14、在子程序的完全定义形式中,其语言类型所起的作用是什么?可用哪二种方法来设定子程序的语言类型?
 
7.15、如何指定子程序的传递参数是动态的,对动态参数有哪些规定?
 
7.16、编写一个子程序,其功能是把其所有参数数值之和存入AX中,每个参数都数16位二进制数,但个数不定。
 
7.17、子程序的参数传递有传值和传地址之分,在汇编语言中,如何实现传地址?请举例说明。
 
7.18、在高级语言中,子程序可定义其局部变量,在汇编语言中,能定义其局部变量吗?若能,请举例说明。
 
7.19、使用.REPEAT和.UNTIL语句编写一个子程序,其功能是从DS:SI开始的内存单元中查找是否有与AL相同的数值。若找不到,CF=0,否则,CF=1,且SI指向所找到位置。假设查找区域以0为结束标志。
 
7.20、用.REPEAT和.UNTILCXZ语句编写一个子程序,用以在内存缓冲区中填入00H。内存缓冲区的首址及长度分别由DS:SI和CX来确定。
 
7.21、用.WHILE和.ENDW语句实现7.16和7.17的功能。
 
7.22、在程序模块中,伪指令PUBLIC和EXTRN的作用是什么?
 
7.23、在C语言程序中,存在关键字EXTERN,它与汇编语言中EXTRN的作用相似吗?
 
7.24、如何创建和维护自己的子程序库?使用子程序库有何好处?
 


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -