资源描述
第三章汇编语言程序设计,本章内容,汇编语言源程序的格式伪操作命令DOS及BIOS功能调用,计算机程序设计语言的演变,1.机器语言直接用机器指令来编制计算机程序的方法。2.汇编语言可以用助记符来表示指令的操作和操作数,也可以用标号和符号来代替地址、常量和变量。3.高级语言更接近于人们的自然语言和习惯的教学语言来描述算法的执行过程,从而使编写的过程更加直观和简练。,为什么要用汇编语言,汇编语言非常接近机器语言程序,通过编制汇编语言程序,可以清楚地了解计算机的工作过程。现在的微机系统中,底层的一些功能仍然靠汇编语言程序来实现。汇编语言程序的效率通常高于高级语言程序。,举例,dataSEGMENTmsgDBHello,World!$dataENDScodeSEGMENTASSUMECS:code,DS:dataMAINPROCNEARstart:MOVAX,dataMOVDS,AXLEADX,msgMOVAH,9hINT21hMOVAX,4C00hINT21hMAINENDPcodeENDSENDstart,在屏幕上显示Hello,World!,本例将在下文中多次提及,为方便计,下文简称其为“Hello例”。,3.2.1分析1分段结构,可以看出,汇编语言源程序是分段结构的形式。一个汇编源程序由若干个段(Segment)组成。每个段以SEGMENT语句开始,以ENDS结束。整个源程序以END语句结尾。这里所说的汇编语言源程序的段和第一章中的CPU管理的存储器的段是不同的概念。汇编语言的段是逻辑段;8086CPU管理的存储器的段是物理段(共有4个:数据段、附加段、堆栈段、代码段,对应4个段寄存器:DS、ES、SS和CS)。一个汇编语言源程序中可以有多个逻辑段。上例中共有两个逻辑段:data和code。,分析2,注:功能号09H的int21中断功能描述:输出一个字符串到标准输出设备上。入口参数:AH09HDS:DX待输出字符的地址说明:待显示的字符串以$作为其结束标志,代码段开头执行了一次功能号09H的21号DOS中断,用于在屏幕上显示字符串。关于DOS功能调用,后文将有详细解释。此处先列出功能号09H的21号DOS中断的相关资料:,最后两行(MOVAX,4C00h、INT21h)也是一个DOS功能调用。,注:功能号4CH的int21中断功能描述:终止程序的执行,并可返回一个代码入口参数:AH4CHAL返回的代码,汇编语言开发过程,源程序:文件名.asm,目标程序:文件名.obj,可执行文件:文件名.exe,Finish,编辑器,如notepad.exe,汇编器,如masm.exe,链接器,如link.exe,调试器,如debug.exe,开发工具(了解),X86+Windows平台下常用的汇编编译器有:Microsoft公司的MASMBorland公司的TASM开源社区的NASMMASM是微软推出的宏汇编语言,自发布以来已有多次版本更新,下页表格中列出了几个较为典型的版本。注:容易与之混淆的是MASM32,它是SteveHutchesson以个人名义发布、基于MASM而构建的软件包。其版本号和MASM的版本号是不同的,比如MASM32V8使用的汇编编译器是MASM6。MASM32的最新版本为MASM32V12。,MASM版本历史(了解),开发工具(了解),Masm5适合进行DOS程序开发;Masm6以后的版本开始支持Win32程序开发。(微软官方发布的Masm6所附的link.exe是SegmentedExecutableLinker,只能开发DOS程序;要进行Win32开发必须配备IncrementalLinker,该类型的link.exe可以从VisualStudio中获取。开发Win32程序推荐使用MASM32开发包)开发DOS程序的Masm下载地址:Masm5.00罗云彬的编程乐园http:/211.90.241.130:22366/view.asp?file=51Masm615ForDosaogo汇编小站,开发步骤演示(了解),使用MASM5.0,开发步骤演示(了解),使用MASM6.15ForDOS,3.2.2语句的类型,汇编语言源程序中的语句主要有以下两种类型:指令性语句指示性语句指令性语句主要由CPU指令组成,对应实际的机器指令;(比如“Hello例”中的MOVDS,AX)指示性语句又称伪操作语句,主要由伪操作指令组成。(比如“Hello例”中的codeSEGMENT),语句的组成,汇编语言的语句可以有14个组成部分,如下所示:名字操作码/伪操作码操作数;注释带方括号的部分表示可选项。以“Hello例”中的几条语句为例:,3.2.3语句的组成名字,名字在指令性语句中,名字是一个标号,实际上就是指令的符号地址。比如“start:MOVAX,data”中的start:。并非每条指令性语句都必须有标号。但如果有了这个标号,程序中其他地方就可引用这个标号,比如执行跳转或者CALL调用。指令性语句中的标号后面通常有一个冒号。标号有三种属性:段、偏移量和类型。段属性是定义标号的程序段的段地址。偏移量表示标号所在段的起始地址到定义该标号的地址之间的字节数。标号的类型有两种:NEAR和FAR。前者可以在段内被引用,地址指针为两个字节;后者可以在其他段中被引用,地址指针为4个字节。,语句的组成名字,在指示性语句中,名字可以是变量名、段名、过程名。比如“Hello例”中“dataSEGMENT”中的data是段名,“msgDBHello,World!$”中的msg是变量名。指示性语句中的标号后面通常没有冒号。变量也有三种属性:段、偏移量和类型。段属性是变量所代表的数据所在段的段地址。偏移量表示变量所在段的起始地址与变量的地址之间的字节数。变量的类型有:BYTE、WORD、DWORD(四字节)、QWORD(八字节)和TBYTE(十字节)等,表示数据区中存取操作对象的大小。,3.2.4语句的组成操作码/伪操作码,操作码/伪操作码在汇编语言中操作码以助记符的形式存在。8086/8088CPU的助记符总共约有90多种,比如MOV、ADC等。关于所有的助记符,参见第二章指令系统。指示性语句中的DB、SEGMENT、ENDS、ASSUME、END等都是伪操作码,而不是CPU指令的助记符。它们在程序中的作用是定义变量的类型、定义段以及命令汇编程序(masm.exe)结束汇编等。它们是指示汇编程序(masm.exe)完成汇编,本身不产生对应的机器码。关于伪操作码的具体作用和使用方法,下文有专门章节讨论。,3.2.5语句的组成操作数,操作数对于CPU指令,可能有单操作数和双操作数,也可能无操作数;伪指令可能有更多个操作数。可以用作操作数的有:常数、寄存器、标号、变量和表达式。常数十进制数,如99D或99。后面加字母“D”,或者什么也不加。十六进制数,如64H,0F800H,后面加一个字母“H”;如果最高位数值不是09,前面要再加一个数字0。(以避免和寄存器名称如“AH”冲突)ASCII常数,例如A、8、cat,字符应该放在单引号中。,语句的组成操作数,寄存器8086/8088的寄存器可以用作指令的操作数。8086/8088CPU的寄存器有:8位寄存器:AH、AL、BH、BL、CH、CL、DH、DL。16位寄存器:AX、BX、CX、DX、SI、DI、BP、SP、DS、ES、SS、CS。标号标号代表一条指令的符号地址,因此可以作为转移、过程调用CALL以及循环控制LOOP等指令的操作数。比如“HELLO例”中“ENDstart”,start就是一个标号。,语句的组成操作数,变量变量是存储器中某个数据区的名字,因此在指令中可以作为存储器操作数。如“Hello例”中的:LEADX,msg其中msg就是一个在数据区定义的变量(msgDBHello,World!$)。表达式汇编语言中的表达式按其性质可以分为两种:数值表达式和地址表达式。数值表达式产生一个数值结果,只有大小,没有属性。地址表达式的结果不是一个单纯的数值,它有三种属性:段、偏移量和类型。,语句的组成操作数,构成表达式必然有运算符。表达式中常用运算符有以下几种:算术运算符,如+、-、*、/和MOD(模除)这些算术运算符可用于数值表达式,运算结果是一个数值。在地址表达式中通常只使用其中的+和两种运算符。逻辑运算符,如AND、OR、XOR和NOT逻辑运算符只用于数值表达式中对数值进行按位逻辑运算。对地址进行逻辑运算是没有意义的。不要把逻辑运算符如AND、OR、XOR和NOT等与同样名称的CPU指令相混淆。前者可对整常数进行按位逻辑运算,是在汇编时进行;后者的操作数可以是寄存器、存储器和立即数,是在程序运行时由CPU执行。比如:ANDAL,01011010B;这里的AND是指令助记符MOVAL,01011010BAND11110000B;这里的AND是逻辑运算符,语句的组成操作数,关系运算符如EQ(等于)、NE(不等)、LT(小于)、GT(大于)、LE(小于或等于)、GE(大于或等于)等。参与关系运算的必须是两个数值,或同一段中的两个存储单元地址,但运算结果只能是两个特定的数值之一。当关系不成立(假)时,结果为0;当关系成立(真)时,结果为0FFFFH(-1)。例如:MOVAX,4EQ3;关系不成立,故(AX)0MOVAX,4NE3;关系成立,故(AX)0FFFFH,语句的组成操作数,分析运算符和合成运算符如OFFSET、SEG、TYPE、SIZE和LENGTH等;合成运算符有PTR、THIS、SHORT等。分析运算符用以分析一个存储器操作数的属性,如段、偏移量或类型等。合成运算符则可以规定存储器操作数的某个属性,例如类型。OFFSET用于获取一个标号或变量的偏移地址,如:MOVSI,OFFSETDATA1是将变量DATA1的偏移地址送至SI寄存器。其效果等同于:LEASI,DATA1,语句的组成操作数,SEG用于获取标号或变量的段址,如:MOVAX,SEGARRAYMOVDS,AX是将变量ARRAY的段地址送入DS寄存器。TYPE的运算结果是一个数值,这个数值与存储器操作数类型属性的关系如下:,语句的组成操作数,TYPE运算符的例子VARDW?ARRAYDD10DUP(?)STRDBThisisatestMOVAX,TYPEVAR;(AX)2MOVBX,TYPEARRAY;(BX)4MOVCX,TYPESTR;(CX)1LENGTH如果一个变量已用重复操作符DUP说明其变量的个数,则利用LENGTH获取这个变量的个数。如果未用DUP说明,则得到的结果为1。比如上例中,LENGTHARRAY运算结果为10。,语句的组成操作数,SIZE如果一个变量已用重复操作符DUP说明,则利用SIZE运算符可得到分配给该变量的字节总数。如果未用DUP说明,则得到的结果是TYPE运算的结果。比如上例中,SIZEARRAY运算结果为10440。由此可知,SIZE的运算结果等于LENGTH的运算结果乘以TYPE的运算结果。PTR是一个合成运算符,用于指定存储器操作数的类型。比如INCBYTEPTRBXSI,指令中利用PTR运算符明确规定存储器操作数的类型为BYTE(字节),因此,本指令将一个8位存储器的内容加1。,语句的组成操作数,THIS也可以指定存储器操作数的类型。使用THIS运算符可以使标号或变量的类型具有灵活性。例如要求对同一个数据区,既可以字节作为单位,又可以字作为单位进行存取,则可以用以下语句:AREAWEQUTHISWORDAREABDB100DUP(?)上面的AREAW和AREAB代表同一个数据区,其中共有100个字节,但AREAW的类型为WORD,而AREAB的类型为BYTE。SHORT指定一个标号的类型为SHORT(短标号),即标号到引用标号的指令间的距离在-128127之间。短标号可用于无条件转移和条件转移指令中。使用短标号的指令比使用默认的近标号的指令少一个字节。,语句的组成操作数,方括号间接寻址指令的存储器操作数要在寄存器名BX、BP、SI或DI外面加上方括号,以表示存储器地址。又如,变址寻址指令的存储器操作数既要用算术运算符将SI或DI与一个位移量做运算,又要在外面加上方括号来表示存储器地址。MOVCL,BXMOVAL,SI+5段超越运算符“:”是“:”(冒号)跟在段寄存器名(DS、ES、SS或CS)之后表示段超越,用以给一个存储器操作数指定一个段属性,而不管其原来隐含的段是什么。例如:MOVAX,ES:SIHIGH和LOW获取一个数值或地址表达式的高位和低位字节。STUFFEQU0ABCDHMOVAH,HIGHSTUFF;(AH)0ABHMOVAL,LOWSTUFF;(AL)0CDH,语句的组成操作数,如果一个表达式中同时具有多个运算符,那么按照以下规则进行运算:优先级高的先运算,优先级低的后运算;同一优先级按表达式中从左到右的顺序进行运算;圆括号可提升运算优先级,圆括号内的运算符总是在其任何相邻的运算之前进行。各种运算符的优先级顺序如下页图表所示。表中同一行的运算符具有同等优先级。,语句的组成操作数,3.2.6语句的组成注释,注释和其他语言一样,汇编语言中的注释仅用于提高程序的可读性。汇编语言中的注释前面要求加上分号(;)。如果注释内容较多,超过一行,则换行以后前面还要加上分号。注释也可以从一行的最前面开始。汇编程序(masm.exe)对注释不予理会,即注释对汇编后产生的目标程序没有任何影响。,3.3伪操作指令,指示性语句中的伪操作指令,因其表示形式类似于CPU指令,故称其为“伪指令”。伪指令与CPU指令的区别:CPU指令是给CPU的指令,对应CPU的特定操作,如加法运算;而伪指令是给汇编程序(masm.exe)的指令,指示汇编程序进行操作,比如定义段、定义数据。CPU指令在汇编后产生一一对应的目标代码,伪指令不产生与之对应的目标代码。下面列出“Hello例”的汇编源码及其对应的机器码对比体会伪指令的作用。,Hello,World!的汇编源代码,Hello,World!的机器代码,Hello,World!机器代码的分析,可以看到,编译后的机器代码中,伪指令都已经不见了。原来的代码段中每条指令性语句都对应一条机器码。汇编源代码中的第一句MOVAX,data经编译后变成MOVAX,1449。这是因为编译器(masm.exe)将数据段放在1449:0000的位置。然后将DS:DX指向该位置,通过INT21的09H中断将其显示出来。,资料回顾:功能号09H的int21中断功能描述:输出一个字符串到标准输出设备上。入口参数:AH09HDS:DX待输出字符的地址说明:待显示的字符串以$作为其结束标志,Hello,World!机器代码的分析,下图使用d1449:0000显示了数据段中的内容:,Review(1),汇编语言源程序中语句的类型指令性语句由CPU指令组成指示性语句由伪指令组成汇编语言语句的组成1、名字指令性语句中的名字是一个标号指示性语句中的名字可以是变量名、段名、过程名2、操作码/伪操作码,Review(2),3、操作数常数寄存器标号变量表达式算术运算符逻辑运算符关系运算符分析运算符和合成运算符各种运算符的优先级4、注释,3.3伪操作命令,宏汇编程序MASM提供了数十种伪操作。(这里也揭示了操作码和伪操作码的区别:伪操作码随编译器的不同而不同;而操作码随CPU的不同而不同。)根据伪操作的功能,大致可以分为下列几类:,伪操作指令分类,处理器方式伪操作(了解),处理器方式伪操作用于指示汇编编译器使用何种CPU的指令系统。常用的有以下几种:.8086指示汇编程序只汇编8086/8088的指令系统。程序中若出现80286或80386的指令,则编译会出错。如果程序中不定义任何处理器方式伪操作,则汇编程序默认即是.8086方式。.386P指示汇编程序汇编8086/8088以及所有80286和80386(包括保护方式和非保护方式)的指令。,3.3.2数据定义伪指令,数据定义伪操作用于定义变量类型、给变量赋值。常用的有以下几种:数据定义伪操作的一般格式是:变量名伪操作操作数,操作数操作数可以是常数、表达式或字符串,但每项操作数的值不能超过伪操作所定义的数据类型限定的范围。,例1:DATA_BDB10,5,10HDATA_WDW100H,-4DATA_DDD0FFFBH汇编后的内存分配情况如右图所示。,例2:操作数可以是字符串,例如STRDBHELLO汇编后的情况如图:,注意下面两个定义的不同之处:DBAB;41H在低字节,42H在高字节DWAB;42H在低字节,41H在高字节,用DW定义字符串只允许包含两个字符,否则必须用DB指令;字符串的个数不超过255个;字符串必须用单引号引起来。,几点说明:,操作数?用来保留存储空间,但不存入数据。例3:ABCDB0,1,2,3,4,OK,$RSVDW?,?,?,?,?,?,?,?复制操作符DUP:重复的数据可以使用复制操作符DUP,如上面RSV亦可写成:RSVDW8DUP(?),3.3.3符号定义伪操作,符号定义伪操作用于给一个符号重新命名,或定义新的类型属性等。这里的符号可以是汇编语言中所用的变量名、标号名、过程名、记录名、寄存器名以及指令助记符等。常用的符号定义伪操作有EQU、LABELEQU格式:名字EQU表达式作用:用名字代替一个数值,或一个较长的表达式。举例:HPIXELEQU1024VPIXELEQU768SCREENEQUHPIXEL*VPIXEL,符号定义伪操作,格式:名字=表达式作用:类似EQU,区别在于“=”可以对一个名字重复定义。举例:COUNT=10MOVCX,COUNT;(CX)10COUNT=COUNT-1MOVBX,COUNT;(BX)9LABEL格式:名字LABEL表达式作用:定义标号或变量的类型。举例:AREAWLABELWORDMOVAREAW,AX;AX送AREAW的第1、2字节中,3.3.4段定义伪操作,段定义伪操作用于在汇编语言源程序中定义逻辑段。常用的段定义伪操作有SEGMENT/ENDS、ASSUMESEGMENT/ENDS格式:段名SEGMENT定位类型组合类型类别作用:定义一个逻辑段举例:STACKSEGMENTDB100DUP(?)STACKENDS“定位类型”告诉编译器如何确定逻辑段的边界在存储器中的位置,即对齐方式。有PARA、BYTE、WORD和PAGE四种。“组合类型”告诉编译器在装入程序时各个逻辑段如何组合。“类别”的作用是在连接时决定各逻辑段的装入顺序。,段定义伪操作,ASSUME格式:ASSUME段寄存器:段名,段寄存器:段名,说明:将某一个段寄存器和某一个逻辑段进行关联。“段名”可以是曾用SEGMENT操作符定义过的一个段名,或是在一个标号或变量前面加上SEG构成的表达式,还可以是关键字NOTHING。需要注意的是,ASSUME仅仅是通知编译器有关段寄存器和逻辑段的关系,并没有为段寄存器赋予实际的初值。举例:ASSUMECS:CODE,DS:DATA1,SS:STACKASSUMEDS:SEGAREA1ASSUMEES:NOTHING;取消前面ASSUME对ES的设置,3.3.5过程定义伪操作,过程定义伪操作命令为PROC/ENDP。PROC/ENDP格式:过程名PROCNEAR/FARRET过程名ENDP作用:定义一个过程,赋予过程一个名字,并指出过程的类型,并指出该过程的类型是NEAR或FAR。如果没有特别指明,则认为过程类型是NEAR。伪操作码ENDP标志过程定义结束。注意:PROC和ENDP必须成对出现。,过程的类型有两种:NEAR(默认类型)表示段内调用;(SP)(SP-2);(SP+1):(SP)(IP);FAR表示段间调用。调用一个过程的格式为:CALL,3.3.6模块定义与连接伪操作(了解),在编写规模较大的汇编语言程序时,可将程序划分成几个独立的源程序模块,分别进行汇编,最后统一连接。各个模块之间可以相互进行符号访问。命令为NAME、END、PUBLIC和EXTRN。NAME格式:Name模块名作用:指定源文件汇编后的目标文件名称END格式:END标号作用:表示源程序到此结束,对于END后面语句不予理会,模块定义与连接伪操作(了解),PUBLIC格式:PUBLIC符号,作用:说明本模块中的某些符号是公共的,即这些符号可以供将被连接在一起的其他模块使用说明:“符号”可以是本模块中定义的变量、标号或数值的名字,包括用PROC定义的过程名等。EXTRN格式:EXTRN名字:类型,作用:说明本模块中所用的某些符号是外部的,即这些符号在将被连接在一起的其他模块中定义(定义这些符号的模块中还必须用PUBLIC说明)。,3.3.7宏处理伪操作,如果在程序中需要多次使用一个程序段,可将其定义为宏。每次需要时,直接进行调用,称为宏调用。【利用过程(PROC)可以实现类似功能。区别在于:宏在编译时就插入每个宏调用处(这称为“宏扩展”);而过程是在执行时进行跳转。过程具有更优的空间效率,而宏则具有更优的时间效率。】MACRO/ENDM格式:宏指令名MACRO;(宏定义体)ENDM作用:将宏指令名定义为宏定义体中包含的程序段。,宏处理伪操作,宏定义伪操作允许带参数,从而具有更强的通用性。例:定义一个宏,用于两个压缩的BCD数相加,结果放在第一个操作数中。DECADDMACROOPR1,OPR2MOVAL,OPR1ADDAL,OPR2DAAMOVOPR1,ALENDM下面使用debug来观察该例中“宏扩展”是如何进行的:,源文件,反汇编并执行观察结果,3.4DOS和BIOS调用(了解),DOS和BIOS为用户提供了两组系统服务程序。BIOS是IBMPC的基本IO系统,包括系统测试程序、初始化引导程序、一部分中断矢量装入程序以及部分外设的服务程序。这些程序都固化在主板上的ROM中。DOS是IBMPC的操作系统,负责管理系统的所有资源。其中包括大量可供用户调用的服务程序。DOS和BIOS调用不是使用CALL命令,而采用软中断指令INTn。,DOS和BIOS调用,用户程序控制PC机硬件的方式使用高级语言提供的功能控制硬件调用方便,但灵活性较低、速度较慢。使用DOS提供的程序控制硬件调用较为方便,程序可移植性好,编程简单。使用BIOS提供的程序控制硬件这种控制比较低层,因而可移植性差,但效率更高。直接访问硬件要求用户对硬件非常熟悉。此种方式只用于两种情况:为了获得高效率,或是为了获得DOS和BIOS不支持的功能。,DOS调用,8086指令系统中,有一条软中断指令INTn。当n=51FH时,调用BIOS服务程序;当n=203FH时,调用DOS服务程序。下表列出了部分DOS软中断的功能:,INT21H调用,其中INT21H是一个具有完整功能的服务程序,一般称之为DOS系统功能调用。是最常用的DOS中断。INT21H中断具有近90个子功能,大致分为4个方面:设备管理、目录管理、文件管理和其他。系统功能调用(INT21H)的使用步骤如下:置系统功能号n(放入AH)置入口参数执行INT21H分析出口参数,INT21H调用示例,例:从键盘读入一个字符,判断是Y还是N,以执行对应操作。,资料:功能号01H的int21H中断功能描述:从标准输入设备(如:键盘)读入一个字符功能号:AH01H,过滤掉控制字符,并回显出口参数:AL输入字符的ASCII码,KEY:MOVAH,1INT21H;执行调用CMPAL,YJEYESCMPAL,NJENOJMPKEY;输入其他字符,退回继续等待输入YES:NO:,BIOS调用,下面列出了部分BIOS中断:,关于BIOS中断的所有中断号内容(从05H1FH),参见书附录3.3,Review,BIOS调用,BIOS调用的使用步骤如下:置系统功能号n(放入AH)置入口参数执行INTn分析出口参数举键盘输入服务(INT16H)为例。其主要功能有三个,分别用于读键盘、读扩展键盘和读取功能键,分别对应功能号0、1、2(AH0、1、2)。下面一段程序的功能是:按下F1和F2键,分别执行两段不同的程序,按其他键则转至错误处理。,INT16H调用示例,资料:功能号00H的int16H中断功能描述:从键盘读入字符入口参数:AH00H出口参数:AH键盘的扫描码AL字符的ASCII码,MOVAH,0INT16H;执行调用CMPAL,0JNEERROR;若为字符键,转ERRORCMPAH,3BH;F1键码为3BHJETT1CMPAH,3CH;F2键码为3CHJETT2JMPERRTT1:;处理F1键功能TT2:;处理F2键功能ERR:,资料:键码又称键盘扫描码,F1键码为3BHF2键码为3CH,INT10H调用示例,从上页的例子中,可以看出,同样的功能,往往既可以用BIOS中断调用来实现,也可以用DOS中断调用来实现。比如磁盘服务、键盘服务、显示字符等。差别在于:BIOS中断调用往往功能更强大、控制更灵活。例:INT10H功能号09H,“在当前光标位置显示字符”。,MOVAH,9;显示字符MOVAL,a;字符MOVBL,0Ch;0表示背景黑色,0Ch表示字符红色MOVBH,0;第0页MOVCX,8;字符重复个数INT10h,INT10H调用示例运行结果,提示:由于程序运行在“虚拟”的8086模式下,在操作硬件时跟纯DOS仍存在一定差异。如果程序直接双击运行时结果跟预期不符,(比如窗口一闪而过)可使用debug加载然后输入g运行。,汇编语言设计举例,字符串查找内存中已经存有一张表,要求从键盘上输入一个字符串,然后在表中查找该字符串,如有,则在屏幕上显示“OK!”;如果没有,则显示“NO!”;若输入字符串长度超过内存中表的长度,则显示“Wrong!Thestringistoolong!”逻辑分析:查找可以分两步进行,先在表中搜索字符串的第一个字符,如有,再比较字符串的其他字符是否一致。功能可行性分析:在屏幕上显示字符串可以使用功能号09H的21号中断;从键盘上接收字符串可以使用功能号0AH的21号中断。,教材P213,流程图,显示提示符,从键盘接收提示符,字符串首址送SI,表首址送DI字符串长度送BX,表长度送CX,表长=串长,搜索、匹配等工作,开始,返回,显示“串太长”,具体见教材P214,资料1:功能号09H的int21H中断,功能描述:显示字符串(串尾字符为$,但不显示)入口参数:AH09HDS:DX被显示字符串的首地址出口参数:无,dataSEGMENTmsgDBHello,World!$dataENDScodeSEGMENTASSUMECS:code,DS:dataMAINPROCNEARstart:MOVAX,dataMOVDS,AXLEADX,msgMOVAH,9hINT21hMOVAH,4ChINT21hMAINENDPcodeENDSENDstart,例如:,资料2:功能号0AH的int21H中断,功能描述:从标准输入设备(如:键盘)读入一个字符串,遇到“回车键”结束输入。入口参数:AH0AHDS:DX存放输入字符的起始地址接受输入字符串缓冲区的定义说明:1、第一个字节为缓冲区的最大容量;2、第二个字节为实际输入的字符数(不包括回车键);3、从第三个字节开始存放实际输入的字符串;4、字符串以回车键结束,回车符是接受的最后一个字符;5、若输入的字符数超过缓冲区的最大容量,则多出的部分被丢弃,直到输入“回车”键才结束输入。例如:BUFFDB80,?,80DUP(?);最多接受80个字符(含回车符)出口参数:无,源码分析1,DATASEGMENTTABLEDBABCDEFGHIJKLMNOPQRSTUVWXYZSTR1DBPleaseenterastring:,0DH,0AH,$STR2DBWrong!Thestringistoolong!$STR3DBNo!$STR4DBOK!$BUFFERDB40DB?DB40DUP(?)TAB_LENEQU26DATAENDSSTACKSEGMENTSTACKDB100DUP(?)STACKENDS,堆栈段定义,数据段定义,源码分析2,CODESEGMENTASSUMECS:CODE,DS:DATA,ES:DATA,SS:STACKSEARCHPROCFARSTART:MOVAX,DATAMOVDS,AXMOVES,AXLEADX,STR1;MOVAH,09;INT21H;,显示提示符,源码分析3,LEADX,BUFFER;参见“0AH号系统调用”资料MOVAH,0AHINT21H;从键盘接收字符串MOVSI,DX;(SI)串首址INCSIMOVBL,SI;参阅“0AH号系统调用”资料MOVBH,0;(BX)实际输入字符串长度INCSI;将SI指向输入字符串首字母LEADI,TABLE;(DI)表首址MOVCX,TAB_LEN;(CX)表长度CMPCX,BX;表长=串长?JNCGOON;是,转GOONLEADX,STR2;JMPEXIT;否则显示串太长,源码分析4,GOON:CLDMOVAL,SI;(AL)字符串第一个字符SCAN:REPNZSCASB;在表中搜索第一个字符JZMATCH;找到,转MATCHERROR:LEADX,STR3;否则,显示NO!JMPEXITMATCH:INCCXCMPCX,BX;剩余表长=串长?JCERROR;否,显示NO!PUSHCXPUSHSIPUSHDIMOVCX,BXDECDIREPZCMPSB;比较串中其余字符,源码分析5,POPDIPOPSIPOPCXJZFOUND;找到字符串,转FOUNDJCXZERROR;否则,若全表搜索完,显示No!JMPSCAN;全表未搜索完,转SCANFOUND:DECDI;(DI)字符串偏移地址LEADX,STR4;显示OK!EXIT:MOVAH,09HINT21H;显示退出字符串MOVAH,4CHINT21HSEARCHENDPCODEENDSENDSTART,如何阅读汇编代码(供参考),对于较长的汇编代码,可通过“分块法”阅读。也就是根据记忆中的既有模板,将源码拆成多个“功能块”。这要求对一些基本模板要有一定印象。(比如:功能号09H的INT21调用模板;查找字符串、对比字符串的模板。一些常用功能的实现往往有其相对固定的套路,在源码中能较容易看出。大家可以自己试着总结。)同时可以借助于一些标记,比如“INTxx”往往标记着一个功能块的结束,那么可以循着往上寻找出一个完整的功能块;“标号”也可以帮助拆分功能块,尤其是书写优秀的源码,往往采用有意义、一目了然的标号。总之,阅读汇编源码要注意积累。在阅读别人源码时要加以留心并注意总结,逐步提升自己水平。,汇编语言程序设计小节寻址方式存储器操作数的寻址方式;指令系统8088/8086指令系统;汇编语言掌握各种“格式”、规则等;汇编高手勇于实践,触类旁通!,题2-11、题2-12、题2-13题3-1、题3-4、题3-5、题3-7,作业,
展开阅读全文