第7章 宏和多模块程序设计_第1页
第7章 宏和多模块程序设计_第2页
第7章 宏和多模块程序设计_第3页
第7章 宏和多模块程序设计_第4页
第7章 宏和多模块程序设计_第5页
已阅读5页,还剩106页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、第7章宏和多模块程序设计,7.1宏7.2宏嵌套7.3重复汇编伪指令和条件汇编伪指令7.4宏汇编语言源程序举例和宏与子程序的区别7.5多模块程序设计7.6汇编语言与高级语言的连接,7.1宏,7.1.1宏定义7.1.2宏调用7.1.3宏展开7.1.4宏的参数传递7.1.5特殊宏操作符7.1.6宏中的变量和标号,返回首页,7.1.1宏定义,一、在使用宏之前必须先定义宏,宏的定义是使用伪指令MACRO和ENDM来实现的。1.宏定义的一般格式:宏名MACRO形参1,形参2,;宏的定义体ENDM(1)宏名:由程序员指定的一个合法的标识符,它代表该宏。宏名可以与指令助忆符、伪指令名相同,在这种情况下,宏指令

2、优先。建议宏名尽可能不要与指令助忆符、伪指令相名,以免引起不必要的误会。,(2)MACRO和ENDM是二个必须成对出现的关键字,它们分别表示宏定义的开始和结束,在ENDM的前面不要再写一次宏名,这与段或子程序定义的结束方式有所不同;(3)“宏体”:MACRO和ENDM之间的部分,由指令、伪指令或引用其它宏所组成的程序片段,是宏所包含的具体内容;(4)在宏定义的首部可以列举若干个形式参数,每个参数之间要用逗号分隔。(形式参数:定义中仅指明了使用哪些参数(参数名),但未具体说明参数值。实参数:参数值在引用宏时给出。),【例7-1】定义一个实现两个16位的带符号数存储变量相加的宏。宏名为MADDM。

3、解:程序段如下:MADDMMACROOPRD1,OPRD2;定义一个宏名为MADDM,;形参为OPRD1和OPRD2的宏MOVAX,OPRD2;本句和下句为宏体中的内;容ADDOPRD1,AX;实现两数相加,结果送;OPRD1变量ENDM;宏定义结束上述宏定义虽然能满足题目的要求,但由于在定义体中改变了寄存器AX的值,这就使宏的引用产生了一定的副作用。,为了使寄存器AX的使用变得透明,可把该宏定义改成如下形式:MADDMMACROOPRD1,OPRD2;定义一个宏名为MADDM,形参为OPRD1和OPRD2的宏PUSHAX;将AX寄存器的内容压入堆栈;保护AX存器的值MOVAX,OPRD2;A

4、DDOPRD1,AXPOPAX;恢复AX寄存器的值ENDM;宏定义结束通过在宏定义的开始和结尾分别增加对所用寄存器的保护和恢复指令,就使得对该宏的任意引用都不会产生任何副作用。,返回本节,7.1.2宏调用,一、在源程序中,一旦定义了某宏,那么,在该程序的任何位置都可直接引用该宏,而不必重复编写相应的程序段。1.引用宏的一般格式如下:宏名实参1,实参2,说明:(1)宏名必须与宏定义中的宏名一致;(2)实参的位置要与形参的位置要对应,但实参的个数可以与形参的个数不相等。当实参的个数多于形参的个数时,多出的实参被忽略;当实参的个数少于形参的个数时,没有实参对应的形参用“空”来对应。但在宏展开时,所得

5、到的指令必须是合法的汇编指令,否则,汇编程序将会给出出错信息。,例如:调用例7-2所定义的宏DISPMSG,实现字符串的输出。程序段如下:DISPMSGMESSAGE1DISPMSGMESSAGE2DISPMSGMESSAGE3,返回本节,7.1.3宏展开,一、定义在源程序中,由于宏定义在前,宏调用在后,宏汇编程序在汇编期间,将先扫描宏定义,将宏名、形参、宏体均填入宏定义表中,以后遇到宏调用时,则嵌入宏体,并用实参按位置对应关系一一替换宏体中的形参,这一过程称为宏展开。宏展开是在汇编期间由汇编程序自动完成的。,针对上述的三次宏调用,其展开后得到下列语句:第一次宏调用后,展开的语句序列。PUSH

