《第14章模块化程序设计(精品).ppt》由会员分享,可在线阅读,更多相关《第14章模块化程序设计(精品).ppt(64页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、第第1414章章 模块化程序设计模块化程序设计 第第14章章 模块化程序设计模块化程序设计 14.1 段间调用段间调用 14.2 定义外部标识符伪指令定义外部标识符伪指令 14.3 使用使用EXTRN和和PUBLIC的范例的范例 14.4 在指令段使用在指令段使用PUBLIC 14.5 在数据段使用在数据段使用PUBLIC 14.6 参数传送参数传送 14.7 C语言与汇编语言的链接语言与汇编语言的链接 第第1414章章 模块化程序设计模块化程序设计 14.1 段段 间间 调调 用用前面介绍的CALL指令都是段内的调用,即在同一个指令段内。段内调用的CALL指令范围为0000HFFFFH。一条
2、段内调用指令(CALL)的目的码是3个字节长度,例如:E82000(0020);十六进制第第1414章章 模块化程序设计模块化程序设计 十六进制E8是段内调用指令(CALL)机器指令的操作码,其操作是先把当前IP指令指针寄存器的值压入堆栈保存,这个值是CALL的下一条指令地址;然后,再把被调用的子程序的偏移地址(2000逆序)值送入IP寄存器,IP0020。微处理器把当前CS的值和IP的值相结合形成物理地址,此地址指向被调用子程序的第1字节。当子程序的执行中,遇到RET指令离开子程序返回时,RET指令会从堆栈中弹出IP的保留值,并把它装入IP,使程序返回到CALL的下一条指令继续执行,这个过程
3、是段内调用。第第1414章章 模块化程序设计模块化程序设计 其特点是在子程序调用、返回过程中段寄存器CS不变化,只有指令指针寄存器IP发生变化。主程序与被调用的子程序同在一个段内。模块化程序设计必然涉及到模块间的调用问题。模块间的调用是通过段间的调用来实现的。若被调用的子程序是在现指令段之外,则称为段间调用。一条段间调用指令(CALL)的机器指令码共有5个字节。例如:9A0002AF04(04AF0200);十六进制第第1414章章 模块化程序设计模块化程序设计 十六进制9A是段间调用指令(CALL)机器指令的操作码。操作是:首先将CS段寄存器的值压入堆栈,并把被调用子程序所在段的段值(AF0
4、4逆序)装入CS段寄存器,CS04AF;然后把IP指令指针寄存器的值压入堆栈,并将被调用子程序相应的偏移地址(0002逆序)装入IP,IP0200。第第1414章章 模块化程序设计模块化程序设计 这些操作建立了被调用子程序的第一条待执行指令的地址:十六进制段值:CS04AF0偏移地址:IP+0200物理地址:04CF0第第1414章章 模块化程序设计模块化程序设计 当离开子程序返回时,段间调用的RET指令会从堆栈中依序弹出IP和CS两个寄存器的原值,返回到CALL的下一条指令。其特点是在子程序调用、返回过程中,段寄存器CS和指令指针寄存器IP均发生变化。主程序与被调用的子程序不在同一个段内。第
5、第1414章章 模块化程序设计模块化程序设计 14.2 定义外部标识符伪指令定义外部标识符伪指令当进行模块化程序设计时,首先应考虑的问题是模块间控制的耦合和数据的耦合。控制耦合就是模块在怎样的环境下如何进入又如何退出。数据耦合就是诸模块间如何进行数据通讯。例如,有一个主模块(MAINPROG)调用一个子模块(SUBPROG),它要用到一个段间调用(CALL),如图14-1所示。第第1414章章 模块化程序设计模块化程序设计 EXTRNSUBPROG:FARMAINPROG:CALLSUBPROGPUBLICSUBPROGSUBPROG:RET图14-1段间调用第第1414章章 模块化程序设计模
6、块化程序设计 主模块MAINPROG内的CALL指令,必须知道子模块SUBPROG是位于本段之外的标号。否则汇编过程中会产生一个错误信息指出SUBPROG是一个未定义的符号。EXTRN伪指令就是执行此功能的,它告诉汇编程序SUBPROG是一个远程的标号(FARLabel),是定义在另一个模块里的。因为汇编程序无法知道真是如此,所以就产生“空的”目的操作数0000,即先空出;而由链接程序在链接时再填入确定值。例如(参考例14.4主模块程序清单):00119A0000-E第第1414章章 模块化程序设计模块化程序设计 子模块SUBPROG内含有一个PUBLIC伪指令,它告诉汇编程序和链接程序,其他
7、模块需要知道SUBPROG的地址。当MAINPROG与SUBPROG都已汇编成目的模块文件后,它们可以下列的方式来链接:LINKMAINPROG+SUBPROGRunFileMAINPROG.EXE:ListFileNUL.MAP:CONLibraries.LIB:第第1414章章 模块化程序设计模块化程序设计 链接程序将一个目的模块内的EXTRN匹配上另一个模块内的PUBLIC,并将插入所有需要的偏移地址,然后把两个目的模块组合成一个可执行的文件。若有不匹配的情况,链接程序会给出错误信息。利用EXTRN和PUBLIC这两条伪指令,一个模块可以访问其他模块的标识符(变量或者标号)。如果一个标识
8、符只在这一个模块中定义过,那么它相对这个模块就是一个内部的标识符或局部标识符。如果它没有在这一个模块中定义过,而是在其他一个模块中定义过,那么它相对于该模块就称为外部标识符。第第1414章章 模块化程序设计模块化程序设计 对于只产生一个单一目标模块的汇编语言程序而言,它所访问的所有标识符必须是局部(内部)定义的,否则就会产生一个错误信息汇编程序会查出有一个未定义的标识符(标号或变量)存在。对于多模块程序来说,必须给汇编程序一个信息以说明其间的有些标识符是外部的,而不至于汇编程序把它们理解为一些无效的标识符。此外为了允许其他模块访问本给定模块中的标识符,该给定模块必须包含一个标识符清单,以说明其
9、中的标识符可以让其他模块访问。因此,每个模块可含有(不一定绝对含有)两个清单,一个清单表明它所访问其他模块的外部标识符(EXTRN),而另一个则列出它所定义的且让其他模块访问的标识符(PUBLIC);第第1414章章 模块化程序设计模块化程序设计 这两个清单靠EXTRN和PUBLIC这两条伪指令来列出。EXTRN和PUBLIC伪指令的格式如下:EXTRN标识符:类型,PUBLIC标识符,EXTRN伪指令里的标识符是被申明的外部的变量或标号,而PUBLIC伪指令里的标识符是供其他模块使用的变量或标号。由于在产生相应的机器代码之前,汇编语言必须要知道所有标识符的类型,以便确定指令的字节数(长度),
10、故在EXTRN伪指令里的每一个标识符都伴有类型符出现。第第1414章章 模块化程序设计模块化程序设计 对于变量来说,类型有BYTE、WORD、DWORD等,对于标号来说类型则有NEAR或FAR。注意:标识符可以是变量、符号常量、标号和过程名。例如:INCVAR1语句,如果VAR1是外部变量,并且是一字变量,那么在含有这个语句的模块中必须使用下列伪指令:EXTRN,VAR1:WORD而在定义VAR1的模块中则一定要有下面的伪指令:PUBLIC,VAR1第第1414章章 模块化程序设计模块化程序设计 链接程序的主要任务之一,就是检测并证实EXTRN语句里的每一个标识符是否与PUBLIC语句的标识符
11、相匹配,如果不相匹配,链接程序就会给出出错信息。下面给出三个模块,说明链接程序是怎样查找匹配,并指出其中错误。第第1414章章 模块化程序设计模块化程序设计 模块1:EXTRNVAR2:WORD,LAB2:FARPUBLICVAR1,LAB1;DATA1SEGMENTVAR1DB2VAR3DB?VAR4DW?DATA1ENDS;第第1414章章 模块化程序设计模块化程序设计 LAB1:模块2:EXTRNVAR1:BYTE,VAR4:WORDPUBLICVAR2链接错误,原因是模块1中PUBLIC;没有申明匹配DATA2SEGMENTVAR2DW0VAR3DB5DUP(?)DATA2ENDS;第
12、第1414章章 模块化程序设计模块化程序设计 模块3:EXTRNLAB1:FARPUBLICLAB2,LAB3;其他模块未使用LAB2:不需申明LAB3:第第1414章章 模块化程序设计模块化程序设计 14.3 使用使用EXTRN和和PUBLIC的范例的范例下面的例子中含有两个模块:主模块CALLMUL1和一个子模块SUBMUL1。主模块定义了堆栈段、数据段和指令段。数据段定义了两个数据项PRICE和QTY。指令段分别把PRICE和QTY装入AX和BX寄存器,然后调用子模块。主模块内的伪指令EXTRN指明了本模块使用的外部模块SUBMUL1。第第1414章章 模块化程序设计模块化程序设计 子模
13、块内有一条伪指令PUBLIC,它告诉链接程序SUMUL1是由其他模块调用的,同时指明此处是链接的进入点。子模块的功能是把AX寄存器的内容乘以BX寄存器的内容,所得乘积放入DX:AX这一对寄存器内。子模块内没有定义任何数据,所以它没有数据段;也可以定义数据段,但只能在子模块中使用。在子模块内也没有定义堆栈段,它与主模块共同使用一个堆栈。所以,在主模块中定义的堆栈,子模块也可以使用。链接程序要求至少有一个堆栈段,在主模块内定义的堆栈段就可以满足要求。第第1414章章 模块化程序设计模块化程序设计 例14.1EXTRN和PUBLIC应用。主模块程序清单如下:;主模块:;filename:CALLMU
14、L1.ASMEXTRNSUBMUL1:FAR;STACK SEGMENT PARA STACKSTACKDW64DUP(?)STACKENDS第第1414章章 模块化程序设计模块化程序设计 ;DATASGSEGMENTPARADATAQTYDW0140HPRICEDW2500HDATASGENDS;CODESGSEGMENTPARACODEBEGINPROCFARASSUMECS:CODESG,DS:DATASG,SS:STACK第第1414章章 模块化程序设计模块化程序设计 PUSH DSSUBAX,AXPUSHAXMOVAX,DATASGMOVDS,AXMOVAX,PRICEMOVBX,Q
15、TYCALLSUBMUL1RETBEGINENDPCODESGENDSENDBEGIN第第1414章章 模块化程序设计模块化程序设计 子模块程序清单如下:;filename:SUBMUL1.ASM;子模块:CODESGSEGMENTPARACODESUBMUL1PROCFARASSUMECS:CODESGPUBLICSUBMUL1MULBXRET第第1414章章 模块化程序设计模块化程序设计 SUBMUL1ENDPCODESGENDSENDSUBMUL1主模块和子模块分别汇编正确无误后,参考上节内容链接,产生一个EXE文件。C:masmLINKCALLMUL1+SUBMUL1RunFileCA
16、LLMUL1.EXE:Enter(回车)ListFileNUL.MAP:EnterLibraries.LIB:Enter第第1414章章 模块化程序设计模块化程序设计 14.4 在指令段使用在指令段使用PUBLIC在主模块的指令段和子模块的指令段使用PUBLIC伪指令,链接程序会把两个逻辑指令区段结合成一个实际的指令段。在例14.1的主模块和子模块中各有一处修改,均是在指令段的SEGMENT伪指令内使用PUBLIC,用法如下:CODESGSEGMENTPARAPUBLICCODE第第1414章章 模块化程序设计模块化程序设计 例14.2在指令段使用PUBLIC。主模块程序清单如下:;主模块:;
17、filename:CALLMUL.ASMEXTRNSUBMUL:FAR;STACKSEGMENTPARASTACKSTACKDW64DUP(?)STACKENDS第第1414章章 模块化程序设计模块化程序设计 ;DATASGSEGMENT PARA DATAQTYDW0140HPRICEDW2500HDATASGENDS第第1414章章 模块化程序设计模块化程序设计 ;CODESGSEGMENTPARAPUBLICCODEBEGINPROCFARASSUMECS:CODESG,DS:DATASG,SS:STACKPUSHDSSUBAX,AXPUSHAXMOVAX,DATASGMOVDS,AX第
18、第1414章章 模块化程序设计模块化程序设计 MOVAX,PRICEMOVBX,QTYCALLSUBMULRETBEGINENDPCODESGENDSENDBEGIN第第1414章章 模块化程序设计模块化程序设计 子模块程序清单如下:;filename:SUBMUL.ASM;子模块:CODESGSEGMENTPARAPUBLICCODESUBMULPROCFARASSUMECS:CODESGPUBLICSUBMULMULBX第第1414章章 模块化程序设计模块化程序设计 RETSUBMULENDPCODESGENDSENDSUBMUL第第1414章章 模块化程序设计模块化程序设计 当两个段使用
19、同一个名称(CODESG)、同样的类型(CODE)以及同样段的组合类型(PUBLIC)时,链接程序会把这样的两个逻辑段组合成一个实际的物理指令区。通过汇编时产生的LST文件中的符号表,可以了解到一个指令段的情况;也可利用DEBUG程序观察到一个指令段的情况。第第1414章章 模块化程序设计模块化程序设计 14.5 在数据段使用在数据段使用PUBLIC你可能会有这样的需求,在一个模块内要处理另外一个模块的数据。例如前面的例题中,主模块仍然定义数据PRICE和QTY;但是由子模块使用它们,把它们的值放入AX和BX。程序修改如下:第第1414章章 模块化程序设计模块化程序设计 例14.3在数据段使用
20、PUBLIC。主模块程序清单如下:;主模块:;filename:CALLMUL.ASMEXTRNSUBMUL:FARPUBLICQTY,PRICE;STACKSEGMENTPARASTACKSTACK第第1414章章 模块化程序设计模块化程序设计 DW64DUP(?)STACKENDS;DATASGSEGMENTPARAPUBLICDATAQTYDW0140HPRICEDW2500HDATASGENDS;第第1414章章 模块化程序设计模块化程序设计 CODESGSEGMENTPARAPUBLICCODEBEGINPROCFARASSUMECS:CODESG,DS:DATASG,SS:STAC
21、KPUSHDSSUBAX,AXPUSHAXMOVAX,DATASGMOVDS,AXCALLSUBMULRET第第1414章章 模块化程序设计模块化程序设计 BEGINENDPCODESGENDSENDBEGIN子模块程序清单如下:;filename:SUBMUL.ASM;子模块:EXTRNQTY:WORD,PRICE:WORD;CODESGSEGMENTPARAPUBLICCODE第第1414章章 模块化程序设计模块化程序设计 SUBMULPROCFARASSUMECS:CODESGPUBLICSUBMULMOVAX,PRICE第第1414章章 模块化程序设计模块化程序设计 MOVBX,QTY
22、MULBXRETSUBMULENDPCODESGENDSENDSUBMUL第第1414章章 模块化程序设计模块化程序设计 PUBLICQTY,PRICE;声明主模块的QTY和PRICE为外部引用EXTRNQTY:WORD,PRICE:WORD;声明QTY和PRICE是外部标识符子模块中使用了主模块的变量,所以两个模块中都应进行声明:第第1414章章 模块化程序设计模块化程序设计 14.6 参参 数数 传传 送送主模块调用子模块,通常也称为主程序调用子程序,主程序经常要传送一些参数给子程序,子程序运行完成后一般都要返回一些信息给主程序。这种主程序和子程序间的信息传送称为参数传送或过程间的数据通信
23、。参数传送的方法有三种:第第1414章章 模块化程序设计模块化程序设计 (1)利用寄存器传递参数:适用参数较少时;(2)利用存储器传递参数:适用参数较多时;(3)利用堆栈传递参数:适用嵌套、递归情况。数据传送根据范围可分为以下几种:(1)同一个模块内的段内参数传送。(2)同一个模块内的段间参数传送。(3)不同模块间的参数传送。(4)不同语言间的参数传送第第1414章章 模块化程序设计模块化程序设计 例14.4利用堆栈传送参数。主模块程序清单如下:;主模块:;filename:CALLMUL.ASMEXTRNSUBMUL:FAR;0000 STACKSEGMENTPARASTACKSTACK00
24、000040DW64DUP(?)?第第1414章章 模块化程序设计模块化程序设计 0080STACKENDS;0000DATASGSEGMENTPARADATA00000140QTYDW0140H00022500PRICEDW2500H0004DATASGENDS;第第1414章章 模块化程序设计模块化程序设计 0000 CODESGSEGMENTPARAPUBLICCODE0000 BEGINPROCFARASSUMECS:CODESG,DS:DATASG,SS:STACK00001EPUSHDS00012BC0SUBAX,AX000350PUSHAX0004B8-RMOVAX,DATASG
25、第第1414章章 模块化程序设计模块化程序设计 00078ED8 MOVDS,AX0009FF360002RPUSHPRICE000DFF360000RPUSHQTY00119A0000ECALLSUBMUL0016CBRET0017BEGINENDP0017CODESGENDSENDBEGIN第第1414章章 模块化程序设计模块化程序设计 子模块程序清单如下:;filename:SUBMUL.ASM;子模块:0000 CODESGSEGMENTPARAPUBLICCODE0000 SUBMULPROCFARASSUMECS:CODESGPUBLICSUBMUL000055PUSHBP第第14
26、14章章 模块化程序设计模块化程序设计 00018BECMOVBP,SP00038B4608MOVAX,BP+800068B5E06MOVBX,BP+60009F7E3MULBX000B5DPOPBP000CCA0004RET4000FSUBMULENDP000FCODESGENDSEND第第1414章章 模块化程序设计模块化程序设计 主模块程序在调用子模块程序SUBMUL之前,把PRICE和QTY都压入堆栈。堆栈的变化如下:1600XXXX400100250000XXXX654321第第1414章章 模块化程序设计模块化程序设计 (1)PUSHDS将DS中的段地址压入堆栈。(2)PUSHAX
27、把偏移地址0压入堆栈。(3)PUSHPRICE把2500压入堆栈。(4)PUSHQTY把0140压入堆栈。(5)CALL把CS寄存器的内容压入堆栈。(6)IP指令指针寄存器的内容0016也被压入堆栈。第第1414章章 模块化程序设计模块化程序设计 被调用的子模块程序SUBMUL要用BP来取得堆栈内的参数。它的第一个操作是把BP的内容压入到堆栈保存起来。本例中BP的内容正好是0,然后把SP的内容送入BP。因为BP可以作为寻址寄存器,而SP则不行。此操作使BP的值为0072,因为SP的初值应是堆栈的大小十六进制80,每次压入堆栈一个字SP减2。堆栈指针的变化应是:00001600XXXX40010
28、0250000XXXX.SP:727476787A7C7E80第第1414章章 模块化程序设计模块化程序设计 因为现在BP的内容是0072,所以PRICE在BP+8位置,而QTY在BP+6位置。下面两条指令把这些值分别搬入AX和BX,然后作乘法。要从子模块程序回到调用程序时,先恢复BP的值0000并将SP加2,从72变成74。最后一条指令RET,是一条子程序返回指令,它执行下列操作:第第1414章章 模块化程序设计模块化程序设计 (1)弹出当前堆栈顶端的字1600送入IP。(2)把SP+2,SP从74增为76。(3)取出目前堆栈顶端的字(XXXX),存入CS。(4)把SP+2,SP从76增为7
29、8。子程序返回指令带有参数即RET4,指令中的4的作用是保证正确返回,将SP的值加4修正为7C。这是因为堆栈内的参数已不再需要,故予以舍弃。使用堆栈传送参数时应特别小心,SP的值弄错的话会产生预想不到的结果。第第1414章章 模块化程序设计模块化程序设计 14.7 C语言与汇编语言的链接语言与汇编语言的链接C语言与汇编语言的链接是指C语言与汇编语言的互相调用。通常只是指从C语言调用汇编语言程序。这是因为C语言不但编程容易,而且效率高。但是,汇编语言效率最高,特别是适合对硬件的直接控制。因此,采用C语言与汇编语言混合编程的方法,能得到高质量的程序。第第1414章章 模块化程序设计模块化程序设计
30、C语言与汇编语言的连接要注意以下几个问题:(1)存储器分配问题:通常情况下,存储器分配问题由链接程序解决,用户不必考虑。(2)两种语言间的控制耦合问题:汇编语言程序一般作为C语言的外部过程,由C语言通过过程调用汇编语言程序。(3)参数传送问题:一般用数值或地址的方式传送。第第1414章章 模块化程序设计模块化程序设计 1.C语言调用汇编语言举例例14.5计算A(2X。C语言程序如下:extrnintpower(int,int)Main()printf(3*time2ofthepower of5is%dn,_power(2,5);第第1414章章 模块化程序设计模块化程序设计 汇编语言子程序:_
31、TEXTSEGMENTASSUMECS:_TEXTPUBLIC_POWER_POWERPROCPUSH BPMOV BP,SPMOV AX,BP+4MOV CX,BP+6SHLAX,CLRET第第1414章章 模块化程序设计模块化程序设计 _POWERENDP_TEXTENDSEND第第1414章章 模块化程序设计模块化程序设计 2.C语言程序嵌入汇编指令举例例14.6将键盘输入的数乘2并输出。第一种方法:用预处理指令#asm、#endasm。main()inti,j;char*s;printf(pleaseinputi=);scanf(%d,i);#asm第第1414章章 模块化程序设计模块
32、化程序设计 movax,imovcl,2mulclmovj,ax#endasmprintf(i(2=%d,j);第二种方法:汇编语句行前加关键字asm,每行结尾按C语言规则加分号。第第1414章章 模块化程序设计模块化程序设计 main()inti,j;char*s;printf(pleaseinput:i=);scanf(%d,i);asmmovax,iasmmovcl,2asmmulclasmmovj,axprintf(i(2=%d,j);第第1414章章 模块化程序设计模块化程序设计 操作方法:(1)在TC集成环境下输入源程序文件。(2)把MASM.EXE改名为TASM.EXE并复制到TC目录下。(3)用TCC.EXE编译、链接程序:TCC-B-C(库文件路径)文件名库文件名