1、教学重点,在掌握基本的汇编语言程序设计方法之后,进一步学习如何提高编程效率的各种实用方法:高级语言特性宏结构模块化,1 高级语言特性,MASM 6.0引入高级语言的程序设计特性条件控制伪指令.IF .ELSE .ENDIF循环控制伪指令.WHILE .ENDW .REPEAT .UNTIL过程声明和过程调用伪指令.PROTO .INVOKE,要调用带参数过程定义的过程,不应采用CALL指令,因为比较烦琐应该采用过程调用伪指令INVOKE使用INVOKE伪指令的前提是需要用PROTO伪指令对过程进行声明,1.3 过程声明和过程调用伪指令,过程名PROC调用距离 语言类型 作用范围 USES 寄存
2、器列表, 参数:类型LOCAL 参数表;汇编语言语句过程名ENDP,过程声明伪指令:用于事先声明过程的结构过程名PROTO 调用距离 语言类型, 参数:类型过程调用伪指令INVOKE 过程名,参数,.,如何调用,;汇编语言程序:lt503.asm.model smallchecksumd PROTO c,:word,:word;声明过程.stack.dataarraydb 12h,25h,0f0h,0a3h,3db 68h,71h,0cah,0ffh,90hcountequ $-array;数组的元素个数resultdb ?;校验和.code.startupINVOKE checksumd,c
3、ount,offset array;调用过程mov result,al;保存校验和.exit 0,例31/2,列表文件,checksumd PROC c USES bx cx,countp:word,arrayp:wordmov bx,arrayp;BX数组的偏移地址mov cx,countp;CX数组的元素个数xor al,alsumd:add al,bx;求和:ALAL+DS:BXinc bxloop sumdretchecksumd endpend,例32/2,列表文件,;lt503.asm的列表文件(lt503.lst).INVOKE checksumd,count,offset ar
4、ray *mov ax,word ptr OFFSET array *push ax *mov ax,+000Ah *push ax *call checksumd *add sp,04hmov result,al.,例31/2,checksumd PROC c USES bx cx,countp:word,arrayp:word *push bp;起始代码 *mov bp,sp *push bx;保护bx和cx *push cxmov bx,arrayp;arrayp=BP+6mov cx,countp;cuontp=BP+4.ret *pop cx;结尾代码 *pop bx *pop bp
5、 *ret 0000hchecksumc endp,例32/2,2 宏结构程序设计,宏汇编重复汇编条件汇编统称宏结构,宏(Macro)是汇编语言的一个特点,它是与子程序类似又独具特色的另一种简化源程序的方法,宏具有宏名的一段汇编语句序列宏定义时书写宏指令这段汇编语句序列的缩写宏调用时书写宏展开宏指令处用这段宏代替的过程宏汇编时实现宏的参数功能强大,颇具特色配合宏,还有宏操作符和有关伪指令,2.1 宏汇编,宏定义,宏名macro 形参表宏定义体endm,mainbeginMACRO ;定义名为mainbegin的宏,无参数mov ax,data;宏定义体mov ds,axENDM;宏定义结束ma
6、inendMACRO retnum;带有形参retnummov al,retnum;宏定义中使用参数mov ah,4chint 21hENDM,宏注释符,宏调用,宏名实参表,start:mainbegin;宏调用,建立DS内容dispmsg string;宏调用,显示字符串mainend 0;宏调用,返回DOSend start 宏调用的实质是在汇编过程中进行宏展开 宏展开的具体过程是:当汇编程序扫描源程序遇到已有定义的宏调用时,即用相应的宏定义体取代源程序的宏指令,同时用位置匹配的实参对形参进行取代,宏展开,宏展开在汇编时,用宏定义体的代码序列替代宏指令的过程。,start:mainbegi
7、n;宏指令 1mov ax,data;宏展开 1mov ds,axmainend 0;宏指令 1mov al,0;宏展开 1mov ah,4ch 1int 21h,宏的参数,宏的参数使用非常灵活,宏定义时,可以无参数,例如4a的mainbegin可以带有一个参数,例如4a的mainend也可以具有多个参数;例如5a的shlext参数可以是常数、变量、存储单元、指令(操作码)或它们的一部分,也可以是表达式;例如5b的shift和shrot宏定义体可以是任何合法的汇编语句,既可以是硬指令序列,又可以是伪指令序列;例如6的dstring,;宏定义shlextmacro shloprand,shlnu
8、mpush cxmov cl,shlnumshl shloprand,clpop cxendm;宏指令shlext ax,6;宏展开 1push cx 1mov cl,06 1shl ax,cl 1pop cx,例5a,;统一4条移位指令的宏指令shiftmacro soprand,snum,sopcodepush cxmov cl,snums&sopcode& soprand,clpop cxendm;统一移位和循环移位8条指令的宏指令shrotmacro sroprand,srnum,sropcodepush cxmov cl,srnumsropcode sroprand,clpop cx
9、endm,例5b,替换操作符,;宏定义dstringmacro stringdb &string&,0dh,0ah,$endm;宏调用dstringdstring;宏展开 1db This is a example., 0dh,0ah,$ 1db 0 Number 10, 0dh,0ah, $,例6,转义注释符,传递注释符,宏操作符,;宏注释符,用于表示在宏定义中的注释。采用这个符号的注释,在宏展开时不出现&替换操作符,用于将参数与其他字符分开。如果参数紧接在其他字符之前或之后,或者参数出现在带引号的字符串中,就必须使用该伪操作符,宏操作符,字符串传递操作符,用于括起字符串。在宏调用中,如果传
10、递的字符串实参数含有逗号、空格等间隔符号,则必须用这对操作符,以保证字符串的完整!转义操作符,用于指示其后的一个字符作为一般字符,不含特殊意义%表达式操作符,用在宏调用中,表示将后跟的一个表达式的值作为实参,而不是将表达式本身作为参数,与宏有关的伪指令,局部标号伪指令LOCAL 标号列表宏定义体采用了标号,应使用LOCAL加以说明它必须是宏定义MACRO语句之后的第一条语句宏定义删除伪指令PURGE 宏名表不需要某个宏定义时,可以把它删除宏定义退出伪指令EXITM伪指令EXITM表示结束当前宏调用的展开,;宏定义absolmacro oprdlocal nextcmp oprd,0jge ne
11、xtneg oprdnext:endm,例7,;宏调用absol word ptr bxabsol bx;宏展开 1cmp word ptr bx,0 1jge ?0000 1neg word ptr bx 1?0000: 1cmp bx,0 1jge ?0001 1neg bx 1?0001:,比较,仅是源程序级的简化:宏调用在汇编时进行程序语句的展开,不需要返回;不减小目标程序,执行速度没有改变通过形参、实参结合实现参数传递,简捷直观、灵活多变,还是目标程序级的简化:子程序调用在执行时由CALL指令转向、RET指令返回;形成的目标代码较短,执行速度减慢需要利用寄存器、存储单元或堆栈等传递参
12、数,宏,子程序,宏与子程序具有各自的特点,程序员应该根据具体问题选择使用那种方法通常,当程序段较短或要求较快执行时,应选用宏;当程序段较长或为减小目标代码时,要选用子程序,比较结论,宏,子程序,2.2 重复汇编,重复汇编指在汇编过程中,重复展开一段(基本)相同的语句重复汇编没有名字,不能被调用重复汇编常用在宏定义体中,也可以在一般汇编语句中使用重复汇编伪指令有三个:REPEAT按参数值重复FOR按参数个数重复FORC按参数的字符个数重复最后,用ENDM结束,按参数值重复,REPEAT 重复次数 重复体ENDM,char = AREPEAT 26 db char char = char +1EN
13、DM,1db char;等效于db A 1char = char +1 1db char;等效于db B 1char = char +1. 1db char;等效于db Z 1char = char +1,按参数个数重复,FOR 形参,实参表 重复体ENDM,FOR regad, push regadENDM,1push ax 1push bx 1push cx 1push dx,按参数字符个数重复,FORC 形参, 字符串 重复体ENDM,FORC regad,dcba pop ®ad&xENDM,1pop dx 1pop cx 1pop bx 1pop ax,2.3 条件汇编,条件汇
14、编伪指令在汇编过程中,根据条件决定汇编的语句IFxx 表达式;满足,汇编分支语句体1分支语句体1 ELSE;不满足,汇编分支语句体2分支语句体2 ENDIF;条件汇编结束,pdatamacro num IF num lt 100;如果num 100,则汇编如下语句db num dup (?) ELSE;否则,汇编如下语句db 100 dup (?) ENDIFendmpdata 12 ;宏调用db 12 dup(?) ;宏汇编结果pdata 102 ;宏调用db 100 dup(?) ;宏汇编结果,例10,宏结构的作用,宏汇编、重复汇编和条件汇编为源程序的编写提供了很多方便,灵活运用它们可以编
15、写出非常良好的源程序来汇编系统中有些以圆点起始的 伪指令(如.startup、.exit等)实际上是一种宏结构,dstringMACRO string;定义字符串db 设置数据段地址mov ax,dssegmov ds,axENDMdispmsgMACRO messagemov dx,offset messagemov ah,09hint 21hENDM,例题41/3,mainendMACRO retnum;返回DOS,可不带参数ifb mov ah,4ch;没有参数else mov ax,4c00h+(retnum AND 0ffh); 有参数endifint 21hENDM,例题42/3,
16、.model small.stack 256.datamsg1equ this bytedstringmsg2equ this bytedstring.codestart:mainbegin data;建立DS内容dispmsg msg1;显示msg1字符串dispmsg msg2;显示msg2字符串mainend;返回DOSend start,例题43/3,将程序分段、采用子程序或宏结构都是进行模块化程序设计本节介绍开发大型程序时采用的方法:源程序文件的包含目标模块连接子程序库,3 模块化程序设计,例题 12将键盘输入的数据按升序输出,把源程序分放在几个文本文件中,在汇编时通过包含伪指令IN
17、CLUDE结合成一体INCLUDE 文件名可将常用的子程序形成.ASM汇编语言源文件可将常用的宏定义存放在.MAC宏库文件中可将常量定义、声明语句组织在.INC包含文件中例12a 宏库文件 lt512a.mac 主程序文件 lt512a.asm 子程序文件 sub512a.asm,3.1 源程序文件的包含,dispcharmacro char;显示char字符mov dl,charmov ah,2int 21hendmdispmsgmacro message;显示message字符串mov dx,offset messagemov ah,9int 21hendm,Lt512a.mac,incl
18、ude lt512a.mac.dispmsg msg1;提示输入数据mov bx,offset bufcall input;数据输入cmp cx,0je start4;没有输入数据则退出mov count,cx.;显示输入的数据.;数据排序.;显示经排序后的数据start4:.exit 0include sub512a.asmend,Lt512a.asm,子程序源文件有3个子程序ALdisp;显示2位16进制数子程序(例)sorting;排序子程序(例)input;键盘输入子程序还包含一个宏convert;将DX两位ASCII码转换为两位16进制数,sub512a.asm,让我们重点分析键盘输
19、入子程序 input,;键盘输入子程序;入口参数:ds:bx=存放数据的缓冲区;出口参数:cx=数据个数inputprocpush axpush dxxor cx,cx;数据个数清0input01:xor dx,dx;输入字符清0input02:mov ah,1;键盘输入一个字符int 21h,input之一,input10:cmp al,0dhje input30;是回车,结束整个数据的输入cmp al, je input20;是空格和逗号,确认输入了一个数据cmp al,je input20cmp al,08hje input17;是退格,丢弃本次输入的数据,出错,input之二,cmp
20、al,0;有效数字判断(图5.2b)jb input17;小于0,不是有效数字,出错cmp al,fja input17;大于f,不是有效数字cmp al,ajb input11sub al,20h;af转换成大写AFjmp input12input11:cmp al,Fja input17;字符小于a、大于F,出错cmp al,Ajae input12;是AF,有效字符cmp al,9ja input17;是09,有效字符,input之三,input12:cmp dl,0;有效字符的处理jne input13mov dl,al;dl=0,输入了一个数据的低位,则dlaljmp input02
21、;转到字符输入input13:cmp dh,0jne input17;dl0,dh0输入3位数据,出错mov dh,dl;dl0,dh0输入了一个数据的高位mov dl,al;dhdl,dlaljmp input02;转到字符输入,input之四,input17:mov dl,7;输入错误处理mov ah,2int 21hmov dl,?mov ah,2int 21hjmp input01;转到输入一个数据,input之五,;转换正确的输入数据(图5.2c)input20:convertjmp input01;转到输入一个数据input30:convertpop dxpop axret;返回,
22、出口参数已设定inputendp,input之六,;将DX两位ASCII码转换为两位16进制数(图5.2c)convertmacrolocal input21,input22local input24,input25cmp dl,0;dl=0,没有要转换的数据,退出je input25,convert之一,cmp dl,9jbe input21sub dl,7;字符AF,则减7input21:and dl,0fh;转换低位cmp dh,0;dh=0,没有高位数据je input24cmp dh,9jbe input22sub dh,7input22:shl dh,1shl dh,1shl dh
23、,1shl dh,1;转换高位or dl,dh;合并高、低位,convert之二,源文件包含的操作步骤: 分别编辑生成各个文件 汇编、连接主程序文件,input24:mov bx,dl;存入缓冲区inc bxinc cx;数据加1input25:endm,convert之三,把常用子程序写成独立的源程序文件,单独汇编,形成子程序的目标文件.OBJ主程序也经过独立汇编之后形成目标文件连接程序将所有目标文件连接起来,最终产生可执行文件需要遵循的原则: 声明共用的变量、过程等 实现正确的段组合 处理好参数传递问题,3.2 目标代码文件的连接,声明共用的变量、过程,各个模块间共用的变量、过程等要说明P
24、UBLIC 标识符 ,标识符.;定义标识符的模块使用EXTERN 标识符:类型 ,标识符:类型.;调用标识符的模块使用标识符是变量名、过程名等类型是byte / word / dword(变量)或near / far(过程)在一个源程序中,public/extern语句可以有多条各模块间的public/extern伪指令要互相配对,并且指明的类型互相一致,实现正确的段组合,子程序文件必须定义在代码段中,也可以具有局部的数据变量采用简化段定义格式,只要采用相同的存储模式,容易实现正确的近或远调用完整段定义格式中,为了实现模块间的段内近调用(near类型),各自定义的段名、类别必须相同,组合类型都
25、是public。实际的程序开发中,各个模块往往由不同的程序员完成,不易实现段同名或类别相同,所以索性定义成远调用(far类型)定义数据段时,同样也要注意这个问题。当各个模块的数据段不同时,要正确设置数据段DS寄存器的段基地址,处理好参数传递问题,少量参数可用寄存器或堆栈直接传送数据本身大量数据可以安排在缓冲区,用寄存器或堆栈传送数据的存储地址还可利用变量传递参数,但是要采用public/extern声明为公共(全局)变量这些也是子程序间的参数传递方法另外,混合编程介绍了更好的堆栈传递参数方法,可以采用,例12b,主程序lt512b.asm并入宏定义子程序文件sub512b.asm,要加上段定义
26、语句、声明语句等,但不需要起始点和结束点,模块连接的操作步骤: 分别编辑生成各个文件 分别汇编各个文件 连接各个目标文件,形成可执行文件,.;宏定义.codepublic count;定义count共用extern ALdisp:near,sorting:near,input:far;声明其他模块中的子程序.startup.exit 0;去掉(lt512a.asm中的)包含语句end,Lt512b.asm,.model small;定义同样的存储模式extern count:word;在其他模块定义了字变量count.code;子程序在代码段中public aldisp,sorting,inp
27、ut;3个子程序是共用的Aldispproc;仍然作为近调用sortingproc;仍然作为近调用inputproc far;修改为远调用.mov count,cx;提供出口参数.inputendpend;结束汇编,sub512b.asm,把常用子程序写成独立的源文件,单独汇编形成OBJ文件后,存入子程序库主程序也单独汇编形成OBJ文件主程序连接时,调入子程序库中的子程序模块,产生最终的可执行文件例5.12c 主程序文件 lt512c.asm 子程序文件 sub512c1.asm 子程序文件 sub512c2.asm 子程序文件 sub512c3.asm,3.3 子程序库的调入,子程序库,子程
28、序库文件(.LIB)是子程序模块的集合,其中存放着各子程序的名称、目标代码及有关定位信息存入库的子程序的编写与目标文件连接方法中的要求一样,只是为方便调用,更加严格子程序文件编写完成后,汇编形成目标文件;然后利用库管理工具程序LIB.EXE,把子程序目标模块逐一加入到库中LIB 库文件名 + 子程序目标文件名库管理程序LIB帮助创建、组织和维护子程序模块库,例如增加、删除、替换、合并库文件等,.;宏定义.codeextern ALdisp:near,sorting:near,input:near;声明其他模块中的子程序.startup.exit 0end,Lt512c.asm,.model s
29、mall.codepublic aldispAldispproc.Aldispendpend,sub512c1.asm,.model small.codepublic sortingsortingproc.sortingendpend,sub512c2.asm,.model small.codepublic inputinputproc.inputendpend,sub512c3.asm,库文件调入的操作步骤: 分别编辑生成各个文件 分别汇编各个文件 用库管理文件,将子程序模块添加到库文件(.LIB)中 连接主程序,提供库文件,形成可执行文件,补充例题,将子程序应用的例题1315的子程序编写成
30、模块,供主程序调用实现功能:从键盘输入有符号十进制数,求它们的平均值,然后输出源程序文件进行简单修改主程序文件子程序文件利用目标代码文件的连接形成可执行文件,.model smallextern read:near,write:near,mean:near;外部子程序public wtemp;变量共用.stack.data;数据定义.code;输入、计算和输出end,主程序文件,.model smallpublic read,write,mean;子程序共用extern wtemp:word;外部变量.code;代码段readproc;输入子程序readwriteproc;输出子程序writemeanproc;计算平均值子程序meanend,子程序文件,教学要求,熟悉带参数的过程定义PROC和过程声明PROTO、过程调用INVOKE伪指令了解宏操作符、宏汇编、条件汇编和重复汇编、源程序包含、代码连接和子程序库等程序设计方法掌握伪指令:MACRO/ENDM、LOCAL;INCLUDEPUBLICEXTERN了解伪指令:REPEATFORFORC、IFxx,放松一下,