6、DXPUSHAXLEADX,MESSAGE1MOVAH,09HINT21HPOPAXPOPDX,第二次宏调用后,展开的语句序列。PUSHDXPUSHAXLEADX,MESSAGE2MOVAH,09H;INT21HPOPAXPOPDX第三次宏调用后,展开的语句序列。PUSHDXPUSHAXLEADX,MESSAGE3MOVAH,09H;,INT21HPOPAXPOPDX宏调用时,在汇编期间被展开,调用一次展开一次。虽然多占用一些空间,但是使用方便,适合短代码程序段。,返回本节,7.1.4宏的参数传递,一、在引用宏时,参数是通过“实参”替换“形参”的方式来实现传递的。注意:(1)参数可以是常数、寄

7、存器、存储单元和表达式,还可以是指令的操作码。(2)由以上程序段可知,宏使用的参数非常灵活,但在宏展开后,所得到的指令必须是合法的汇编指令-如下例:,【例7-3】定义一个实现两个带符号的16位数相乘的宏,宏名为MULTIPLY,并在源程序中调用该宏。解:程序段如下:;宏定义MULTIPLYMACROOPR1,OPR2,RESULT;定义一个宏名为;MULTIPLY形参为:;OPR1,OPR2,RESULTPUSHDXPUSHAXMOVAX,OPR1;将乘数送AX寄存器IMULOPR2;将(AX)与OPR2相乘,结果送寄存器DX和AXMOVRESULT,AX;将结果的低16位送RESULT存储单

8、元MOVRESULT+2,DX;将结果的高16位送RESULT的下一个存储单元POPAXPOPDXENDM;宏定义结束,;宏调用MULTIPLYCX,VAR,,YZBX;形参分别为寄存器,;存储单元和存储单元以上宏调用后,宏展开的语句序列为:PUSHDXPUSHAXMOVAX,CXIMULVAR;VAR不能为立即数MOVXYZBX,AXMOVXYZBX+2,DXPOPAXPOPDX形参OPR2所对应的实参VAR可以是寄存器操作数或存储器操作数,但不能为立即数和段寄存器,否则,汇编程序将会给出出错信息。,【例7-4】定义一个能实现对存储变量进行的加、减操作合并在一起的宏。宏名为MOPM。解:程序

9、段如下:;宏定义MOPMMACROOP,OPRD1,OPRD2MOVAX,OPRD2OPOPRD1AXENDM;宏调用MOPMSUBA1,A2;形参分别为指令,变量和变量MOPMADDB1,B2;形参分别为指令,变量和变量它们在宏展开时将会得到下列语句:MOVAX,A2SUBA1,AXMOVAX,B2ADDB1,AX,返回本节,7.1.5特殊宏操作符,1.字符串整体传递运算符“”在宏调用中,有时实参是一串带间隔符空格或逗号的字符串,为了不致混淆(把一个实参看成几个实参),应该用尖括号将它们括起来。【例7-5】定义一个宏,实现堆栈段的定义。解:程序段如下:;宏定义:STMACROASTACKSE

10、GMENTSTACKDBASTACKENDSENDM,;宏调用ST;实参为“500DUP(0)”,宏调用实现功能:建立一个500个字节,赋初值为0的堆栈段。说明:在以上宏调用时,由于实参中间带有空格,因此要用尖括号括起来,说明该语句为一个实参,以上宏扩展后的语句序列为:STACKSEGMENTSTACKDB500DUP(0)STACKENDS2计算表达式运算符“%”有时需要以实参符号的值而不是符号本身替换形参,这种参数的替换称为数字参数的替换用操作符“%”将其后的表达式转换成它所代表的数值,并将些数值的ASCII码字符嵌入到宏扩展中。,例如,有以下宏定义:DATAMACROA,B,CDBA,B

