《汇编语言程序设计精品》由会员分享,可在线阅读,更多相关《汇编语言程序设计精品(84页珍藏版)》请在金锄头文库上搜索。
1、汇编语汇编语言程序言程序设计设计 吴吴 向向 军军中山大学中山大学计计算机科学系算机科学系第第6章章 程序的根本结构程序的根本结构6.1.1 段的定义段的定义 在定义段时,每个段都有一个段名。在取段名时,要取一个具有一定含义的段名。段定义的一般格式如下:段名 SEGMENT 对齐类型 组合类型 类别 ;段内的具体内容段名 ENDS 其中:“段名必须是一个合法的标识符,前后二个段名要相同。可选项“对齐类型、“组合类型和“类别的说明作用请见6.3节中的表达。 段的长度是指该段所占的字节数:如果段是数据段,那么其长度是其所有变量所占字节数的总和;如果段是代码段,那么其长度是其所有指令所占字节数的总和
2、。 在通常情况下,一个段的长度不能超过64K,在80386及其以后系统的保护方式下,段基地址是32位,段的最大长度可达4G。6.1 源程序的根本组成源程序的根本组成第第6章章 程序的根本结构程序的根本结构一个数据段的定义例子:DATA1 SEGMENTword1DW1, 9078H, ?byte1DB21, WorldDD12345678HDATA1 ENDS一个代码段的例子:CODE1 SEGMENTMOVAX, DATA1;把数据段DATA1的段值送AXMOVDS, AX ;把AX的值送给DS,即:DS存储数据段的段值MOVAX, 4C00HINT21H;调用DOS功能,结束程序的运行CO
3、DE1 ENDS第第6章章 程序的根本结构程序的根本结构6.1.2 段存放器的说明语句段存放器的说明语句 在汇编语言源程序中可以定义多个段,每个段都要与一个段存放器建立一种对应关系。建立这种对应关系的说明语句格式如下:ASSUME 段存放器名:段名, 段存放器名:段名, 其中:段存放器是CS、DS、ES、SS、FS和GS,段名在段定义语句说明。 例如,ASSUME CS:CODE1, DS:DATA1 说明了:CS对应于代码段CODE1,DS对应于数据段DATA1。 在ASSUME语句中,还可以用关键字NOTHING来说明某个段存放器不与任何段相对应。下面语句说明了段存放器ES不与某段相对应。
4、ASSUME ES:NOTHING 在通常情况下,代码段的第一条语句就是用ASSUME语句来说明段存放器与段之间的对应关系。 在代码段的其它位置,还可以用另一个ASSUME语句来改变前面ASSUME语句所说明的对应关系,这样,代码段中的指令就用最近的ASSUME语句所建立的对应关系来确定指令中的有关信息。第第6章章 程序的根本结构程序的根本结构例6.1:汇编语言段及其段说明语句的作用。DATA1SEGMENT;定义数据段DATA1word1DW5678hbyte1DB“ABCDEFGDATA1ENDSDATA2SEGMENT;定义数据段DATA2word2DW1234hword3DW9876h
5、DATA2ENDSDATA3SEGMENT;定义数据段DATA3byte2DB?DATA3ENDS第第6章章 程序的根本结构程序的根本结构CODE1 SEGMENT;编写代码段CODE1ASSUME CS:CODE1, DS:DATA1, ES:DATA2;MOVAX, DATA1;MOVDS, AX;MOVAX, DATA2;MOVES, AX;MOVAX, word1;访问段DATA1中的字变量word1MOVword2, AX;访问段DATA2中的字变量word2ASSUME DS:DATA3, ES:NOTHING;MOVAX, DATA3MOVDS, AXMOVBL, byte2;访
6、问段DATA3中的变量byte2MOVAX, 4C00H;INT21H;CODE1 ENDS第第6章章 程序的根本结构程序的根本结构6.1.3 堆栈段的说明堆栈段的说明在源程序中,可用以下方法来定义堆栈段。方法1:Stack1SEGMENTDB256 DUP(?);256是堆栈的长度,可根据需要进行改变TOPLABEL WORDStack1ENDS 由于堆栈是按地址从大到小的存储单元顺序来存放内容的,所以,在堆栈存储单元说明语句之后,再说明一个栈顶别名,这样,对SP的赋值就很方便。 在源程序中,还要添加如下程序段,才能把段Stack1当作堆栈段来使用。ASSUME SS:STACK1;可在代码
7、段的段指定语句中一起说明CLI;禁止响应可屏蔽中断MOVAX, STACK1MOVSS, AXMOVSP, offset TOP;给堆栈段的栈顶存放器SP赋初值STI;恢复响应可屏蔽中断第第6章章 程序的根本结构程序的根本结构方法2:STACK1SEGMENT STACK;定义一个堆栈段,其段名为STACK1DB256 DUP(?)STACK1ENDS 上述段定义说明了该段是堆栈段,系统会自动把段存放器SS和栈顶存放器SP与该堆栈段之间建立相应的关系,并设置其初值,而不用在代码段对它们进行赋值。 除了以上二种方法外,还有一种更简洁的方法来定义堆栈段,有关内容请见第6.4.2节中的表达。第第6章
8、章 程序的根本结构程序的根本结构6.1.4 源程序的结构源程序的结构例6.2:在屏幕上显示字符串“Hello, World.STACK1SEGMENT STACK;定义堆栈段STACK1DB 256 DUP(?)STACK1ENDSDATA1SEGMENT;定义数据段DATA1MSGDB“Hello, World.$DATA1ENDSCODE1 SEGMENT;编写代码段CODE1ASSUME CS:CODE1, DS:DATA1START: MOVAX, DATA1MOVDS, AXMOVDX, offset MSGMOVAH, 9INT21H;中断21H的9H号功能,显示DS:DX指向的字
9、符串MOVAX, 4C00HINT21HCODE1 ENDSENDSTART;源程序的结束语句 伪指令END表示源程序到此为止,汇编程序对该语句之后的任何内容都不作处理,所以,通常情况下,伪指令END是源程序的最后一条语句。 伪指令END后面可附带一个在程序中已定义的标号,该标号指明程序的启动位置。如果源程序是一个独立的程序或主模块,那么,伪指令END后面一定要附带一个标号;如果源程序仅是一个普通模块,那么,其END后面就一定不能附带标号。第第6章章 程序的根本结构程序的根本结构6.2.1 顺序结构顺序结构在学习高级语言程序设计时,我们知道了程序的三大主要结构:顺序结构、分支结构和循环结构。在
10、汇编语言的源程序也同样有此三大结构,所不同的是它们的表现形式不同。用高级语言编写程序时,由于不使用“转移语句而使这三种结构清晰明了。6.2 程序的根本结构程序的根本结构 顺序结构是最简单的程序结构,程序的执行顺序就是指令的编写顺序,所以,安排指令的先后次序就显得至关重要。另外,在编程序时,还要妥善保存已得到的处理结果,为后面的进一步处理直接提供前面的处理结果,从而防止不必要的重复操作。例6.3 编写程序段,完成下面公式的计算。A(X-Y+24)/Z的商,B(X-Y+24)/Z的余数其中:变量X和Y是32位有符号数,变量A,B和Z是16位有符号数。第第6章章 程序的根本结构程序的根本结构6.2.
11、2 分支结构分支结构例6.5 字节变量CHAR1,编写一程序段,把它由小写字母变成大写字母。例6.6 编写一程序段,计算以下函数值。其中:变量X和Y是有符号字变量。例6.7 把以下C语言的语句改写成等价的汇编语言程序段(不考虑运算中的溢出)。If (a+b 0 & c%2=0) a = 62;else a = 21;其中:变量a、b和c都是有符号的整型(int)变量。第第6章章 程序的根本结构程序的根本结构分支伪指令的具体格式如下:格式1:.IF condition 指令序列.ENDIF格式2:.IF condition 指令序列1.ELSE 指令序列2.ENDIF格式3:.IF condit
12、ion1 指令序列1.ELSEIF condition2 指令序列2.ENDIF 其中:条件表达式“condition的书写方式与C语言中条件表达式的书写方式相似,也可用括号来组成复杂的条件表达式。第第6章章 程序的根本结构程序的根本结构 条件表达式中可用的操作符有:=(等于)、!=(不等)、(大于)、=(大于等于)、(小于)、=(小于等于)、&(位操作与)、!(逻辑非)、&(逻辑与)、|(逻辑或)等。 假设在条件表达式中检测标志位的信息,那么可以使用的符号名有:CARRY?(相当于CF=1)、OVERFLOW?(OF=1)、PARITY?(PF=1)、SIGN?(SF=1)、ZERO?(ZF
13、=1)等。例如:.IF CARRY? & AX != BX ;检测CF=1且AX!=BX是否成立;汇编语言指令序列.ENDIF 在指令序列中,还可再含有其它的.IF伪指令,即:允许嵌套。伪指令.ELSEIF引导出另一个二叉分支,但它不能作伪指令块的第一个伪指令。第第6章章 程序的根本结构程序的根本结构6.2.3 循环结构循环结构 循环结构是一个重要的程序结构,它具有重复执行某段程序的功能。通常,循环结构包括以下四个组成局部:循环初始化局部初始化循环控制变量、循环体所用到变量;循环体局部循环结构的主体;循环调整局部循环控制变量的修改、或循环终止条件的检查;循环控制局部程序执行的控制转移。第第6章
14、章 程序的根本结构程序的根本结构一、用循环指令构成循环结构例6.10:分类统计字数组data中正数、负数和零的个数,并分别存入内存字变量Positive、Negative和Zero中,数组元素个数保存在其第一个字中。例6.11:把数组score的平均值(取整)存入字变量Average中,数组以负数为结束标志。第第6章章 程序的根本结构程序的根本结构二、用伪指令实现的循环结构 在宏汇编MASM 6.11系统中,增加了表达循环结构的伪指令:WHILE循环、REPEAT-UNTIL循环。另外,还增加两个辅助循环的伪指令。 循环伪指令的格式和含义如下:1、WHILE型循环伪指令.WHILE condi
15、tion 循环体的指令序列;条件condition成立时所执行的指令序列.ENDW其中:.ENDW与前面的.WHILE相匹配,它标志着其循环体到此结束。 如果条件表达式“condition在循环开始时,就为“假(false),那么,该循环体一次也不会被执行。第第6章章 程序的根本结构程序的根本结构2、REPEAT型循环伪指令.REPEAT.REPEAT 循环体的指令序列 循环体的指令序列.UNTIL condition.UNTILCXZ condition REPEAT型循环在执行完循环体后,才判定逻辑表达式condition的值。假设该表达式的值为真,那么终止该循环,并将执行伪指令.UNTI
16、LCXZ后面的指令,否那么,将向上跳转到伪指令.REPEAT之后的指令,为继续执行其循环体作准备。 如果.UNTILCXZ后面没有写逻辑表达式,那么,由.REPEAT.UNTILCXZ所构成的循环与用LOOP指令所过程的循环是一致的,它们都是以“CX=0为循环终止条件。 如果.UNTILCXZ后面书写了逻辑表达式,那么,该逻辑表达式的形式只能是:“EXP1=EXP2或“EXP1!=EXP2。所以,这时由“.REPEAT.UNTILCXZ condition所构成的循环就与用LOOPNE/LOOPE指令所过程的循环是一致的,它们都是以“condition | CX=0为循环终止条件。 .REPE
17、AT.UNTILCXZ的循环体也会至少被执行一次。 .WHILE.ENDW和.REPEAT.UNTILCXZ的循环体内还可再含有循环伪指令,这样就构成了循环结构的嵌套。第第6章章 程序的根本结构程序的根本结构3、辅助循环伪指令终止循环伪指令.BREAK.BREAK .IF condition 该伪指令用来终止包含它的最内层循环。前者是无条件终止循环,后者是仅当逻辑表达式condition为真时,才终止循环。.WHILE 1.REPEAT .BREAK .IF condition .BREAK .IF condition .ENDW.UNTIL 0 对于以上二个循环,如果没有指令来终止循环的话,
18、它们都将进入死循环状态,但如果在该层循环体内,存在伪指令“.BREAK .IF condition的话,那么,当逻辑表达式condition为真时,该循环就会被终止了。第第6章章 程序的根本结构程序的根本结构n循环继续伪指令n.CONTINUEn.CONTINUE .IF conditionn 该伪指令用于直接跳转到包含它的最内层循环的计算循环条件表达式的代码处。前者是无条件转移到计算循环条件表达式的代码处,后者是仅当条件表达式condition为真时,才进行这样的跳转。n 辅助循环伪指令.BREAK和.CONTINUE只能在伪指令.WHILE.ENDW和.REPEAT.UNTIL的循环体内使
19、用。n例6.12 显示9个数字字母19,26个大写字母,和显示任意输入的数字字符,并用按“回车键来结束本程序的运行。第第6章章 程序的根本结构程序的根本结构 段定义的一般格式如下:段名 SEGMENT 对齐类型 组合类型 类别 段名 ENDS 段属性“对齐类型、“组合类型和“类别要按此顺序说明,但这些选项可根据需要选择书写。如果源程序中不指定某个属性,那么,汇编程序将使用该属性的缺省值。 程序中的段名可以是唯一的,也可以与其它段同名。在同一模块中,如果有二个段同名,那么后者被认为是前段的后续,这样,它们就属同一段。 当同一模块出现二个同名段时,那么后者的可选项属性要么与前者相同,要么不写其属性
20、而选用前者的段属性。 略。6.3 段的根本属性段的根本属性第第6章章 程序的根本结构程序的根本结构程序存储模式说明伪指令的格式如下:.MODEL 存储模式,语言类型 ,操作系统类型 ,堆栈类型 程序可选的存储模式有:TINY、SMALL、COMPACT、MEDIUM、LARGE、HUGE和FLAT。 伪指令.MODEL必须写在源程序的首部,且只能出现一次,其前内容只能是注释。 如果用伪指令来指定程序所遵循的语言类型,那么,将不允许子程序的嵌套定义。6.4 简化的段定义简化的段定义6.4.1 存储模型说明伪指令存储模型说明伪指令第第6章章 程序的根本结构程序的根本结构lTINYl 该存储类型是为
21、编写COM文件类型而设置的。程序员还可用汇编命令行选项/AT和连接命令选项/TINY来到达此目的。lSMALLl 所有的数据变量必须在一个数据段之内,所有的代码也必须在一个代码段之内。该存储类型是独立汇编语言源程序常用的存储模型。lMEDIUMl 所有的数据变量必须在一个数据段之内,但代码段可以有多个。在这种模型下,数据段存放器的内容保持不变,转移可以是段间转移。lCOMPACTl 数据段可以有多个,但代码段只能有一。lLARGEl 数据段和代码段都可以有多个,但一个数组的字节数不能超过64KB。lHUGEl 数据段和代码段都可以有多个,一个数组的字节数也可以超过64KB。lFLATl FLA
22、T存储模式在创立执行文件时,将使该程序仅含一个包括程序数据和代码的32位段,并且只能在80386及其以后的计算机系统中运行。该程序的文件类型为EXE。第第6章章 程序的根本结构程序的根本结构程序存储模式说明伪指令的格式如下:.MODEL 存储模式,语言类型 ,操作系统类型 ,堆栈类型 程序可选的存储模式有:TINY、SMALL、COMPACT、MEDIUM、LARGE、HUGE和FLAT。 伪指令.MODEL必须写在源程序的首部,且只能出现一次,其前内容只能是注释。 如果用伪指令来指定程序所遵循的语言类型,那么,将不允许子程序的嵌套定义。6.4.2 简化段定义伪指令简化段定义伪指令第第6章章
23、程序的根本结构程序的根本结构u代码段定义u.CODEu 作用:说明其下面的内容是代码段中内容。u堆栈段定义u.STACK 堆栈字节数u 其中,“堆栈字节数可以不写,其缺省值为1024B。u数据段定义u.DATA / .DATA? / .CONSTu 作用:说明其下面的内容是数据段中的变量定义。u 在一个源程序中,可以有多个伪指令“.DATA定义的数据段,这就好象在源程序中定义多个同段名的数据段一样。u 伪指令“.DATA?说明下面是一个未初始化数据段的开始,u 伪指令“.CONST说明下面是一个常数数据段的开始。u远程数据段定义u.FARDATA 段名 / .FARDATA? 段名u 其中:“
24、段名是可选项,如果不指定的话,那么该段名就取其缺省段名。u 作用:说明一个独立的数据段。u 伪指令“.FARDATA?说明下面是一个未初始化的、独立数据段的开始。第第6章章 程序的根本结构程序的根本结构表6.3 小模式下简化段定义的缺省属性表6.4.3 简化段段名的引用简化段段名的引用伪指令缺省段名对齐类型组合类型类别段组名.CODE_TEXTWORDPUBLICCODE.FARDATAFAR_DATAPARANONEFAR_DATA.FARDATA?FAR_BSSPARANONEFAR_BSS.STACKSTACKPARASTACKSTACKDGROUP.DATADATAWORDPUBLIC
25、DATADGROUP.DATA?BSSWORDPUBLICBSSDGROUP.CONSTCONSTWORDPUBLICCONSTDGROUP第第6章章 程序的根本结构程序的根本结构 在汇编程序MASM中,提供了二组简化的代码伪指令:.STARTUP和.EXIT。.STARTUP在代码段的开始用于自动初始化存放器DS、SS和SP;.EXIT用于结束程序的运行,它等价于以下二条语句:MOVAH, 4CHINT21h 当使用汇编程序TASM时,以上二条伪指令分别改为:STARTUPCODE和EXITCODE。 例6.16:.MODEL SMALL.STACK 128.DATA MSG DBSimpl
26、ified Segment Directives.$.CODE .STARTUP;自动初始化存放器DS、SS和SP MOVDX, offset MSG MOVAH, 9H INT21h .EXIT 0 END第第7章章 子程序和库子程序和库 定义子程序的一般格式如下: 子程序名 PROC NEAR | FAR ;子程序体子程序名 ENDP 对子程序定义的具体规定如下:7.1 子程序的定义子程序的定义u “子程序名必须是一个合法的标识符,并前后二者要一致;uPROC和ENDP必须是成对出现的关键字,表示子程序定义开始和结束;u子程序的类型有近(NEAR)、远(FAR)之分,其缺省的类型是近类型;
27、uNEAR类型的子程序只能被与其同段的程序所调用,FAR类型的子程序可被不同段的程序所调用;u子程序至少要有一条返回指令。返回指令是子程序的出口语句,但它不一定是子程序的最后一条语句;u子程序名有三个属性:段值、偏移量和类型。其段值和偏移量对应于子程序的入口地址,其类型就是该子程序的类型。第第7章章 子程序和库子程序和库 在编写子程序时,除了要考虑实现子程序功能的方法,还要养成书写子程序说明信息的好习惯。其说明信息一般包括以下几方面内容:功能描述入口和出口参数所用存放器;可选项,最好采用存放器的保护和恢复方法所用额外存储单元;可选项,可以减少为子程序定义自己的局部变量子程序的所采用的算法;可选
28、项,如果算法简单,可以不写调用时的本卷须知;可选项,尽量防止除入口参数外还有其它的要求子程序的编写者;可选项,为将来的维护提供信息子程序的编写日期;可选项,用于确定程序是否是最新版本 这些说明性信息虽然不是子程序功能的一局部,但其他程序员可通过它们对该子程序的整体信息有一个较清晰认识,为准确地调用它们提供直接的帮助,与此同时,也为实现子程序的共享提供了必要的资料。第第7章章 子程序和库子程序和库 调用子程序指令格式如下:CALL 子程序名/Reg/Mem 子程序的调用指令分为近(near)调用和远(far)调用。如果被调用子程序的属性是近的,那么,CALL指令将产生一个近调用,它把该指令之后地
29、址的偏移量(用一个字来表示的)压栈,把被调用子程序入口地址的偏移量送给指令指针存放器IP即可实现执行程序的转移。7.2 子程序的调用和返回指令子程序的调用和返回指令7.2.1 调用指令调用指令第第7章章 子程序和库子程序和库如果被调用子程序的属性是远的,那么,CALL指令将产生一个远调用。这时,调用指令不仅要把该指令之后地址的偏移量压进栈,而且也要把段存放器CS的值压进栈。在此之后,再把被调用子程序入口地址的偏移量和段值分别送给IP和CS,这样完成了子程序的远调用操作。例如: CALL DISPLAY;DISPLAY是子程序名 CALL BX;BX的内容是子程序的偏移量 CALL WORD1;
30、WORD1是内存字变量,其值是子程序的偏移量 CALL DWORD1;DWORD1是双字变量,其值是子程序偏移量和段值 CALL word ptr BX;BX所指内存字单元的值是子程序的偏移量 CALL dword ptr BX;BX所指内存双字单元的值是子程序的偏移量和段值第第7章章 子程序和库子程序和库 当子程序执行完时,需要返回到调用它的程序之中。为了实现此功能,指令系统提供了一条专用的子程序返回指令。其格式如下:RET/RETN/RETF Imm 子程序的返回在功能上是子程序调用的逆操作。为了与子程序的远、近调用相对应,子程序的返回也分:远返回和近返回。7.2.2 返回指令返回指令第第
31、7章章 子程序和库子程序和库 如果返回指令后面带有立即数(其值通常为偶数),那么表示在得到返回地址之后,SP还要增加的偏移量,它不是类似于高级语言中子程序的返回值。例如:RET;可能是近返回,也可能是远返回RETN;近返回指令RETF;远返回指令RET 6;子程序返回后,(SP)(SP) + 6第第7章章 子程序和库子程序和库例7.1:编写一个子程序UPPER,实现把存放器AL中存放的字符变大写。解:;子程序功能:把AL中存放的字符变大写;入口参数:AL;出口参数:AL;算法描述:判断AL中字符必须在az之间才能把该字符变为大写UPPER PROCCMPAL, a;书写a的ASCII码61H也
32、可以JBoverCMPAL, zJAoverSUBAL, 20H;书写指令AND AL, 0DFH也可以over:RETUPPER ENDP例7.2:编写一个求字符串长度的子程序StrLen,该字符串以0为结束标志,其首地址存放在DS:DX,其长度保存在CX中返回。解:;子程序功能:求字符串的长度;入口参数:DS:DX存放字符串的首地址,该字符串以0为结束标志;出口参数:CX存放该字符串的长度;算法描述:用BX来指针来扫描字符串中的字符,如果遇到其结束标 志,那么停止扫描字符串操作StrLenPROCPUSHAXPUSHBX;用堆栈来保存子程序所用到的存放器内容XORCX, CXXORAL,
33、ALMOVBX, DXagain:CMPBX, ALJZoverINCCX;增加字符串的长度INCBX;访问字符串的指针向后移JMPagainover:POPBX;恢复在子程序开始时所保存的存放器内容POPAXRETStrLenENDP第第7章章 子程序和库子程序和库 一方面,由于CPU中的存放器在任何程序中都是“可见的,一个程序对某存放器赋值后,在另一个程序中就能直接使用,所以,用存放器来传递参数最直接、简便,也是最常用的参数传递方式。但另一方面,CPU中存放器的个数和容量都是非常有限,所以,该方法适用于传递较少的参数信息。 例7.1是用存放器传递参数的例子,子程序处理的数据被保存在存放器A
34、L中。假设有以下的程序段:MOVAL, bCALLUPPER;子返回时,(AL)=BMOVAL, 2CALLUPPER;子返回时,AL的值不变,因为2不是字母7.3 子程序的参数传递子程序的参数传递7.3.1 存放器传递参数存放器传递参数第第7章章 子程序和库子程序和库例7.3:按五位十进制的形式显示存放器BX中的内容,如果BX的值小于0,那么应 在显示数值之前显示负号-。例如:(BX)=123,显示:00123;(BX)=-234,显示:-00234;解: 见书,略。第第7章章 子程序和库子程序和库 在调用子程序时,当需要向子程序传递大量数据时,因受到存放器容量的限制,就不能采用存放器传递参
35、数的方式,而要改用约定存储单元的传送方式。 例7.2是采用约定存储单元传递参数的例子,所处理的数据不是直接传给子程序,而是把存储它们的地址告诉子程序。7.3.2 约定存储单元传递参数约定存储单元传递参数例7.4:编写一个子程序分类统计出一个字符串中数字字符、字母和其它字符的个数。该字符串的首地址用DS:DX来指定(以0为字符串结束),各类字符个数分别存放BX、CX和DI中。解: 见书,略。例7.5:显示出任意字符串中数字字符、字母和其它字符的个数。解: 见书,略。第第7章章 子程序和库子程序和库 堆栈是一个特殊的数据结构,它通常是用来保存程序的返回地址。当用它来传递参数时,势必会造成数据和返回
36、地址混合在一起的局面,用起来要特别仔细。 具体做法如下:7.3.3 堆栈传递参数堆栈传递参数u当用堆栈传递入口参数时,要在调用子程序前把有关参数依次压栈,子程序从堆栈中取到入口参数;u当用堆栈传递出口参数时,要在子程序返回前,把有关参数依次压栈(这里还需要做点额外操作,要保证返回地址一定在栈顶),调用程序就可以从堆栈中取到出口参数。第第7章章 子程序和库子程序和库1、用堆栈传递入口参数的调用方法:PUSHPara1PUSHParan;把n个字的参数压栈CALLSUBPRO;调用子程序SUBPRO第第7章章 子程序和库子程序和库1、用堆栈传递入口参数的调用方法:PUSHPara1PUSHPara
37、n;把n个字的参数压栈CALLSUBPRO;调用子程序SUBPRO第第7章章 子程序和库子程序和库2、在子程序中取入口参数的方法段内调用子程序SUB1PROC NEARPUSHBP;保护存放器BPMOVBP, SP;用存放器BP来访问堆栈,读取参数;保护其它存放器的指令MOVParan, BP+4MOVPara1, BP+4+2*(n-1)SUB1ENDP从堆栈中取入口参数第第7章章 子程序和库子程序和库u段间调用子程序u 在段间调用子程序时,CALL指令会把返回地址的偏移量和段存放器CS的内容都压栈。u 在进入子程序后,需要用BP来读取传递过来的参数,所以,也要先保护BP原来的值,再把当前S
38、P的值传送给BP。u 当前BP所指向的堆栈单元与最后一个参数Paran之间隔着BP的原值、返回地址的偏移量和段地址,所以,二者之间相差6个字节。第第7章章 子程序和库子程序和库 在子程序中,保存和恢复存放器内容的主要方法是:在子程序的开始把它所用到的存放器压进栈,在返回前,再把它们弹出栈。这样编写的好处是该子程序可以被任何其它程序来调用。 在调用指令前,不需要保存存放器,在调用指令后,也无需恢复存放器。 利用堆栈来保存和恢复存放器内容方法的一般形式如下:XXXXX PROCPUSHREG1;把所使用的存放器压栈,REGi代表某个存放器PUSHREGn;子程序的处理功能语句POPREGn;前面压
39、栈的存放器弹出,注意它们的次序POPREG1RETXXXXX ENDP7.4 存放器的保护与恢复存放器的保护与恢复第第7章章 子程序和库子程序和库 在子程序中利用堆栈来保存和恢复存放器内容。利用堆栈来实现此项功能时,应注意以下几点:u用堆栈保存和恢复存放器的内容,要注意堆栈“先进后出的操作特点u通常情况下不保护入口参数存放器的内容,当然,也可以根据事先的约定而对它们加以保护u如果用存放器带回子程序的处理结果,那么,这些存放器一定不能加以保护u整个子程序的执行几乎肯定要改变标志位,可用PUSHF和POPF来保护和恢复标志位,但一般在子程序中不保护标志位,除非有此特殊需要第第7章章 子程序和库子程
40、序和库子程序名 PROC distance langtype visibility USES 存放器列表 ,参数:数据类型. LOCAL varlist 子程序的程序体子程序名 ENDP 定义子程序时,可使用参数表来直接指明其所要的参数,但程序员必须先用.MODEL伪指令,或使用参数来说明本子程序所使用的程序设计语言类型。 程序员在定义子程序时,最好先说明该子程序的原型(用伪指令PROTO)。这样,在调用时,系统可以自动进行类型检查,也可以使用更方便的调用伪指令INVOKE来调用该子程序。 7.5 子程序的完全定义子程序的完全定义7.5.1 子程序完全定义格式子程序完全定义格式第第7章章 子程
41、序和库子程序和库 子程序的位距(Distance)有:Near、Far、Near16、Far16、Near32和Far32。 子程序位距描述符告诉汇编程序该子程序是在本段之内(Near),还是在本段之外(Far)。7.5.2 子程序的位距子程序的位距 子程序语言类型(Language Type)可以是任何一种有效的程序设计语句类型,由它来告诉汇编程序将使用什么样的标识符的命名风格、子程序的调用和返回约定。该语言类型说明可使汇编语言程序与其它语言程序到达共享的目的。 程序员可用另外三种方法来设置程序的语言类型:.MODEL、OPTION LANGTYPE:和命令行选项/Gx。 假设在程序和命令行
42、中都说明了语言类型,那么,前者的说明优先。7.5.3 子程序的语言类型子程序的语言类型第第7章章 子程序和库子程序和库 子程序的可见性(Visibility)决定该子程序对其它模块是否可用。它共有三个属性值:PRIVATE、PUBLIC和EXPORT。7.5.4 子程序的可见性子程序的可见性 当程序员想用自己定义的宏来替代缺省的“起始和“结束的代码段时,可用以下说明语句来实现:OPTION PROLOGUE : MacroName1OPTION EPILOGUE : MacroName2 PROLOGUE和EPILOGUE分别指定MacroName1和MacroName2为“起始和“结束代码段
43、的宏名。 假设程序员不要汇编程序自动产生“起始和“结束代码,那么可用NONE来代替说明语句中的宏名,即:OPTION PROLOGUE : NONEOPTION EPILOGUE : NONE7.5.5 子程序的起始和结束操作子程序的起始和结束操作第第7章章 子程序和库子程序和库 保护存放器说明子句的说明格式:USES 存放器列表 该说明子句要求汇编程序为其生成保护和恢复存放器的指令序列:在进入子程序执行指令之前,把存放器列表中的存放器压进堆栈;在结束子程序时,把先前压进堆栈的存放器弹出,以到达保护存放器的目的。 存放器列表:列举出在子程序中需要保护的存放器名,即:在子程序开始时需要把内容进栈
44、的存放器名。假设有多个存放器名,那么在存放器名之间要用“空格来分开。7.5.6 存放器的保护和恢复存放器的保护和恢复第第7章章 子程序和库子程序和库例如:DsipPROC USES AX DX, FUNC:WORD, MSG:PTR BYTEMOVDX, MSGMOVAX, FUNCINT21HRETDispENDP 汇编程序在处理该子程序时,会根据子句USES的作用,在第一条指令“MOV DX, MSG之前,插入把存放器AX和DX进栈的指令序列,即:PUSHAXPUSHDX 而在返回指令RET之前插入把存放器DX和AX的值弹出的指令序列,即:POPDXPOPAX 注意:假设子程序含有多个RE
45、T或IRET指令,那么,汇编程序在每个RET或IRET指令前都将增加相应的弹出堆栈指令序列。第第7章章 子程序和库子程序和库 子程序参数是用来向子程序传递信息的数据。假设有多个参数,那么参数之间要用逗号分割。为了能说明子程序的参数,程序员必须事先指定参数所遵循的语言类型或使用“语言类型参数。 参数的数据类型可以是任何一个有效的数据类型说明符或VARARG。 VARARG数据类型允许向子程序传递“个数不定的参数,其参数之间要用逗号“,来分开。 假设参数表中含有VARARG说明的参数,那么,该参数一定是该子程序的最后一个参数。其规定隐含地说明了在参数表中只能有一个用VARARG说明的参数。 如果没
46、有显式地指定某个参数的数据类型,那么,在16位段规模的情况下,其缺省的数据类型是WORD;在32位段规模的情况下,其缺省的数据类型是DWORD。7.5.7 子程序的参数传递子程序的参数传递第第7章章 子程序和库子程序和库 子程序原型的说明格式如下:子程序名 PROTO distance langtype ,parameter:tag. 该说明语句告诉汇编程序该子程序的假设干属性,如:位距、语语言类型、参数个数及其类型等。这样,汇编程序就可以对其定义进行适当的检查。 如果对所有基于堆栈的过程都定义一个原型,那么,就可把这些原型存放在一个独立的包含文件(用伪指令INCLDUE来装入)中。使用这种方
47、法对将来把所有子程序放入自定义的库文件中是非常方便的。 该原型说明语句中参数distance、langtype、parameter和tag等的含义与前面的表达相一致。7.5.8 子程序的原型说明子程序的原型说明第第7章章 子程序和库子程序和库 子程序调用伪指令INVOKE与调用指令CALL在功能上是一致的,但它使汇编语言的子程序调用方法高级语言化。 调用伪指令INVOKE的使用格式如下:INVOKE expression , arguments其中:expression 地址表达式,通常为子程序名; arguments 传递给子程序的参数列表,各参数之间用,分开, 参数可以是存放器、表达式或A
48、DDR 标识符等。 该伪指令是调用基于堆栈的子程序的方法,它把所有参数压栈,子程序结束时,又把参数自动弹出堆栈。 在参数传递时,汇编程序将根据子程序的原型进行数据类型检查。假设需要进行参数类型转换的话,汇编程序那么自动生成一段代码来满足数据类型转换的要求。7.5.9 子程序的调用伪指令子程序的调用伪指令第第7章章 子程序和库子程序和库例如:INVOKE TEST, AX, 12+34, ADDR MSG其中:TEST是子程序名,存放器AX和表达式“12+34是参数,“ADDR MSG是传递变量MSG的地址。例7.6 编写一个累加参数数值的子程序。其中参数的个数不定,参数的个数由第一个参数来确定
49、。解:.MODEL SMALL.STACK 256.CODE;第一个参数parmcount确定其后面参数parmvalues中所含参数的个数ADDUP PROC NEAR C, parmcount:WORD, parmvalues:VARARGXORAX, AXXORSI, SIMOVCX, parmcount.REPEAT ADDAX, parmvaluesSI INCSI INCSI.UNTILCXZRETADDUP ENDP.STARTUPINVOKE ADDUP, 3, 5, 2, 4;计算5+2+4INVOKE ADDUP, 4, 1, 2, 3, 4;计算1+2+3+4.EXIT
50、0END第第7章章 子程序和库子程序和库 局部变量的定义格式:LOCAL 变量名数量 :数据类型 ,变量名数量 :数据类型. 伪指令LOCAL的作用是说明一个或多个临时的局部变量(位于堆栈中)。局部变量必须在任何指令之前加以说明,可用多个LOCAL伪指令来说明局部变量。 在子程序中,假设说明了某个局部变量,那么子程序体中的指令就可使用该局部变量。汇编程序会把对它的引用转换成用指针存放器BP来访问其在堆栈中的实际存储单元。 局部变量只在当前子程序中使用,离开该子程序,它们就不能再被引用。但在局部变量的命名规那么上有所不同,高级语言中的局部变量可与外层变量同名,而汇编语言中的局部变量不能与其它任何
51、变量同名,否那么,在汇编时,将会给出“重定义(Symbol redefinition)的错误信息。7.5.10 局部变量的定义局部变量的定义第第7章章 子程序和库子程序和库 “数量用来说明该变量所具有的元素个数,该数量必须写在括号“ 之中。“数量说明项是可选项。 局部变量的类型说明符可以是任何合法的数据类型说明符。在16位段环境下,该缺省数据类型是WORD,而在32位段环境下,该缺省数据类型是DWORD。 例如:LOCAL data20:BYTE, num:WORD 在上例的说明中,定义了二个局部变量:data和num。前者是字节类型,并有20个元素,后者是字类型,只有其自身1个元素。第第7章
52、章 子程序和库子程序和库 宏汇编MASM系统提供了建立库文件的命令文件LIB.EXE。其通常是在命令行环境(MS-DOS方式)下使用的,当然,也可在Windows操作系统环境下利用其“开始菜单下的“运行功能项来使用。一、MS-DOS系统 显示命令LIB用法的命令如下: lib /? 该命令的显示结果如右图所示。7.6.1 建立库文件命令建立库文件命令7.6 子程序库子程序库第第7章章 子程序和库子程序和库二、Windows系统第第7章章 子程序和库子程序和库 假设现有目标文件sub1.obj、sub2.obj和sub3.obj,要用它们建立库文件mylib.lib。可用以下方法来建立该库文件:
53、方法1:所有目标文件都准备好了,可一次性把它们参加到库文件中lib mylib +sub1 +sub2 +sub3方法2:随着目标文件的逐个生成,而依次把它们参加到库文件中lib mylib +sub1lib mylib +sub2lib mylib +sub3 假设源文件sub3.asm已修改,并也生成了新的目标文件sub3.obj,这时,可用下面命令来实现替换:lib mylib -+sub3 当提示目标库文件名(Output library)时,可按“回车用默认的原库文件名。 如果想查看库文件mylib.lib中文件的大小和存放的先后次序,可用以下命令:lib mylib, list ;
54、把库文件mylib.lib中的文件结构生成到文件list中type list7.6.2 建立库文件举例建立库文件举例第第7章章 子程序和库子程序和库 当开发一个功能较强、关系较复杂的应用程序时,其执行文件常常由多个目标文件(模块)连接而成的。各模块之间无疑会存在着相互调用、相互访问数据单元等内在联系。 为了解决描述各模块之间的联系,汇编语言提供了二条伪指令PUBLIC和EXTRN,它们的作用说明变量、过程和函数是“全局的或“外部的。 这二条伪指令的具体用法和含义如下:1. 伪指令PUBLIC 伪指令PUBLIC是用来说明:当前模块中哪些标识符是能被其它模块引用的公共标识符。其说明的一般格式如下
55、:PUBLIC 标识符1, 标识符2, 其中:“标识符可以是变量名、过程名和程序标号,标识符之间要用逗号分开。上面说明语句说明了标识符1、标识符2等是公共标识符,可以被其它模块引用。在一个模块中,可用多条PUBLIC伪指令来说明公共标识符。7.6.3 库文件的应用库文件的应用第第7章章 子程序和库子程序和库2. 伪指令EXTRN 伪指令EXTRN是用来说明:在当前模块所使用的标识符中,哪些标识符是已在其它模块中被定义为指定类型的标识符。如果当前模块使用了其它模块的标识符,而对它又不加以说明的话,那么,汇编程序将会给出以下出错信息:error nnnnn: undefined symbol :
56、XXXXXX伪指令EXTRN的一般说明格式如下:EXTRN 标识符1:类型1, 标识符2:类型2, 其中:“标识符和“类型之间要用冒号“:连接。 上面语句说明了标识符1、标识符2等是外部标识符,它们在其它模块中已被分别定义为类型1、类型2等,该类型说明符可以是:NEAR、FAR、BYTE、WORD、DWORD等之一。 在一个模块中,可用多条EXTRN伪指令来说明本模块所引用的外部标识符。 注意:伪指令EXTRN中所说明的标识符必须在其定义的模块中被PUBLIC伪指令说明为公共标识符,并且其说明的标识符类型要与该标识符在定义是的类型相一致,否那么,要么不能生成其可执行文件,要么其执行文件不能正确
57、运行。第第7章章 子程序和库子程序和库 程序员在编写程序时,通常采用模块化的思想来组织源程序:把各类子程序分别编写在不同的源程序中,在各源程序中说明所用到的、在其它模块中已定义的子程序,或说明本模块所定义的子程序可被其它模块调用。这样就可以分别汇编它们而得到其相应的目标文件,在有了这些目标文件后,程序员就可用不同的方法来生成最终的可执行目标文件。方法1:直接连接目标文件而生成可执行文件 这种方法简单、方便,也是常用的一种方法,但在连接时,LINK程序会把目标文件中的所有代码都嵌入到执行文件中,从而使得:包含在某目标文件中、但并没有被调用的子程序代码也出现在执行文件中。这种情况无疑增加了执行文件
58、的字节数。7.6.4 库文件的好处库文件的好处第第7章章 子程序和库子程序和库方法2:采用子程序库的方法 库文件可以把它看成是子程序的集合。库文件中存储着子程序名、子程序的目标代码以及连接所需要的重定位信息。 当某目标文件与库文件相连接时,LINK程序只把目标文件所用到的子程序从库文件中找出来,并合并到最终的可执行文件中,而不是把库中所含的全部子程序都纳入最后的可执行文件。 对照方法1和2可知:用库文件来存储子程序可生成较短的执行文件。第第8章章 输入输出和中断输入输出和中断 输入输出是一个完整应用程序的重要组成局部,是交互式应用程序不可缺少的组成局部。在高级语言编程时,程序员可直接用输入输出
59、语句来完成键盘输入、屏幕显示或打印输出等需求,而无需关心这些输入输出语句是如何实现的。但汇编语言是与机器有关的程序设计语言,要编写出具有输入输出功能的代码段就必须清楚CPU为输入输出提供了哪些指令,或计算机系统提供了哪些可直接使用的功能调用。8.1.1 I/O端口地址端口地址8.1 输入输出的根本概念输入输出的根本概念 I/O端口是CPU与输入输出设备的交换数据的场所。通过I/O端口,处理机可以接受从输入设备输入的信息,也可向输出设备发送信息。 在计算机系统中,用不同的数字给各类I/O端口进行编号,这种I/O端口的编号就称为I/O端口地址。第第8章章 输入输出和中断输入输出和中断 在Intel
60、公司的CPU家族中,I/O端口的地址空间可达64K,即可有65536个字节端口,或32768个字端口。这些地址不是内存单元地址的一局部,不能用普通访问内存指令来读取其信息,要用专门的I/O指令才能访问它们。虽然CPU提供了很大的I/O地址空间,但目前大多数微机所用的端口地址都在03FFH范围之内,其所用的I/O地址空间只占整个I/O地址空间的很小局部。表8.1 几个重要的I/O端口地址端口地址端口名称端口地址端口名称020H023H中断屏蔽寄存器378H37FH并行口LPT2040H043H时针/计数器3B0H3BBH单色显示器端口060H键盘输入端口3BCH3BFH并行口LPT1061H扬声
61、器(0,1位)3C0H3CFHVGA/EGA200H20FH游戏控制口3D0H3DFHCGA278H27FH并行口LPT33F0H3F7H磁盘控制器2F8H2FFH串行口COM23F8H3FFH串行口COM1第第8章章 输入输出和中断输入输出和中断8.1.2 I/O指令指令 由于I/O端口地址和内存单元地址是相互独立的,这些端口地址不能用普通的访问内存指令来访问其信息。输入指令IN 输入指令IN的一般格式如下:INAL/AX, PortNo/DX 该指令的作用是从端口中读入一个字节或字,并保存在存放器AL或AX中。如果某输入设备的端口地址在0255范围之内,那么,可在指令IN中直接给出,否那么
62、,要把该端口地址先存入存放器DX中,然后由DX来给出其端口地址。 例如:INAL, 60H ;从端口60H读入一个字节到AL中INAX, 20H ;把端口20H、21H按“高上下低组成的字读入AXMOVDX, 2F8HINAL, DX;从端口2F8H读入一个字节到AL中INAX, DX ;把端口2F8H、2F9H按“高上下低组成的字读入AX第第8章章 输入输出和中断输入输出和中断u输出指令OUTu 输出指令OUT的一般格式如下:uOUTPortNo/DX, AL/AXu 该指令的作用是把存放器AL或AX的内容输出到指定端口。如果某输出设备的端口地址在0255范围之内,那么,可在指令OUT中直接
63、给出,否那么,要把该端口地址先存入存放器DX中,然后在指令中由DX来给出其端口地址。u 例如:uOUT61H, AL;把AL的内容输出到端口61H中uOUT20H, AX;把AX的内容输出到端口20H、21H中uMOVDX, 3C0HuOUTDX, AL;把AL的内容输出到端口3C0H中uOUTDX, AX;把AX的内容输出到端口3C0H、3C1H中第第8章章 输入输出和中断输入输出和中断8.2.1 中断的根本概念中断的根本概念8.2 中断中断1. 中断和中断源 CPU在执行程序时,是否响应中断要取决于以下三个条件能否同时满足:(1)、有中断请求(2)、允许CPU接受中断请求(3)、一条指令执
64、行完,下一条指令还没有开始执行 条件(1)是响应中断的主体。除用指令INT所引起的软件中断之外,其它中断请求信号是随机产生的,程序员是无法预见的。 程序员可用程序来控制条件(2)的满足与否,即用指令STI和CLI来控制CPU是否响应可屏蔽的外部中断。但对于不可屏蔽中断和内部中断,程序员是无法控制它们的,CPU一定会执行这些中断的中断效劳程序。第第8章章 输入输出和中断输入输出和中断2. 中断向量表和中断效劳程序 中断向量表是一个特殊的线性表,它保存着系统中所有中断效劳程序或系统参数的入口地址(偏移量和段地址)。在微机系统中,该向量表有256个元素,每个元素占4个字节,总共占1K个字节。 右图中
65、的“偏移量和“段地址是指该中断效劳程序入口单元的“偏移量和“段地址。从图中不难看出:假设中断号为n,那么在中断向量表中存储该中断效劳程序入口地址的单元地址为:4n。第第8章章 输入输出和中断输入输出和中断表8.2 局部常用的中断号及其含义中断号含义中断号含义0除法出错8定时器1单步9键盘2非屏蔽中断A未用3断点BCOM24溢出CCOM15打印屏幕D硬盘(并行口)6未用E软盘7未用F打印机第第8章章 输入输出和中断输入输出和中断8.2.2 引起中断的指令引起中断的指令1、中断指令INT 中断指令INT的一般格式如下:INT Imm其中:立即数Imm是一个00FFH范围内的整数。 指令执行的步骤:
66、u把标志存放器压栈,去除标志位IF和TF;u把段存放器CS的内容压栈,并把中断效劳程序入口地址的高字局部送CS;u把指针存放器IP的内容压栈,并把中断效劳程序入口地址的低字局部送IP;对80386及其以后的CPU,对16位段,压16位IP;对32位段,压32位EIP。在该指令执行完后,CPU将转去执行中断效劳程序。由于有了指令INT,程序员就能为满足某种特殊的需要,在程序中有目的地安排中断的发生,也就是说,该中断不是随机产生的,而是完全受程序控制的。第第8章章 输入输出和中断输入输出和中断2、溢出指令INTO 当标志位OF为1时,引起中断。该指令格式如下:INTO 该指令影响标志位:IF和TF
67、。第第8章章 输入输出和中断输入输出和中断8.2.3 中断返回指令中断返回指令 当一个中断效劳程序执行完毕时,CPU将恢复被中断的现场,返回到被中断的程序中。为实现此功能,指令系统提供了一条专用的中断返回指令。该指令的格式如下:IRET/IRETD 该指令执行的过程根本上是INT指令的逆过程,具体如下:从栈顶弹出内容送入IP;再从新栈顶弹出内容送入CS;再从新栈顶弹出内容送入标志存放器; 对80386及其以后的CPU,指令IRETD从栈顶弹出32位内容送入EIP。第第8章章 输入输出和中断输入输出和中断8.2.4 中断和子程序调用中断和子程序调用 中断和子程序调用之间有其相似和不同之处。它们的
68、工作过程非常相似,即:暂停当前程序的执行,转而执行另一程序段,当该程序段执行完时,CPU都自动恢复原程序的执行。 中断和子程序调用在实现方面的主要差异:n子程序调用是程序员在编写源程序时事先安排好的,是可知的,而中断是由中断源根据自身的需要产生的,是不可预见的(用指令INT引起的中断除外);n子程序调用是用CALL指令来实现的,但没有调用中断的指令,只有发出中断请求的事件(指令INT是发出内部中断信号,不要理解为调用中断效劳程序);n子程序的返回指令是RET,而中断效劳程序的返回指令是IRET/IRETD;n在通常情况下,子程序是由应用系统的开发者编写的,而中断效劳程序是由系统软件设计者编写的
69、。第第8章章 输入输出和中断输入输出和中断8.3 中断功能的分类中断功能的分类 汇编语言程序员常用的这类中断有:DOS功能调用(INT 21H)、BIOS中断、硬件和外设的中断等。 在用户程序中,假设直接通过端口来操作硬件或外设,那么,其处理过程没有额外的多余工作,处理速度显然是最快的,但这样做,无疑使用户程序具有了很大的局限性。硬件环境的改变将直接影响程序的正常运行。 假设用户程序通过调用DOS功能来实现其所需功能,那么,应用程序与低层硬件相距较远,操作最终的对象需要经过中间环节,处理速度肯定受到一定的损失,但这种应用程序适应性强,应用范围广,对硬件的依赖性最小。 由于BIOS介于DOS和具
70、体硬件之间,所以,调用BIOS的功能是一个很好的折中方案。程序员可在以下三种情况下考虑使用BIOS的功能:1)、BIOS提供的功能,而DOS没有提供该功能的情况;2)、不能利用DOS功能调用的情况(可能因为某些具体应用的限制);3)、基于处理速度的考虑,需要绕过DOS层的情况。 综上所述,可以归纳出如下结论:使用中断的层次越高,它与硬件设备相关程度就越低,处理速度也就越低,但用户程序的适用范围较广。反之也然。第第8章章 输入输出和中断输入输出和中断8.3.1 键盘输入的中断功能键盘输入的中断功能例8.1 用键盘最多输入10个字符,并存入内存变量Buff中,“CR键结束输入。解:1、方法1.MO
71、DEL SMALLCREQU0DH;定义“回车键的符号名.DATABuffDB10 DUP(?).CODE.STARTUPMOV CX, 0AHLEABX, Buff.REPEAT MOVAH, 0H INT 16H;用BIOS中的中断功能 .BREAK .IF AL=CR MOVBX, AL INC BX.UNTILCXZ.EXIT 0END第第8章章 输入输出和中断输入输出和中断例8.1 用键盘最多输入10个字符,并存入内存变量Buff中,“CR键结束输入。解:2、方法2.MODEL SMALL.DATABuffDB 10, ?, 10 DUP(?);注意缓冲区的定义方式.CODE.STA
72、RTUPLEADX, BuffMOV AH, 0AHINT21H;用DOS中的功能调用.EXIT 0END第第8章章 输入输出和中断输入输出和中断8.3.2 屏幕显示的中断功能屏幕显示的中断功能1、文本显示方式 文本显示方式是指以字符为最小单位的显示方式,每个字符都是以矩形块形式显示的。 在常用的文本显示模式(模式3)下,屏幕被划分成25行,每行可显示80个字符,所以,每屏最多可显示2000(8025)个字符。为了便于标识屏幕上的每个显示位置,我们就用其所在行和列来表示之,并规定:屏幕的左上角坐标为(0, 0),右下角坐标为(24, 79)。 在显示字符时,用一个字节存储该字符的ASCII码,
73、用另一个字节存储的显示属性,即:显示颜色。 由上面的表达可知:在8025的文本显示模式下,满屏可显示2000个字符,也就需要4000个字节来存储一屏的显示信息。第第8章章 输入输出和中断输入输出和中断2、图形显示方式 图形显示是目前最常用的一种显示方式,也是Windows操作系统的默认显示方式。在该显示方式下,我们可以看到优美的图象、VCD、浏览丰富多彩的网页等。 图形显示的最小单位是象素,对每个象素可用不同的颜色来显示。所以,在显示缓冲区内记录的信息是屏幕各象素的显示颜色。 由于各种图形显示模式所能显示的颜色和象素是不同的,它决定了显示缓冲区的存储方式也是不同的。第第8章章 输入输出和中断输
74、入输出和中断例8.2 用直接写屏方式在屏幕第5行、第10列以黄色(0EH)显示字符串“Hello。解:在文本显示方式下,每行显示80个字符,每个字符占2个字节,所以,显示一行需要160个字节。假设在第m行、第n列位置显示字符,那么该位置所对应存储单元的偏移量为:m160 + n2。例8.3 用“霓虹灯的显示方式显示字符串“Hello,按ESC键时结束程序的运行。解:我们用显示颜色的变化来模拟霓虹灯的显示方式,即用颜色15(亮白)作为字符的主要显示颜色,再用颜色12(亮红)从左到右逐个扫描。例8.4 编写一个输入密码的程序,该程序的具体要求如下:1、每输入一个字符,显示字符#表示之;2、密码最多
75、只有10个字符,多余的按键被丢弃;3、假设输入的字符串为“HELLO,那么以蓝色显示Welcome,否那么,以闪烁、亮红色在显示Invalid Password。解:第第8章章 输入输出和中断输入输出和中断例8.5 在256色320200的图形显示模式下,从屏幕最左边向最右边,依次画竖线(从顶到底),线的颜色从1依次加1。要求用中断调用的方法来画线。解:例8.6 在256色320200的图形显示模式下,从屏幕顶到屏幕底依次画横线(从最左边到最右边),线的颜色从1依次加1。要求用直接操作显示缓冲区的方法来画线。解:第第8章章 输入输出和中断输入输出和中断8.3.3 打印输出的中断功能打印输出的中
76、断功能8.3.4 串行通信口的中断功能串行通信口的中断功能8.3.5 鼠标的中断功能鼠标的中断功能8.3.6 目录和文件的中断功能目录和文件的中断功能8.3.7 内存管理的中断功能内存管理的中断功能8.3.8 读取和设置中断向量读取和设置中断向量谢 谢计计算机科学系算机科学系20032003年年0303月月2020日日MgUp%x1F9NhWq&y2GaOiXr*z3HbPkYs(A4IcRlZt)B5JdSm#u-C6KfTn!v+D7LgUo$w0E8NhVp%xRlZt)C6KeSm#u+D7LfTn!v0E8MgUo$x1F9NhVp&y2GaOiWq*z3HbPjXs(A4IcQkZ
77、t)B5JdRl#u-C6KeSn!v+D7LfTo8MgUo$x1F9NhVp&y2GaOiWr*z3HbPjXs(A4IcQkZt)B5JdRl#u-C6KeSn!v+D7LfUo$w0E8MgVp%x1F9NiWq&y2GaPjXr*z3HbQkYs(A4IdRlZt)B5JeSm#u-C6LfTn!v+D8MgUo$w0E9NhVp%x1GaOiWq&y3HbPjXr*z4IcQkYs(B5JdRlZt)C6Ys(A4JdRlZt)B5KeSm#u-C7LfTn!v+E8MgUo$w0F9NhVp%x2GaOiWq&z3HbPjXr*A4IcQkYs)B5J*z3HbPkYs(A4Ic
78、QlZt)B5JdSm#u-C6KeTn!v+D7LgUo$w0E8NhVp%x1F9OiWq&y2GbPjXr*z3IcQkYs(A4JdRlZt)B6KeSm#u-C7LfTn!v+E8MgUo$w1F9NhVp%x2GaOiWq&z3HbPjXr*A4IcQkYs)B5JdRlZu-C6KeSm#v+D7LfTn$weSm#u-D7LfTn!v0E8MgUo$x1F9NhVp%y2GaOiWq*z3HbPjXr(A4IcQkYt)B5JdRl#u-C6KeSm!v+D7LfTo$w0E8MgVp%x1F9NhWq&y2GaOjXr*z3Hs(A4IcQkYt)B5JdRl#u-C6KeS
79、n!v+D7LfTo$w0E8MgVp%x1F9NiWq&y2GaOjXr*z3HbQkYs(A4IcRlZt)B5JeSm#u-C6LfTn!v+D7MgUo$w0E9NhVp%x1GaOiWq&y2HbPjXr*z4IcQkYs(A5JdRlZt)C6KeSm#u+D7LfTn!v0E8MgUo$x1F9NhVpLfUo$w0E8MgVp%x1F9NiWq&y2GaOjXr*z3HbQkYs(A4IdRlZt)B5JeSm#u-C6LfTn!v+D8MgUo$w0E9NhVp%x1GaOiWq&y2HbPjXr*z4IcQkYs(B5JdRlZt)C6KeSm#u+D7LfTn!w0E8M
80、gUo$x1F9NhVp&y2GaOiWq*z3HbPjXs(A4IcQkZt)B5JdRl6KeSm#u+D7LfTn!w0E8MgUo%x1F9NhVp&y2GaOiWr*z3HbPjXs(A4IcQkZt)B5JdRm#u-C6KeSn!v+D7LfUo$w0E8MgVp%x1F9NiWq&y2GaPjXr*z3HbQkYs(A4IdRlZt)B5KeSm#u-C6LfTn!v+D8MgUo$w0E9NhVp%x1GaOiWqMgUo%x1F9NhVp&y2GaOiWr*z3HbPjYs(A4IcQkZt)B5JdRm#u-C6KeTn!v+D7LfUo$w0E8MhVp%x1F9NiW
81、q&y2GaPjXr*z3HcQkYs(A4IdRlZt)B5KeSm#u-C7LfTn!v+D8MgUo$w0F9!v+D7LgUo$w0E8NhVp%x1F9OiWq&y2GbPjXr*z3IcQkYs(A4JdRlZt)B6KeSm#u-D7LfTn!v+E8MgUo$w1F9NhVp%x2GaOiWq&z3HbPj3IcQkYs(A5JdRlZt)B6KeSm#u-D7LfTn!v+E8MgUo$w1F9NhVp%y2GaOiWq&z3HbPjXr(A4IcQkYt)B5JdRlZu-C6KeSm!v+D7LfTn$w0E8MgUp%x1F9NhWq&y2GaOiXr*z3HbPkYs
82、(A4IcRlZt)B5JdSm#u-C6KfTn!v+D7LgUo$wSm#u-D7LfTn!v0E8MgUo$w1F9NhVp%y2GaOiWq*z3HbPjXr(A4IcQkYt)B5JdRl#u-C6KeSm!v+D7LfTo$w0E8MgUp%x1F9NhWq&y2GaOjXr*z3HbPkYs(A4IcRlZt)B5JdSm#u-C6KfTn!v+D7MgUo$w0Ep%x1F9NhWq&y2GaOjXr*z3HbQkYs(A4IcRlZt)B5JeSm#u-C6KfTn!v+D7MgUo$w0E9NhVp%x1FaOiWq&y2HbPjXr*z4IcQkYs(A5JdRlZt)C
83、6KeSm#u-D7LfTn!v0E8MgUo$x1FlZt)B5KeSm#u-C7LfTn!v+E8MgUo$w0F9NhVp%x2GaOiWq&z3HbPjXr*A4IcQkYs)B5JdRlZt-C6KeSm#v+D7LfTn$w0E8MgUo%x1F9NhVq&y2GaOiXr*z3HbPjYs(A4IcQlZt)B5JdRm#u-C6K(A4JdRlZt)B6KeSm#u-C7LfTn!v+E8MgUo$w1F9NhVp%x2GaOiWq&z3HbPjXr(A4IcQkYs)B5JdRlZu-C6KeSm#v+D7LfTn$w0E8MgUp%x1F9NhVq&y2GaOiXr*z3H
84、bPkYs(A4IcQlZt)B5JdSm#u-C6KeTn!vfTn$w0E8MgUp%x1F9NhWq&y2GaOiXr*z3HbPkYs(A4IcQlZt)B5JdSm#u-C6KfTn!v+D7LgUo$w0E8NhVp%x1FaOiWq&y2GbPjXr*z3IcQkYs(A4JdRlZt)B6KeSm#u-D7LfTn!v+EXs(A4IcQkYt)B5JdRl#u-C6KeSn!v+D7LfTo$w0E8MgVp%x1F9NiWGaOiWr*z3HbPjXs(A4IcQkZt)B5JdRl#u-C6KeSn!v+D7LfUo$w0E8MgVp%x1F9NiWq&y2GaPjXr*
85、z3HbQkYs(A4IdRlZt)B5JeSm#u-C6LfTn!v+D8MgUo$w0E9NhVp%x1GaOiWq&y3HbPjXr*z4IcQkYs(B5Jd)B5KeSm#u-C6LfTn!v+D8MgUo$w0F9NhVp%x1GaOiWq&y3HbPjXr*z4IcQkYs(B5JdRlZt-C6KeSm#u+D7LfTn!w0E8MgUo%x1F9NhVp&y2GaOiWr*z3HbPjXs(A4IcQkZt)B5JdRm#u-C6K(A4IdRlZt)B5KeSm#u-C7JdRlZt)B6KeSm#u-C7LfTn!v+E8MgUo$w1F9NhVFaOiWq&y2GbPj
86、Xr*z3IcQkYs(A4JdRlZt)B6KeSm#u-D7LfTn!v+E8MgUo$w1F9NhVp%y2GaOiWq&z3HbPjXr(A4IcQkYs)B5JdRlZu-C6KeSm!v+D7LfTn$w0E8MgUp%x1F9v+D7MgUo$w0E8NhVp%x1FaOiWq&y2GbPjXr*z3IcQkYs(A5JdRlZt)B6KeSm#u-D7LfTn!v0E8MgUo$w1F9NhVp%y2GaOiWq&z3HbPjXr(A4IcQkYt)B5JdRl6KeSm#u-D7LfTn!v0E8MgUo$x1F9NhVp%y2GaOi0F9NhVp%x1GaOiWq&y3H
87、bPjXr*z4IcQkYs(B5JdRlZt-C6KeSm#u+D7LfTn!w0E8MgUo%x1F9NhVp&y2GaOiWr*z3HbPjXs(A4IcQkZt)B5JdRm#u-C6KeSn!vRlZt)B5KeSm#u-C7LfTn!v+D8MgUo$w0F9NhVp%x1GaOiWq&y3HbPjXr*A4IcQkYs(B5JdRlZt-C6KeSm#v+D7LfTn!w0E8MgUo%x1F9NhVp&y2GaOiWr*z3HbPjYs(A4Ic)B5JdRlZt-C6KeSm#v+D7LfTn$w0E8MgUo%x1F9NhVq&y2Uo$w1F9NhVp%y2GaOiWq&
88、z3HbPjXr(A4IcQkYt)B5JdRlZu-C6KeSm!v+D7LfTo$w0E8MgUp%x1F9NhWq&y2GaOiXr*z3HbPkYs(A4IcRlZt)B5Jdz3IcQkYs(A5JdRlZt)C6KeSm#u-D7LfTn!v0E8MgUo$w1F9NhVp%y2GaOiWq*z3HbPjXr(A4IcQkYt)B5JdRl#u-C6KeSm!v+D7LfTo$w0E8MgUp%x1F9NhWq&y2GaOjXHbPjXs(A4IcQkYt)B5JdRl#u-C6KeSn!v+D7LdRm#u-C6KeSn!v+D7L)B5KeSm#u-C7LfTn!v+D8MgU
89、o$w0F9NhVp%x1GaOiWq&y3HbPjXr*A4IcQkYs(B5JdRlZt-C6KeSm#v+D7LfTn!w0E8MgUo%x1F9NhVp&y2GaOiWr*PjXr*A4IcQkYs)B5JdRlZt-C6KeSm#v+D7LfTn!w0E8MgUo%x1F9NhVq&y2GaOiWr*z3HbPjYs(A4IcQlZt)B5JdRm#u-C6KeTn!v+D7LfUo$w0E8MhVp%x1F9Oy2GaOiUp%x1F9NhWq&y2GaOiXr*z3HbPkYs(A4q&y2HbPjXr*z3IcQkYs(A5JdRlZt)C6KeSm#u-D7LfTn!v0E8
90、MgUo$w1F9NhVp%y2GaOiWq*z3HbPjXr(A4IcQkYt)B5JdRl#u-C6KeSm!v+D7LfTo$w0E8MgUp%x1F9Nh2GaOiWq*z3HbPjXs(A4IcQkYt)B5JdRl#u-C6KeSm!v+D7LfTo$w0E8MgVp%x1F9NhWq&y2GaOjXr*z3Hb&y2GaOiWr*z3HbPjYs(A4IcQkZt)B5JdRm#u-C6KeSn!v+D7LfUo$w0E8MhVp%x1F9NiWq&y2GaPjXr*z3HcQkYs(A4q&y3HbPjXr*A4IcQkYs)B5JdRlZt-C6KeSm#v+D7LfTn!w
91、0E8MgUo%x1F9NhVq&y2GaOiWr*z3HbPjYs(A4IcQlZt)B5JdRm#u-C6KeTn!v+D7LfUo$w0E8MhVF9NhVq&y2GaOiXr*z1F9NhWq&y2GaOiXr*z3HbPkYs(A4IcRlHbPjXr*z3IcQkYs(A5JdRlZt)B6KeSm#u-D7LfTn!v0E8MgUo$w1F9NhVp%y2GaOiWq*z3HbPjXr(A4IcQkYt)B5JdRlZu-C6KeSm!v+D7LfTo$w0E8MgUp%NhVp%y2GaOiWq*z3HbPjXs(A4IcQkYt)B5JdRl#u-C6KeSm!v+D7LfT
92、o$w0E8MgVp%xfTn!w0E8MgUo%x1F9NhVp&y2GaOiWr*z3HbPjYs(A4IcQkZt)B5JdRm#u-C6KeSn!v+D7LfUo$w0E8MhVp%x1F9NiWq&y2GaPjXrNhVp%x2GaOiWq&y3HbPjXr*A4IcQkYs(B5JdRlZt-C6KeSm#v+D7LfTn!w0E8MgUo%x1F9NhVq&y2GaOiWr*z3HbPjYs(A4IcQkZt)B5JdRm#IcQkYs)B5JdRlZu-C6KeSm!v+D7LfTn$w0E8MgUp%x1Fp%y2GaOiWq*z3HbPjXr(A4IcQkYt)B5JdRlZu-C6KeSm!v+D7LfTo$w0E8MgUp%x1F9NhWq&y2GaOjXr*z3HbPkYs(A4IcR