《汇编语言程序设计及上机指导第6章结构化程序设计.ppt》由会员分享,可在线阅读,更多相关《汇编语言程序设计及上机指导第6章结构化程序设计.ppt(35页珍藏版)》请在三一办公上搜索。
1、第6章 结构化程序设计,【本章提要】本章针对Intel系列微处理器的指令系统,首先介绍利用宏汇编工具MASM6.X实现结构化程序设计的方法,然后介绍模块化程序设计和宏结构程序设计,最后叙述汇编语言源程序的汇编、链接和运行调试的过程。【学习目标】熟练掌握顺序、分支、循环结构程序设计方法 熟练掌握子程序及宏机构程序设计方法 掌握利用宏汇编工具MASM6.X的专用伪指令实现程序结构控制 熟练掌握汇编与调试工具的应用,2023/11/3,6.1 分支和循环结构程序设计,1.分支程序设计一、用转移指令实现假如要把连续存放在内存变量名DAT中的三个数按递减次序排列。,2023/11/3,二、用MASM6.
2、X伪指令实现MASM6.X引入了条件控制伪指令,格式:.IF 条件表达式;条件为真(非0),执行分支体 分支体.ELSEIF 条件表达式 分支体;前面IF条件为假,并且当前ELSEIF条件为真执行分支体.ELSE;前面IF条件为假执行分支体 分支体.ENDIF;分支结束例如:.IF AX0 MOV BX,1;如果AX0,则将1存入BX.ELSEIF AX=0 MOV BX,0;如果AX=0,则将0存入BX.ELSE MOV BX,-1;如果AX0,则将-1存入BX.ENDIF,2023/11/3,条件表达式中的操作符及功能,2023/11/3,&的优先级高于|和!位测试运算符的用法为:“数值表
3、达式&数值”,相当于执行TEST指令和相应的条件转移指令。以下为采用&运算符的分支结构程序片段,功能为:若AX内容为奇数,则把全1送BX;若AX内容为偶数,则把0送入BX。.IF AX&1;相当于TEST AX,1指令,也设置标志位,若ZF=0则执行第一分支 MOV BX,0FFFFH;第一分支.ELSE MOV BX,0;第二分支.ENDIF,2023/11/3,【例】用条件控制伪指令实现有实根判别的程序,.MODEL SMALL.386.STACK.DATAA SBYTE?B SBYTE?C SBYTE?SIGN BYTE?.CODE.STARTUPMOV AL,BIMUL ALMOV B
4、X,AX;BX中为B的平方MOV AL,AIMUL CMOV CX,4IMUL CX;AX中为4AC.IF SWORD PTR BX=AX;比较B的平方和4AC的大小 MOV SIGN,1;条件成立,SIGN得到1.ELSE MOV SIGN,0;条件不成立,SIGN得到0.ENDIF.EXIT 0END,2023/11/3,6.1.2 循环程序设计,一、用循环指令实现循环结构例:计算l20的整数之和,并将结果存入字变量SUM中.MODEL SMALL.STACK.DATA SUM DW?.CODE.STARTUPXOR AX,AX;被加数AX清零MOV CX,20AGAIN:ADD AX,C
5、X;从20,19,2,1倒序累加到AXLOOP AGAIN;每循环一遍,CX自动减1MOV SUM,AX;将累加和送入SUM单元.EXIT 0END,2023/11/3,二、用MASM 6.x循环控制伪指令实现循环结构(1).WHILE结构的循环控制伪指令的格式为:.WHILE 条件表达式;条件为真,执行循环体 循环体.ENDW;循环体结束例:求5的阶乘12345,并送入指定单元的程序片段可以编写为:MOV AX,1;积AX初值设为1 MOV CX,2.WHILE CL=5;该循环总共执行4遍 MUL CL;从1,2,3,4,5累乘 INC CL.ENDW MOV MEMWORD,AX;将乘积
6、送入指定单元(2).REPEAT结构的循环控制伪指令的格式为:.REPEAT;重复执行循环体 循环体.UNTIL 条件表达式;直到条件为真结束循环如果要实现1100之间偶数求和,循环体程序片段可以编写为;MOV AX,0 MOV CX,100.REPEAT;是先执行后判断的结构 ADD AX,CX SUB CX,2.UNTIL CX=0;直到CX内容为0结束,AX内容为偶数之和,2023/11/3,(3).REPEAT结构还有一种格式:.REPEAT;重复执行循环体 循环体.UNTILCXZ 条件表达式;cxcx-1,直到cx=0或条件;为真结束不带表达式的.repeat/.untilcxz伪
7、指令将汇编成一条loop指令,即重复执行直到cx减1后cx=0;带有表达式的.repeat/.untilcxz伪指令的循环结束条件是cx减l后等于0或指定的条件为真。.untilcxz伪指令的表达式只能是比较寄存器与寄存器、寄存器与常数,以及存储单元与常数相等()或不等(!)。(4).BREAK伪指令和.CONTINUE伪指令.BREAK的功能是无条件退出当前循环;.CONTINUE的功能是转向循环体的开始,直接进入下一轮循环,2023/11/3,【例】设ARRAY 是100字节的字符数组,分别统计出其中大写、小写字符的个数,并保存到相应单元,同时将所有字母单元内容改为数值55H,对0到9的阿
8、拉伯数字不统计,也不修改,遇到其他字符则推出循环。程序如下:.MODEL SMALL.STACK.DATAARRAY DB A,A,4,B,G,R,3,5;总共不超过100个UP_ALP DB 0;大写字母个数,初值为0DOWN_ALP DB 0;小写字母个数,初值为0.CODE.STARTUPMOV BX,0.WHILE BX=41H&ARRAYBX=61H&ARRAYBX=30H&ARRAYBX=39H;阿拉伯数字 INC BX.CONTINUE.ELSE;其他字符,结束循环.BREAK.ENDIF MOV ARRAYBX,55H;大小写字母单元都该为55H INC BX.ENDW.EXI
9、T 0END,2023/11/3,6.1.3 用中断指令实现简单输入输出(1)从键盘读入一个字符 功能号:1 入口参数:无 出口参数:AL输人字符的ASCII码功能:等待从键盘读入一个字符,将字符的ASCII码送给AL,同时将该字符显示在屏幕上。调用方法:MOV AH,l;AH中存放的是功能号 INT 21H说明:在输入一个字符后,不需要键入回车。若只键入回车,则出口参数AL得到的是回车符的ASCII码0DH。(2)显示一个字符功能号:2 入口参数:DL要显示字符的ASCII码出口参数:无 功能:在当前光标位置显示DL中的字符,然后光标右移。调用方法示例:下列指令序列用来显示字符AMOV DL
10、,AMOV AH,2INT 2lH,2023/11/3,功能号;9入口参数;DS:DX欲显示的字符串在内存的首地址。字符串必须以$作为结束标志,$不属于被显示的字符串。出口参数:无功能:在当前光标位置,显示由DS:DX所指的、以$为结束标志的字符串,然后光标右移。调用方法示例:STRING DB Hello world!,下列指令序列用来显示String中的字符串Hello world!。MOV AX,SEG STRING MOV DS,AXLEA DX,STRINGMOV AH,9INT 21H,(3)显示一个字符串,2023/11/3,功能号:0AH入口参数:DS:DX输人缓冲区的首地址输
11、入缓冲区格式:第0个字节给出输入缓冲区最多能容纳的字符个数(1255,包括回车符),由应用程序设置;第1个字节将存放实际输人的字符个数(不包括回车符),由系统在读入字符串后自动设置;从第2个字节开始存放实际输入的字符串,最后为回车符的ASCII码0DH。出口参数;无功能:从键盘读入一个字符串,存入由DS:DX所指的输入缓冲区。说明:在输入字符串后,必须以回车结束。当输人的字符数达到了输入缓冲区所能容纳的字符个数减l时,随后的输入将不被系统接收,且响铃警告。调用方法示例:BUF DB 80;定义输入缓冲区,最多容纳79个字符与1个回车符 DB?;存放实际输入的字符个数,由系统自动设置 DB 80
12、 DUP(?);存放实际输入的字符串下列指令序列将从键盘读人字符串,并存入输入缓冲区BUF中 MOV AX,SEG BUF MOV DS,AX MOV DX,OFFSET BUF MOV AH,0AH INT 21H,(4)从键盘读入一个字符串,2023/11/3,一、过程设计在MASM 6.X中,带有参数的过程定义伪指令PROC格式如下:过程名 PROC 调用距离语言类型作用范围(起始参数)USES寄存器列表,参数:类型,参数:类型 LOCAL 参数表;汇编语言语句过程名 ENDP其中,过程所具有的各个选项参数如下:过程名:表示该过程名称,应该是遵循相应语言类型的标识符。调用距离:可以是NE
13、AR或FAR,表示该过程是近或远调用。简化段格式中,默认值由MODEL语句选择的存储模式决定。语言类型:可以是任何有效的语言类型,确定该过程采用的命名约定和调用约定;语言类型还可以由.MODEL伪指令指定。作用范围:可以是PUBLIC,PRIVATE,EXPORT,表示该过程是否对其他模块可见。默认是PUBLIC,表示其他模块可见;PRIVATE表示对外不可见;EXPORT隐含有 PUBLIC和FAR,表示该过程应该放置在导出表中。起始参数:采用这个格式的PROC伪指令,汇编系统将自动创建过程的起始代码和收尾代码,用于传递堆栈参数以及清除堆栈等。起始参数表 示传送给起始代码的参数;它必须使用尖
14、括号“”括起来,多个参数用逗号分隔。,6.2 子程序设计,2023/11/3,寄存器列表:指通用寄存器名,用空格分隔多个寄存器。只要利用“USES寄存器列表”罗列该过程中需要保存与恢复的寄存器,汇编系统将自动在起始代码产生相应的入栈指令,并对应在收尾代码产生出栈指令。参数:类型;表示该过程使用的形式参数及其类型。在16位段中,默认的类型是字WORD,在32位段中默认的类型是双字DWORD。参数类型可以是任何MASM有效的类型或PTR(表示地址指针);在C,SYSCALL,STDCALL 语言类型中,参数类型还可以是VARARG,它表示长度可变的参数。如果过程使用局部变量,紧接着过程定义伪指令P
15、ROC,可以采用一条或多条LOCAL伪指令说明。它的格式如下:LOCAL 变量名 个数:类型,其中,可选的“个数”表示同样类型数据的个数,类似数组元素的个数。在l 6位段中,默认的类型是字WORD,在32位段中默认的类型是双字DWORD。使用LOCAL伪指令说明局部变量后,汇编系统将自动利用堆栈存放该变量,其方法与高级语言的方法一样。,2023/11/3,PROTO是过程声明伪指令,用于事先声明过程的结构。它的格式如下:过程名 PROTO 调用距离 语言类型,参数:类型 语句中的各个项必须与相应过程定义伪指令PROC的各个项一致。使用PROTO伪指令声明过程之后,汇编系统将进行类型检测,才可以
16、使用INVOKE调用过程。与PROTO配合使用的过程调用伪指令是INVOKE,它的格式如下:INVOKE 过程名,参数 它自动创建调用过程所需要的代码序列,调用前将参数压入堆栈,调用后平衡堆栈。其中“参数”表示通过堆栈将传递给过程的实在参数,可以是数值表达式、寄存器、ADDR标号。“ADDR标号”传送的是标号的地址(如果是双字DWORD类型则是段地址和偏移地址,如果是字WORD类型则是偏移地址)。,2023/11/3,例:.MODEL SMALL ARRAYSUM PROTO C,:WORD,:WORD;声明过程.STACK 100.DATA COUNT EQU 5;数组的元素个数 ARRAY
17、 DB 2H,60,10H,13H,5;数组 RESULT DB?;和.CODE.STARTUP INVOKE ARRAYSUM,COUNT,OFFSET ARRAY;调用过程 MOV RESULT,AL;保存和.EXIT 0;计算字节和的过程,入口参数:ARRAYCOUNT数组的元素个数,;ARRAYADDR数组的偏移地址,出口参数:AL和 ARRAYSUM PROC C USES BX CX,ARRAYCOUNT:WORD,ARRAYADDR:WORD MOV BX,ARRAYADDR;数组的偏移地址送BX MOV CX,ARRAYCOUNT;数组的元素个数送CX XOR AL,AL SU
18、MD:ADD AL,BX;求和:AL AL十DS:BX INC BX LOOP SUMD RET ARRAYSUM ENDP END,2023/11/3,可以把不同的过程或功能模块放在不同的源文件中,分别编辑、汇编和调试,最后把各模块连接成一个可执行文件。(1)EXTRN伪指令格式一:EXTRN 过程名 属性:声明当前程序将要调用的存在于当前文件之外的过程名,调用属性可以是NEAR或FAR,默认的属性为NEAR,当模块规模比较大时可定义为FAR。格式二:EXTRN 变量名 属性:声明当前程序将要用到的,但却是在其它文件中用PUBLIC语句定义的公共变量,属性可以是BYTE、WORD或DWORD
19、等。(2)PUBLIC伪指令格式:PUBLIC 变量名表/过程名表:定义当前文件中的变量名或过程名是可以被其它模块中使用的公共变量或者过程。,二、多模块编程,2023/11/3,【例6.7】MAIN.ASM,EXTRN SUBPROG1:FAR;定义远调用的外部的过程名SUBPROG1EXTRN SUBPROG2:FAR;定义远调用的外部的过程名SUBPROG2PUBLIC VALUE1,VALUE2,SUM,PRODUCT;声明4个全局变量.MODEL SMALL.STACK 64.DATAVALUE1 DW 2050VALUE2 DW 500SUM DW 2 DUP(?)PRODUCT D
20、W 2 DUP(?).CODE.STARTUPCALL SUBPROG1;调用其他模块中的过程SUBPROG1 实现相加运算CALL SUBPROG2;调用其他模块中的过程SUBPROG2 实现相乘运算.EXIT 0 END,2023/11/3,子模块1:SUB1.ASM,EXTRN VALUE1:WORD;声明3个被用到的变量及类型 EXTRN VALUE2:WORD EXTRN SUM:WORD PUBLIC SUBPROG1;声明SUBPROG1是可被其他模块调用的过程.MODEL SMALL.CODESUBPROG1 PROC FAR SUB BX,BX;实现BX及CF的清零 MOV
21、AX,VALUE1 MOV DX,VALUE2 ADD AX,X;把VALUE1和VALUE2相加 ADC BX,00;把进位放在BX中 MOV SUM,AX;16位和存放在SUM中 MOV SUM+2,BX;进位存放在SUM的高字 RETSUBPROG1 ENDP END,2023/11/3,子模块2:SUB2.ASM,EXTRN VALUE1:WORD;声明3个被用到的变量及类型 EXTRN VALUE2:WORD EXTRN PRODUCT:WORD PUBLIC SUBPROG2;声明它是可被其他模块调用的过程.MODEL SMALL.CODESUBPROG2 PROC FAR MOV
22、 AX,VALUE1 MOV CX,VALUE2 MUL CX;实现VALUE1 和VALUE2相乘 MOV PRODUCT,AX;积的低16位存入PRODUCT MOV PRODUCT+2,DX;积的高16位存入PRODUCT的高字SUBPROG2 ENDP END;模块结束,2023/11/3,上述3个文件分别汇编生成各自的目标程序(.obj)文件之后,就可以把他们连接到一起形成一个可执行文件(.exe)了。连接时,LINK程序根据自动各模块中用PUBLIC和EXTRN伪指令声明的变量及过程进行匹配。连接可以用的DOS命令为:LINK MAIN.OBJ+SUB1.OBJ+SUB2.OBJ
23、注意:各个模块的文件名与模块内部的过程名是没有关联的,模块之间的相互调用和返回都是通过过程名来实现的,与模块的文件名无关。,2023/11/3,一、宏定义宏定义由MACRO伪指令和ENDM伪指令定义,其语句格式如下:宏指令名 MACRO 宏体 ENDM下例是定义有一个参数的宏DISPCHAR,在屏幕显示参数所对应的字符:DISPCHAR MACRO DISCHAR MOV DL,DISCHAR MOV AH,2H INT 21HENDM二、宏引用和宏扩展 如有DISPCHAR 42H宏引用,则汇编程序会自动将该宏扩展为如下语句序列:MOV DL,42H;显示B MOV AH,2H INT 21
24、H注意:宏定义本身不生成任何目标代码,宏引用语句也不生成目标代码,它仅表示宏引用出现的位置,宏扩展时才生成代码。,6.3 宏结构程序设计,2023/11/3,:宏注释符,用于表示在宏定义中的注释。采用这个符号的注释,在宏展开时不出现。例:对8086的4条移位指令:shlshrsalsar,现在我们用宏指令movereg替代。这时,需要用参数表示助记符:movereg MACRO X,Y,Z;PUSH CX MOV CL,Y S&X&Z,CL POP CX ENDM,该宏调用在汇编后的宏展开为:PUSH CX MOV CL,3;用实参3代替形参Y SHL AX,CL;用实参HL代替形参Z 并;与
25、前面的S连接,用实参AX代替形参X POP CX,三、几个宏操作符的使用,2023/11/3,为了方便09H号DOS调用,字符串的定义可以采用如下宏:DISPSTRING MACRO STR DB 实参个数少于形参,则多余的形参为空值.,2023/11/3,1)宏引用语句由宏汇编程序识别,并完成相应的处理;而调用过程的CALL语句是在执行程序时完成的。2)源程序在汇编过程中,要将宏指令所代替的程序段汇编成相应的机器代码,并插入到源程序的目标代码中。由于每引用一次宏指令,就要插入一次,因此宏引用不能缩短目标代码的长度。但是,被调用的过程经汇编后的机器代码是与主程序分开并独立存在的,其目标代码在存
26、储器中只需保留一份。因此,采用过程调用能有效地缩短目标代码长度,即节省内存空间。3)过程调用时需要保护程序的断点和现场,待过程执行完毕后还要恢复现场和断点,这些操作需要耗费CPU的时间,而宏引用不需要进行这些操作。因此,过程调用节省存储空间,但降低程序的执行速度;而宏指令及其引用不能节省存储空间,但能有较快的执行速度。,四、宏指令与过程的比较,2023/11/3,6.4 汇编程序和汇编处理过程,一、源程序的汇编1行汇编:按行对汇编语言源程序逐条汇编 DEBUG.EXE中的A命令就属于这种汇编类型例:C DEBUG-A 0AF5:0100 MOV AH,0080 0AF5:0103 ADD AH
27、,10 0AF5:0105 MOV 0081,AH 0AF5:0108 HLT 0AF5:0109 C,2023/11/3,2宏汇编,首先对扩展名为.ASM的汇编语言源程序进行汇编,产生扩展名为.OBJ的可重定位目标代码文件,然后用连接程序LINK连接一个或多个.OBJ模块(包括库文件),生成一个扩展名为.EXE的可执行目标文件,2023/11/3,MASM6.X包含了许多文件,最常用的文件如下:ML.EXE 汇编器LINK.EXE 连接器CV.EXE 调试器Code View(1)汇编器ML.EXE(Masm and Link)ML 可以自动调用LINK,实现对程序的汇编和连接。设源文件为M
28、YPRG.ASM,汇编的基本命令格式为:ML/c MYPRG.ASM其中,源文件MYPRG的扩展名.ASM不能省略。若程序无语法错误,则汇编后将生成MYPRG.OBJ文件。此外若不带参数/c,直接使用命令:ML MYPRG.ASM则ML将自动调用连接器LINK进行连接,生成MYPRG.OBJ与MYPRG.EXE,这样就不需要单独使用LINK命令。,MASM6.X介绍,2023/11/3,ML允许的选项,ML允许的选项有很多,常用选项如下:/AT 生成COM文件/c 只汇编,不连接/Fe 可执行文件名 指定生成的可执行文件名/Fl 列表文件名 产生列表文件(LST),缺省与源文件同名/Fm 映象
29、文件名 产生映象文件(MAP),缺省与源 文件同名/Fo 目标文件名 指定生成的目标文件名/I 包含路径名 指定include文件的路径名 ML除了产生目标文件与可执行文件外,还可以根据需要生成些其他文件,如列表文件(.Lst)与映象文件(.map)。例如命令:ML Fl/Fm myprg.asm 除了能生成myprg.obj与myprg.exe之外,还生成列表文件myprg.lst与映象文件myprg.map。,2023/11/3,(2)列表文件:是一个文本文件,其内容包括两部分:第一部分,从左到右依次列出数据或指令在段内的偏移地址、机器代码和源程序。若程序中有语法错误,则列出错误信息。第二
30、部分,列出了程序中定义的所有标识符的信息,比如段的名称、大小与长度,变量与标号的名称、类型与偏移地址等。(3)映象文件是一个文本文件,主要列出每个段的内存分配情况。其中给出了每个段的起点、终点、长度、段名、类别以及程序执行的起始地址等。,2023/11/3,2023/11/3,关于DEBUG参数的说明:进制:在DEBUG中输入或显示的数据都是十六进制形式;分隔:命令和参数、参数和参数之间要用空格、逗号或制表符等分隔;地址:用“段值:偏移量”的形式来表示地址,也可用段寄存器来代表“段值”;例如:1000:0,ds:10,cs:30等;范围:用来表示地址范围,从哪个地址开始,到哪个地址结束。有两种
31、表示方式:地址 地址前者表示起始地址,要用“段值:偏移量”来表达,后者表示终止地址,只用“偏移量”来表示;地址 长度前者表示起始地址,要用“段值:偏移量”来表达,后者表示该区域的大小,用字母L开头的数值来表示例如:100:50 80;段值为100,偏移量从50到80的内存区域,100:50 L80;段值为100,偏移量从50开始的80个字节区域。端口地址:二位十六进制数值字节值:二位十六进制数值字节值表:由若干个字节值组成,也可以是用引号括起来的字符串,2023/11/3,DEBUG应用示例:,【例】启动DEBUG,并装入test.exe文件(假设该文件已存在)。方法1:方法2:debug t
32、est.exe debug-n test.exe-l【例】比较以DS为段值,偏移量从10到50的内存区域与从地址100:20开始的内存区域。-C DS:10 50 100:20 或-C DS:10 L41 100:20【例】显示以DS为段值,偏移量从10到50内存区域的单元内容,然后用ABC来填充它。-D DS:10 60 或-D DS:10 L51-F DS:10 00 ABC【例】显示十六进制1234与5678之和、差。-H 1234 5678【例】把数据段区域DS:0-50H内的内容传送给从附加段ES:20H开始的内存中。-M DS:0 50 ES:20【例】在数据段区域DS:0-80内
33、查找是否有字符串CIH。-S DS:0 80 CIH,2023/11/3,【例】将AX寄存器的值设置为1234H,并显示当前各寄存器的内容-R AX;该行为输入的命令AX 0000;该行为系统显示的AX寄存器原来的值是0:1234;冒号为系统的提示符,1234为当前输入的新值-R;输入R命令并回车,以下显示为当前各寄存器的内容AX=1234 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000DS=0AF5 ES=0AF5 SS=0AF5 CS=0AF5 IP=0100 NV UP EI PL NZ NA PO NC可以在第二行右半部看到FLAG寄存器中的标志含义:,