11、DBCDUP(0)ENDM如果存在以下宏调用:X=1Y=2DATAX,4,X+YDATA%X,4,%X+Y则宏扩展后的语句序列为:X=1Y=2DBX,4DBX+YDUP(0)DB1,4DB3DUP(0),%后的符号一定是直接用EQU或等号赋值的符号常量或者汇编时能计算出来的表达式而不能是变量名和寄存器名。,3.连接运算符“转移到SQR2,结束循环的条件,INCAX;若CF1,够减,寄存器AX加1,记录减法的次数,最后即得所求数的平方根值ADDCX,2;奇数递增JMPSQRl;跳到SQRl,循环作减法SQR2:POPDX:现场恢复POPCX;现场恢复ENDM;宏定义结束宏定义结束XORBX,BX

12、;BX清0,存放平方根之和IRPY;重复汇编伪指令,求三次平方根的和SQROTY;宏调用SQROTADDBX,AX;累加平方根ENDM;重复汇编伪指令结束,MOVSUM,BX;将最后结果送SUM内存单元MOVAH,4CHINT21HCODEENDSENDSTART,【例7-16】采用宏的方法实现例4-10:计算S=1!+2!+7!+8!解:解题思路与例4-10相似,区别在于把计算任一正整数i的阶乘i!编写成为一个宏FACTORIAL。8次累加用重复汇编伪指令IRPC实现。源程序如下:DATASEGMENTSUMDW?;定义SUM变量用来保存最终结果DATAENDSCODESEGMENTASSU

13、MECS:CODE,DS:DATASTART:MOVAX,DATAMOVDS,AX;宏定义开始,FACTORIALMACRON;宏定义,形参为NLOCALNEXT;说明NEXT为局部标号PUSHAXPUSHCXMOVAX,1;AX存放N!,初值为1MOVCL,N;循环次数送入寄存器CLNEXT:MULCL;计算N!LOOPNEXTPOPCXPOPAXENDM;宏定义结束;宏定义结束,XORBX,BX;BX清0,存放阶乘之和IRPCY12345678;重复伪指令,形参为Y,实参为12345678FACTORIALMACROY;宏调用,求N!ADDBX,AX;计算阶乘之和,寄存器AX存放数的阶乘E

14、NDM;重复伪指令结束MOVSUM,BX;结果存入SUM字存储单元MOVAH,4CH;终止程序运行并返回DOSINT2lHCODEENDSENDSTART,返回本节,7.4.2宏与子程序的区别,从以上实例和第四章的子程序对比,我们可以得知:宏和子程序都可以用来处理程序中重复使用的程序,从而简化源程序的编写,提高程序的可维护性,但是它们二者之间存在着以下本质的区别,总之,当程序片段不长,速度是关键因素时,可采用宏来简化源程序,但当程序片段较长,存储空间是关键因素时,可采用子程序的方法来简化源程序和目标程序。,返回本节,7.5多模块程序设计,7.5.1汇编语言程序的多模块连接,返回首页,7.5.1

15、汇编语言程序的多模块连接,一、SEGMENT语句提供的连接信息二、模块之间的沟通符号外部变量和全局变量的定义三、两个模块之间的数据交换四、运行连接程序LINK实现多模块程序的连接五、多模块程序设计注意事项与范例,一、SEGMENT语句提供的连接信息段定义伪指令的格式是:段名SEGMENT定位类型组合类型类别如:DATA1SEGMENT;DATA1是段名。又如:CODESEGMENT;CODE是段名。,段名DATA、CODE、是不能省略的,其构成规则与语句的名称一样。,段名除了有段地址外,还有定位类型、组合类型、和类别三个属性。,一般情况下,定位类型、组合类型、和类别三个属性可以不用说明。但是,

16、如果需要把一个程序与其它程序模块相连接时,就要用到这些属性。,1、定位类型(align_type):表示指定段的起始地址,有(1)PAGE从页开始,即用二进制表示的边界地址的低8位为0,或者说,能被256除尽;例如:段名SEGMENTPAGE段名ENDS(2)PARA从自然段开始,即用二进制表示的边界地址的低4位为0,或者说,能被16除尽;例如:段名SEGMENTPARA;PARA可以省略。段名ENDS,(3)PARA从自然段开始,即用二进制表示的边界地址的低4位为0,或者说,能被16除尽;例如:段名SEGMENTPARA;PARA可以省略。段名ENDS(4)WORD从字开始,即边界地址的低2

17、位为0,或者说,能被2除尽;例如:段名SEGMENTWORD段名ENDS,(5)BYTE从任意地方开始。例如:段名SEGMENTAT1A2BH;段首址是1A2BH。这里用到了AT表达式(详见2.2.1中的“2组合类型”)ORG0009;段内从0009偏移量开始。段名ENDS,ORG是调整偏移量伪指令ORG,详见2.8中的“4调整偏移量伪指令ORG”,如果上一段从1A2B0H的边界地址(符合用二进制表示的边界地址的低4位为0的要求)开始,占用了26个字节,即用到1A2C9H。而下一段若从1A2D0H的边界地址开始,那么就会浪费了6个字节的内存单元。为了避免这种情况,可以让下一段的段首址=1A2C

18、0H,而偏移地址从0009开始,如上一段所述。,2.组合类型作用:告诉汇编程序应为连接程序提供本段与其它段连接的有关信息,如本段与其它段是否组合为同一段;组合后,本段信息与其它段信息息的关系如何,等等。分类:(1)NONE类型表示本段与不同模块中的其它段在逻辑上不发生关系。连接后各模块中的各段都有自已的段地址(也称基地址)。(2)PUBLIC类型表明连接时,应把不同模块中属于该类型的同名同类别的段相继地连成一个段。其中所有的变量或标号都有相同的段地址。连接的顺序与由连接命令LINK指定连接次序(由用户提供)一致(本节的最后将给出连接的基本方法)。各模块中属于PUBLIC类型的同名同类别的各段的

19、总长度不超过64K字节。,段定义时,组合类型若被省略,隐含为NONE类型。,(3)STACK类型与PUBLIC类型同样处理,但只对堆栈段起作用。所以,在可执行文件装入内两个寄存器传送初值。存后,段寄存器SS已写入该段的段地址,堆栈指针SP已指向堆栈底。不必再为这两个寄存器传送初值。(4)COMMON类型表明连接时,应将不同模块中属于该类型的同名同类别的各段连接成一段,它们共用一个段地址,且互相覆盖。连接后,段的长度取决于最长的COMMON段的长度。,(5)AT表达式类型使段的起始地址是表达式所计算出来的16位段地址,但它不能用来指定代码段。表达式也可以是一个有效的常数。该类型可以将我们要定义的

20、段设定在固定的地址范围内。定义AT类型的段内不应包括任何指令语句或有初值的变量定义语句。但该段内允许设定标号或与标号有相同属性的过程定义语句或无初值的变量定义语句。它仅仅用来将该段指向内存区中的某个段,使该段的段名及段内的变量与指向的内存区的段地址有关。,例题,若要用一个过程名SUB1代表BIOS中的某段子程序,我可以这样定义一个段和过程:CODEBSEGMENTAT表达式1;定义CODEB段地址ORGN;定义过程SUB1的偏移地址SUB1PROCFARSUB1ENDPCODEBENDS,表达式的值即为某子程序所在段的段地址,这样定义后,程序中调用过程名SUB1时。即调用BIOS中对应的子程序

21、。其中也可以定义一个标号,并用ORG指定该标号的偏移地址,这样,该标号就与该段内的这个偏移地址相关。,(6)MEMORY类型表明连接时应把本段装在被连接的其它所有段之上(地址高端)。当有多个段为此类型时,只有汇编程序遇到的第一个段才认为是MEMORY段,而其它段则当作COMMON段。【例7-18】现有两个程序模块如下:模块l:DATASEGMENTCOMMONDW20HDUP(?)DATAENDSCODESEGMENTPUBLICCODEENDS,模块2:DATESEGMENTCOMMONDW30HDUP(?)DATEENDSCODESEGMENTPUBLICCODEENDS图给出了不同模块中

22、组合类型为PUBLIC和COMMON时的连接结果。因为两个模块的数据段都为COMMON类型,连接后,这两个段组合成一个段,并且互相覆盖,其长度取两个模块中数据段长度长的,即为第二模块的长度。,由于COMMON类型的段组合后,相互覆盖,所以,只有不同模块采用公用缓冲区(模块2的缓冲区大于模块1的缓冲区)时才使用这种类型。,由于两个模块的代码段是PUBLIC类型。因此,连接后,两个模块的代码段也组合成一个段,但它们并不覆盖,而是两个代码段相邻地连接在一起,其顺序也与LTNK时提供的目标模块的顺序一致。组合后段的长度应是两个代码段长度的和。图中两个源模块中的数据段和代码段部没有给出类别,这也是允许的

23、。但若某个模块中给出了类别而另一模块中不给出类别,那么,这两个模块中的同名段将不能组合成一个段。3.类别用于组或段组的名字,必须用英文单引号()括起来。连接时类别相同的段被集中在一起,其顺序亦与LINK时提供的各模块顺序一致。当类别相同的各段的段名不同时,它们连接后虽在同一物理段内,但它们仍不属于同一段,也就是它们的段首址不相同。,类别说明该段的类型,有CODE,DATA,STACK等,返回小节,二、模块之间的沟通符号外部变量和全局变量的定义伪指令EXTRN和PUBLIC分别用于通知汇编程序上述的信息。1.EXTRN伪指令格式:EXTRN符号:类型:,符号:类型功能:说明在本模块中用到的哪些标

24、识符是由其它模块定义的,即外部符号。标识符必须指出其类型,这是在汇编时为了生成正确的机器码所必需的。变量的类型可以是BYTE,WORD或DWORD,标号的类型可以是NEAR或FAR(若调用者所在的段与位于另一模块内的被调用者所在的段连接后能合并成一个段,则调用相当于段内调用,选近转移类型NEAR;若不能合并成一个段,则调用相当于段间调用,选远转移类型FAR。)一个EXTRN语句可以声明多个外部符号,它们之间用逗号分隔。,2.PUBLIC伪指令格式:PUBLIC符号,符号功能:PUBLIC伪指令的功能是指明本模块中所定义的标识符有哪些是可以提供其它模块调用的全局标识符。PUBLIC伪指令可声明多

25、个这样的符号,符号间用逗号隔开。,各模块中语句PUBLIC和EXTRN提供的标识符必须互相呼应。,【例7-19】现有三个程序模块如下模块1EXTRNVAR3:WORD,EX1NEAR;声明VAR3、EX1在其他模块中定义EXTRNEX2:FAR;声明EX2在其他模块中定义PUBLICVARl,VAR2;声明VARl、VAR2为全局变量DATASEGMENTVARlDB?VAR2DW?DATAENDSCODESEGMENTPUBLICCODECODEENDSEND,模块2:EXTRNVARlBYTE,VAR2:WORD,VAR5:WORD;声明VAR1、VAR2、VAR5在其他模块中定义PUBL

26、ICEXl,VAR3;声明EXl、VAR3为全局变量DATASEGMENTVAR3DW?DATAENDSCODESEGMENTPUULICCODEEXl:CODEENDSEND,模块3:EXTRNVAR4:BYTE;声明VAR4在其他模块中定义PUBLICVAR5,EX2;声明EX2、VAR5为全局变量DATASEGMENTVAR5DW?DATAENDSCODE3SEGMENTEX2:;CODE3ENDSEND模块1与模块2的代码段同名,连接后是一个段,所以,在模块1中要用到的标号EXl虽不在同一模块中,但却是NEAR类型。标号EX2在模块3中定义。连接后它与模块1的代码段不在同一段,因而EX

27、2为FAR类型。,引用的外部变量分别是VAR3,VARl、VAR2,VAR4,但在PUBLIC语句中说明可以提供给其它模块引用的全局变量分别为VARl、VAR2,VAR3,VAR5,没有变量VAR4,从而出错;而变量VAR5是由模块3定义的外部变量。虽然没有其它模块引用,这是允许的。,返回小节,三、两个模块之间的数据交换两个模块之间若要相互交换数据,可用如下三种办法实现:1通过寄存器传递。2通过变量或数据区传递。3通过堆栈传递。这些,在子程序和宏中,已有详尽的讨论,不复赘述。前两种方法较为简单,因为无论在同一模块内还是在不同模块内的各个过程间,都有共用相同的寄存器和堆栈段,所以在模块内还是在模

28、块外调用都是一样,返回小节,四、运行连接程序LINK实现多模块程序的连接如果已有多个模块,且每个模块都是一个独立的ASM文件,则各模块应先分别汇编,得到几个相应的目标(OBJ)文件,再用连接程序将这几个目标文件连接成一个可执行(EXE)文件,连接时用“+”来连接合并各个目标文件例如,若一个程序由三个模块SUMASM、DUMPASM、MAXASM组成,若要运行该程序则应先将它们分别汇编,生成对应的目标模块SUMOBJ、DUMPOBJ和MAXOBJ;再用简单方式或提问方式调用LINK程序,将它们连接成可执行文件。(1)简单方式D:LINKSUM+DUMP+MAX;,指的是将3个目标模块SUMOBJ

29、、DUMPOBJ和MAX0BJ连接在一起,生成的可执行文件被默认为SUMEXE。,(2)提问方式D:LINKObjectModulesOBJ:SUM+DUMP+MAXRunFileSUMEXE:ListFiLeNULMAP:SUMLibrariesLIB:用以下命令运行可执行文件,得到运行结果:D:SUM,返回小节,五、多模块程序设计注意事项与范例1.注意事项(1)模块的划分原则模块间的调用关系应尽量简单,避免有多个数据入口点或退出点,方便模块之间的调试。尽量减少模块间的数据传递,对于需要相互传递数据较多的两模块,应予合并。模块的大小适中,一般长度在50100行。(2)各模块文件的命名,设计者

30、代号,如C1、L2、W3,分别标识张姓设计者,设计模块1,李姓设计者,设计模块2,王姓设计者,设计模块3,。便于编程中的彼此识别和相互沟通。简单标识模块功能,以利于调用和连接。标识该模块在整体中的位置。(3)标号、变量和缓冲区的定义标号、变量和缓冲区的定义也应该简明,显示出标识功能或类型特征。如DSP标识显示功能,PRN标识打印功能;变量以“V”开头,字符串以“S”开头,缓冲区以“B”开头;“B”标识字节类型,“W”标识子类型,“Q”标识4字类型。,(4)模块注释模块注释是为了方便子模块的调用,在子模块的前面说明,内容包括:子模块功能、调用此子模块的入口参数和出口参数、子模块中所使用的主要变量

31、等。这样,即使不了解子模块的内部结构,也可以直接按说明调用该子模块,从而提高编程的效率。子模块说明一般以注释的形式给出。如果该说明需要随源程序一起输入到计算机内,则要用ASCII字符表中的字符书写,如果操作系统支持汉字,也可用汉字书写。,2.多模块程序设计范例【例7-20】从键盘输入一串十进制有符号数(范围:3276732767),以逗号为分隔符,然后按从小到大的顺序显示出来,仍以逗号为分隔符。若输入的数中包括非法数,则停止输入并给出错误提示后返回DOS。例如:输入的数组为180,90,123,327,10,32708排序输出结果为32708,327,180,10,90,123;或者输入的数组

32、为180,90,9AISILIEGALDIGIT!,因“9A”为非法数,则结束程序的执行返回DOS,无输出结果,解:分析问题:由题意可知,实现以上功能的方法是:采用l号DOS功能调用,输入一个字符,如果该字符不是逗号,也不是回车符,则说明该字符为十进制数字字符,应送入BUF字节缓冲区,再输入下一个字符;如果该字符是逗号,说明一个数已经输完,则应将BUF区中的这个十进制数字串转换成二进制数,送入ARR字存储区(调用F10T2子程序实现)后,再输入下一个数;如果该字符是回车符,则说明全部数已经输完,需再对ARR存储区中的全部有符号数排序(调用QUEUE子程序),最后将排好序的数通过调用F2T10子

33、程序全部以十进制的形式显示出来,仍以逗号为分隔符。确定算法:如果采用模块设计的方法,将F2T10、F10T2、QUEUE三个子程序都写成独立模块的形式且存放在子程序库WAN.LIB中,则主模块对它们的调用关系如图,算法因具体模块而不同,主程序和三个子程序中,大多采用比较循环算法,并且多为分支结构。画程序流程图:因具体模块而不同,图7-3给出了主程序流程图,各子程序流程图略。确定汇编语言程序的基本框架:因具体模块而不同,略。编写程序:因具体模块而不同,略,具体程序,图7-3主模块程序流程图,(1)主模块1)注释主模块中寄存器及主要变量的使用分配如下:2)主模块程序在编写主模块时,调用了宏库MAC

34、RO.LIB(请读者注意,如何调用)。根据图7-12编写出的主模块程序如下:NAMEMAIN;主模块EXTRNFl0T2:NEARF2T10:NEARQUEUE:NEAR;定义外部变量IF1;条件汇编伪指令INCLUDEMACROLIB;将宏库在第一次扫描时加入一起汇编ENDIF;与IFl配套的条件汇编结束符386;主程序名,DATASEGMENTUSEl6PARAPUBLlCDATA;主模块数据段定义DATAENDSSTACK0;调用宏指令定义堆栈CODESEGMENTUSEl6PARAPUBLICCODEASSUMEDS:DATA,ES:DATA,CS;CODE,SS;STACKSTART

35、:;主模块代码段内容,略CODEENDSENDSTART;主模块结束,(2)十进制数二进制数子模块F10T2NAMEF10T2;子模块F10T21)注释;功能:;入口参数:;出口参数;2)子模块程序PUBLlCF10T2DATASEGMENTUSEl6PARAPUBLICDATADATAENDSCODESEGMENTUSEl6PARAPUBLICCODEASSUMECS:CODE,DS:DATAF10T2PROC;过程体F10T2ENDPCODEENDSEND,(3)二进制数十进制数子模块F2T10NAMEF2T10;子模块F2T101)注释;功能:;调用F2T10的入口参数:;调用F2T10

36、的出口参数:;所使用的变量:;调用RADIX的入口参数:;调用RADIX的出口参数:;所使用的寄存器:2)子模块程序PUBLICF2T10DATASEGMENTUSEl6PARAPUBLICDATA,DATAENDSCODESEGMENTUSEl6PARAPUBLICCODEASSUMECS:CODE,DS:DATAF2Ti0PROC;过程体F2T10ENDPRADIXPROC;过程体RADlXENDPCODEENDSEND(4)排序子模块QUEUENAMEQUEUE;子模块QUEUE,1)注释;功能:;入口参数:;所使用的寄存器:;出口参数:2)排序子模块QUEUE程序PUBLICQUEUE

37、CODESEGMENTUSEl6PARAPUBLICCODEASSUMECS:CODEQUEUEPROCPUSHAX;以下三句保护寄存器内容PUSHDXPUSHDI,MOVDI,SI;将待排序数组首址DI(备份);过程体POPDI;以下三句恢复寄存器内容POPDXPOPAXRETNO:CMPAX,SI+2;对无符号数,如果前一个数小于或等于后一个数,则不交换JBENOXCHJMPXCH;如果前一个数大于后一个数,则两数交换位置QUEUEENDPCODEENDSEND,返回小节,7.6汇编语言与高级语言的连接,1C语言中嵌入汇编2C语言调用汇编语言子程序3.C语言程序的汇编输出,返回首页,1C语

38、言中嵌入汇编,一、定义在C程序中允许直接编写汇编语言代码,称作“嵌入汇编”,也称为行内汇编,其特点是简洁直观。C语言允许嵌入四类汇编命令:一般指令、串指令、跳转指令、数据分配和定义指令,嵌入汇编比调用汇编子程序更方便、灵活,功能也更强。二、格式:汇编语句前面必须有关键字asm标识asm若要嵌入一组汇编语句,则需要用括号“”把它们括起来。,说明:标号不是一定要有的。参数是汇编指令或伪指令的操作数,可引用C语言中的常量、变量或标号。“;”不再是汇编语言中起注释作用的分号,而是作为语句的分隔符。即一行内可写多条嵌入式汇编语句,它们以“;”分隔;一行内如果只有一条asm语句,则后面不需要“;”。语句分

39、隔符也可以用换行符。注释分隔符统一用“*/”或“/*”(2)嵌入式汇编的编译连接在命令行编译器TCC.EXE下进行编译:TCCoptionsfiles其中files为需要编译或连接的文件,可有一个或多个。options为各个参数项,常用的参数有“-B”,用于说明源程序中使用了嵌入汇编;“-S”能使TCC.EXE编译成汇编语言的源程序输出。,【例7-21】嵌入式汇编的编译连接。asmBUFDBHellowor!$Main()asmLEADX,BUFasmMOVAH,9HasmINT21H或者写成asmLEADX,BUFMOVAH,9HINT21H,返回小节,2C语言调用汇编语言子程序,一、当TU

40、RBOC调用汇编子程序时,汇编程序指令序列应当具备一定的顺序,这种顺序可描述为:如果一组汇编程序不符合上面的顺序,则TURBOC将不能对其进行调用。,正文段描述,段模式,组描述,进栈,程序体,退栈,正文段结束,二、调用协议在混合编程中,双方须定义相同的接口协议,即必须遵循共同的约定规则,才可使双方的代码协同工作。接口协议顺序如下:(1)声明约定:(2)存储器模式约定:TC与汇编语言采用相同的存储模式,即对存储器的使用,如段、组的划分,段名、组名的约定一致。(3)命名约定:声明共用函数和变量。C语言程序中使用汇编语言程序定义的变量和函数时,在C语言程序中应该用extem说明。在汇编语言程序中应该

41、用PUBLIC说明。(4)调用约定:调用者用哪种顺序将参数入栈,被调用者以哪种顺序提取参数,由谁负责最后清除堆栈中的参数等。(5)参数传递约定:参数传递包括两个方面,一个是从TURBOC语言程序向汇编子模块传递参效,另一个是从汇编语言向TURBOC调用程序返回参数。,TURBOC程序向汇编语言程序的参数传递是通过栈操作进行的。先传递的参数被最后压入堆栈,即参数按从右到左的顺序被压入堆栈(这与C语育的版本有关)。进退栈操作是为了保存现场。另外,如果汇编语言程序中需耍用到某些寄存器,则需将这些寄存器压入堆栈,待程序将要结束时,再退出堆栈。汇编语言程序结束时应该用RET,指令返回。而且由于采用堆栈来

42、传送参数,因而返回时往往采用带常数的退回指令,以便跳过参数区。(6)寄存器使用约定:汇编语言程序中的结果返回给TURBOC主程序是通过AX和DX寄存器来完成的。,例题,【例7-22】设有一个TURBOC程序从键盘上获得两个数,将其传给汇编子程序ASMADDASM完成两个数相加并返回和,然后在TURBOC的程序中将结果显示在屏幕上。建立CADDc程序:#includestdioh);externintASMADD(inti,intj,long*k);定义外部整形变量,来自汇编程序ASMADD,顺序是i,j,kmain();以下是C语言主程序inti,j,k;printf(”inputi,j=?);scanf(”d,d”,i,j);ASMADD(i,j,printf(”d+d=dn”,i,j,k);getch();,其中ASMADD()是一个用汇编语言写的子程序,其源程序如下:PUBLIC_ASM

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论