1、第5章 汇编语言程序设计,5.1 汇编语言程序的上机过程,汇编示意图,5.1 汇编语言程序的上机过程(调用masm汇编演示) 1、源文件的建立和汇编 (1)建立源程序文件 (2)汇编源程序文件汇编程序主要功能:检查源程序中的语法错误并给出出错信息。产生目标文件,列表文件和对照文件。展开宏指令。,汇编操作过程:设在当前C盘上已经建立了一个扩展名为ASM的源程序文件MYASM,汇编时发出如下命令: C:MASM MYASM (或MASM MYASM.ASM ) 具体的三个输入提示行显示如下:Object Filename MYASM.OBJ:Source Listing NUL.LST:(可打入源
2、文件名或省略)Cross Reference NUL.CRF:(可打入源文件名或省略) 汇编程序对源文件进行汇编,若无错误信息则显示如下结果:0 Warning Errors0 Severe Errors,2.目标文件的链接连接软件LINK的功能:1)找到要连接的所有目标文件;2)确定所有段的地址值;3)确定所有浮动地址和外部符号所对应的存储地址;4)生成.EXE可执行文件。,连接软件为 LINK.EXE,其过程如下: 设源文件MYASM.ASM已经由汇编软件汇编后生成MYASM.OBJ,其连接命令为: C:LINK MYASM 或 LINK MYASM.OBJ则在屏幕上显示连接软件的版本号和
3、三个输入提示行,三个输入提示行显示如下:Run File MYASM.EXE:List File NUL.MAP:Libraries .LIB:3.执行文件的调试,连接示意图:,汇编语言程序开发中的相关文件,Handwritten source program,EDIT Editor program,MASM assembler program,LINK linker program,DEBUG debug program,Final debugged run module,PROG1.LST,PROG1.OBJ,PROG1.CRF,Other .OBJ files,Libraries,汇编语
4、言源程序的结构,分段结构鉴于8086 系列微处理器都是采用存储器分段管理,其汇编语言都是以逻辑段为基础,按段的概念来组织代码和数据的,因此作为用汇编语言编写的源程序,其结构上具有以下 特点:(1)由若干逻辑段组成,各逻辑段由伪指令语句定义和说明;(2)整个源程序以END 伪指令结束;(3)每个逻辑段由语句序列组成,以SEGMENT 语句开始,以ENDS 语句结束。,程序设计步骤,本节将介绍程序设计的一般过程,以及一些典型程序设计、形成的编写方法。汇编语言程序设计步骤归纳如下:(1) 分析问题。就是全面理解问题的功能,把要解决问题的所需条件、原始数据、输入和输出信息、运行速度要求、精度要求和结果
5、形式搞清楚。这是程序开发过程的第一步。(2) 建立数学模型。程序设计者可以先研究要解决问题的技术规范,找出规律,归纳出数学模型。(3) 确定算法。一旦有了描述问题的数学算法,就可把实际问题分解为计算机求解的步骤和方法,即确定算法。算法可由计算机语言、日常生活语言、表格、自定义流程图等按计算机能接受的方式进行描述。,(4) 绘制流程图。程序流程图是用图形方式对算法的一种直观而形象的描述。它是用箭头线段、框图及菱形图等绘制的形象化的图形。常见的程序流程图是由逻辑框和流向线组成。 (5) 内存空间分配。就是用指令或伪指令为数据和代码程序分配内存空间。在程序设计时要考虑分段结构。程序运行时所需要的工作
6、单元应尽可能设在CPU 寄存器中。 (6) 编制程序。选用合适的指令及程序设计常用的技巧,按流程图编写程序。要求做到简单明了、层次清晰、运算迅速以及少占内存。 (7) 程序调试。程序调试是程序设计的最后一步,也是程序设计中最重要的一步。只有通过上机运行才能验证程序是否正确,经过反复的“运行发现错误改正错误运行”才能得到正确的程序。,图5.1 标准流程图符号,汇编语言程序结构,顺序结构,分支结构,循环结构,5.2 顺序结构程序设计,顺序程序,这种程序的形式最简单,计算机执行程序的方式是指令逐条依次被执行,不进行判断和跳转,直到程序结束。实现直线运行结构程序的指令有数据传送类、算术运算类、逻辑移位
7、类等。因此,直线运行结构程序只能完成简单的功能,例如计算表达式的值、顺序查表等。顺序结构流程图见图52 【补充例】编程计算Z=(x23y)/ 2。设x、y 为单字节正整数,结果Z 用两个字节来存放。 分析:本题采用顺序结构,程序框图如右图所示。,源程序如下: DATA SEGMENTX DB 25Y DB 32Z DW ? DATA ENDS CODE SEGMENTASSUME CS:CODE,DS:DATA EXPRE PROC FAR START: PUSH DS SUB AX,AXPUSH AXMOV AX,DATA ;初始化DSMOV DS,AXMOV AL,XMUL AL ; X2
8、,MOV BL,YADD BL,BLADD BL,Y ;3YSUB AX,BX ; X23YSHR AX,1 ; (X23Y)/ 2MOV Z,AX ; 存结果RET ; 返回DOS EXPRE ENDP CODE ENDSEND STATR ; 汇编结束,例5.2 用查表的方法将一位十六进制数转换成与它相应的ASC码。 1)明确任务,确定算法。 2)绘流程图(图5-4),图5-4 例5-2流程,3)根据流程图编写汇编语言程序 DATA SEGMENT TAB DB 30H,31H,32H,33H,34H,35H,36H,37HDB 38H,39H,41H,42H,43H,44H,45H,46
9、H HEX DB ? ASCI DB ? DATA ENDS COSEG SEGMENTASSUME CS:COSEG,DS:DATA BEING: MOV AX,DATAMOV DS,AX,MOV BX,OFFSET TABMOV AH,0MOV AL,HEXXLAT MOV ASCI,ALMOV AH,4CHINT 21H COSEG ENDSEND BEING,补: 习题例解1,5.3 分支结构程序设计,分支程序就是根据不同的情况或条件执行不同功能的程 序,它具有判断和转移功能,在程序中利用条件转移指令对 运算结果的状态标志进行判断,以实现转移功能。汇编语言中实现分支的要素有两个:(1)
10、 使用能影响状态标志的指令,如算术逻辑指令、移位指令和位测试指令等,将状态标志设置为能正确反映条件成立与否的状态。(2) 使用条件转移指令,对状态位进行测试判断,确定程序如何转移,形成分支。支程序可以有2分支结构和多分支结构两种形式,分支程序的结构形式,2分支结构 IF_THEN_ELES结构,多分支结构 CASE结构,【补充例】 已知在内存中,有一个字节单元NUM 存有带符号数据,计算出它的绝对值后并放入RESULT 单元中。分析:根据数学中绝对值的概念可知,一个正数的绝对值是它本身,而一个负数的绝对值是它的相反数。要计算一个数的相反数,就要完成减法运算,即用0 减去这个数。而8086/80
11、88 系统有专用的求补指令NEG可实现。,DATA SEGMENTX DB 25RESULT DB ? DATA ENDS CODE SEGMENTASSUME CS:CODE,DS:DATA START: MOV AX, DATAMOV DS,AX ; 初始化MOV AL,X ; X取到AL 中TEST AL,80H ; 测试AL 正负JZ NEXT ; 为正转NEXTNEG AL ; 否则AL 求补 NEXT: MOV RESULT,AL ;送结果MOV AH,4CHINT 21H ; 返回DOS CODE ENDSEND START ;汇编结束,【补充例】求补码数的绝对值。 1)明确任务
12、,确定算法。 2)绘流程图(图5-7),3)根据流程图编写汇编语言程序 STACK SEGMENT STACKDW 300 DUP(?) TOP LABEL WORD STACK ENDS DATA SEGMENT XADR DW ? DATA ENDS CODE SEGMENT MAIN PROC FARASSUME CS:CODE,DS:DATA,SS:STACKMOV AX,STACKMOV SS,AXMOV SP, OFFSET TOP START: PUSH DS,MOV AX,0PUSH AXMOV AX,DATAMOV DS,AXMOV AX,XADRAND AX,AX JNS
13、DONENEG AX MOV XADR,AX DONE: RETMAIN ENDP CODE ENDSEND START,例5.3 在长度小于256的字符串中分别统计数字、大写字母和其 它字符的个数。1)明确任务,确定算法。2)绘流程图,3)根据流程图编写汇编语言程序 DATA SEGMENT BUF DB NDB 07H,2AH,47H,6AH,96H NUM DB 3 DUP(?) DATA ENDS CODE SEGMENT MAIN PROC FARASSUME CS:CODE,DS:DATA START: PUSH DSSUB AX,AXPUSH AXMOV AX,DATAMOV D
14、S,AXMOV SI,OFFSET BUFMOV CH,SI,MOV CL,CHMOV BX,0INC SI LP: MOV AH, SICMP AH,30HJL NEXTCMP AH,39HJG ABCINC BHJMP NEXT ABC:CMP AH,41HJL NEXTCMP AH,5AHJG NEXTINC BL NEXT:INC SI,DEC CH JNZ LPMOV SI,OFFSET NUMMOV SI,BHMOV SI+1,BLSUB CL,BHSUB CL,BLMOV SI+2,CLRET MAIN ENDP CODE ENDS END START,习题例解2,5.4 循环结
15、构程序设计,在程序中,往往要求某一段程序重复执行多次,这时候就可以利用循环程序结构。这里把能按一定规律,多次重复执行的一串语句,叫作循环程序。,1. 循环结构组成:(1) 循环初始化部分:这是为了保证循环程序能正常进行循环操作而必须做的准备工作。循环初值分两类:一类是循环工作部分的初值,别一类是控制循环结束条件的初值。(2) 循环工作部分:即需要重复执行的程序段,这是循环的中心,即循环体。(3) 循环参数修改部分:按一定规律修改操作数地址及控制变量,以便每次执行循环体时得到新的数据。(4) 循环控制部分:用来保证循环程序按规定的次数或特定条件正常循环。(5) 循环结束部分:主要用来分析和存放程
16、序的结果。,两种形式: WHILE_DO结构 DO _UNTIL结构WHILE_DO结构设计思想:当循环控制条件满足时,执行循环体程序,否则退出循环。 DO _UNTIL结构设计思想:先执行循环体程序,再判断循环控制条件是否满足,若不满足则执行循环体程序,否则退出循环。,2.循环结构程序设计,循环程序的结构形式,DOUNTIL结构,3. 循环控制的方法如何控制循环是循环程序设计中最重要的一个环节,下面 介绍两种最常见的循环控制方法。 1) 计数控制法当循环次数已知时,通常使用计数控制法。在汇编语言 程序设计中常采用CX 寄存器作为循环计数器。假设循环次 数为n,常常用以下3种方法实现计数控制和
17、条件控制。 2) 条件控制法在有些情况下,循环次数事先无法确定,但它与问题的某 些条件有关。这些条件可以通过指令来测试。若测试比较的 结果表明满足循环条件,则继续循环;否则结束循环,假设循环次数为N,常常用以下2种方法实现计数控制和 条件控制(1) 先将循环次数N送入循环体计数器中,然后,每循环 一次,计数器减1,直至循环计数器中的内容为0 时结束循 环。例如:MOV CX,N ;循环初值部分 LOOPA: ; 工作部分 ;修改部分DEC CX ; 控制部分JNZ LOOPA其中工作部分、修改部分被重复执行N 次,即当(CX)=0 , 1, N1时,重复执行循环体,当(CX)=0 时,结束循环
18、。,(2) 先将0送入循环计数器中,然后每循环一次,计数器加 1,直到循环计数器的内容与循环次数N相等时退出循环。 例如:MOV CX,0 ;循环初值部分 LOOPA: ;工作部分INC CX ;修改部分CMP CX,N ; 控制部分JNE LOOPA其中工作部分、修改部分重复执行N 次,即当(CX)=0,1,N1时重复执行,当(CX)=N时结束循环。,例5-6 试编写一程序统计出某一内存单元中1的个数 并将结果存入RESULT单元中。 1)明确任务,确定算法。 2)绘流程图(图5-11),3)根据流程图编写汇编语言程序 DATA SEGMENT XDA DW 3AD8H RESULT DW
19、? DATA ENDS CODE SEGMENT MAIN PROC FARASSUME CS:CODE,DS:DATA START: PUSH DSMOV AX,0PUSH AXMOV AX,DATAMOV DS,AXMOV CX,0,MOV AX,XDA AGAIN: CMP AX,0 ; (AND AX,AX)JZ EXITSHL AX,1JNC NEXTINC CX NEXT: JMP AGAIN EXIT: MOV COUNT,CXRET MAIN ENDP CODE ENDSEND START,5.4.2 循环程序的控制方法 (1)计数法 计数法分为正计数法和倒计数法。 例5.10
20、 编制程序将两个n字节的无符号数相加,结果存入SUM 开始的n+1字节存储区中。 1)明确任务,确定算法。,2)绘流程图,3)根据流程图编写汇编语言程序 SSEG SEGMENT PARA STACKSSEG STACK DB 150 DUP(?) SSEG ENDS DATA SEGMENT DATA1 DB N DUP(?) DATA2 DB N DUP(?) SUM DB N+1 DUP(?) DATA ENDS CSEG SEGMENTASSUME CS:CSEG,DS:DATA,SS:SSEG MAIN PROC FAR START: PUSH DSMOV AX,0PUSH AXMO
21、V AX,DATAMOV DS,AXMOV AX,SSEG,MOV SS,AXMOV SP,SIZE STACKLEA BX,DATA1LEA SI,DATA2LEA DI,SUMMOV CX,NCLC AGAIN: MOV AL,SI ADC AL,BXMOV DI,ALINC BXINC SIINC DILOOP AGAINADC BYTE PTR DI,0 RET MAIN ENDP CSEG ENDSEND START,(2)条件控制法 条件控制法利用已知的条件对循环进行控制的方法。 分两种情况: 如循环最大次数已知, 但有可能使用一些特征或条件使循环提前结束。 循环次数未知,利用条件
22、中的特征结束循环。 例5.11 编制程序用单字符输出的DOS功能调用向屏幕输出以 “%”结束的字符串。 1)明确任务,确定算法。,2)绘流程图,图5-12 流程图,3)根据流程图编写汇编语言程序DSEG SEGMENTDATA DB HOW ARE YOU?%DSEG ENDSCSEG SEGMENTASSUME CS:CSEG,DS:DSEG,SS:SSEGSTART: MOV AX,DSEG MOV DS,AX,LEA SI,DATA AGAIN: MOV DL,SICMP DL,%JZ ENDOUTMOV AH,2INT 21HINC SIJMP AGAIN ENDOUT: RET CS
23、EG ENDSEND START,【补充例】 编写程序完成求123N 的累加和,直 到累加和超过1000 为止。统计被累加的自然数个数送CN 单元,累加和送SUM。,DATA SEGMENTSUM DW ?CN DW ? DATA ENDS CODE SEGMENTASSUME CS:CODE,DS:DATA START: MOV AX,DATAMOV DS,AX ;初始化MOV AX,0 ;0 送AXMOV BX,0 ;0 送BXLP: INC BX ;BX 加1ADD AX,BX ;求累加和CMP AX,1000 ;比较JBE LP ;1000 转MOV SUM,AXMOV CN,BX ;
24、送结果MOV AH,4CHINT 21H ;返回DOSCODE ENDSEND START ;汇编结束,源程序:,流程图如图,习题例解3、4,采用冒泡排序法: 从数组的第一个数开始,依次对相邻的两个数进行比较,若次序符合要求,则不进行任何操作;否则,将相比较的两数交换位置。 多重循环结构,共进行N-1遍比较就可完成排序任务。 COUNT1为外循环变量,COUNT2为内循环变量。,例5-13:对N个数按由大到小的次序排列,DSEG SEGMENT ADDR DW N DUP(?) DSEG ENDS CSEG SEGMENTASSUME CS:CSEG,DS:DSEG MAIN PROC FAR
25、 START: PUSH DSSUB AX,AXPUSH AXMOV AX,DSEGMOV DS,AXMOV CX,N ;内循环变量存于CX中DEC CX ;CX=N-1 LOOP1: MOV DX,CX ;外循环变量存于DX中MOV BX,0 ;地址指针预置为0 LOOP2: MOV AX,ADDRBX ;取相邻两数比较CMP AX,ADDRBX+2JBE COTINUE ;符合排序,转移XCHG AX,ADDRBX+2;不符合排序,二数交换MOV ADDRBX,AX ;存大数 COTINUE:ADD BX,2 ;修改地址指针LOOP LOOP2 ;若一遍未比较完,继续MOV CX,DXLO
26、OP LOOP1 ;若N-1遍未作完,继续RET MAIN ENDP CSEG ENDSEND START,5.5 子程序结构程序设计,在程序设计中,往往将一些需要在不同的地方多次反复出现的程序段定义成子程序,即过程,这样主程序在每次需要时就可以进行调用,当过程执行结束后,再返回原来调用的地方,继续执行后续程序。1) 过程调用指令 (Call a Procedure)通过改变代码段寄存器CS和指令指针寄存器IP的内容,使程序的执行顺序发生转移。过程调用指令执行时,须将断点地址,即当前的IP 或IP 与CS 的内容压入堆栈保护,以便过程结束时通过相应的出栈操作,能够正确返回程序断点处,继续执行主
27、程序,2) 过程返回指令(Return from Procedure)过程的最后一条可执行指令必须是返回指令,用以返回到调用过程的断点处,即从堆栈中弹出由CALL 指令压入的断点地址,送入IP和CS寄存器中,从而在断点处继续执行程序。,主要包括三个方面,即: 子程序的定义与调用 子程序的参数传送 子程序嵌套与递归调用,子程序结构程序设计,在程序设计中,可将具有一定功能的程序段看成为一个过程(相当于一个子程序)。它可以被别的程序调用(用CALL指令)或由JMP指令转移到此执行;也可以由程序顺序执行;也可以作为中断处理程序,在中断响应后转此执行。一个过程由伪指令PROC和ENDP来定义,其格式为过
28、程名 PROC类型 过程体RET过程名 ENDP,1. 过程的定义和调用,远过程调用时被调用过程必定不在本段内。例如,有两个程序段,其结构如下:,CODE1 SEGMENTASSUME CS:CODE1 FARPROC RPOC FARRETFARPROC ENDP CALL FARPROC CODE1 ENDSCODE2 SEGMENTASSUME CS:CODE2 CALL FARPROC CALL NEARPROC NEARPROC PROC NEAR RETNEARPROC ENDPCODE2 ENDS,寄存器内容的保护和恢复,通常主程序和过程的设计是分开进行的,因而它们使用的寄存器往
29、往会发生冲突。如果主程序中某寄存器的内容在调用过程后还要用,而被调用过程执行期间也要使用该寄存器,则在进入过程时,先将该寄存器的内容保护起来,称为保护现场;而从过程返回主程序前,再将这些寄存器的内容恢复,称为恢复现场。保护现场和恢复现场通常用堆栈压入指令和弹出指令来实现。,SUBRP PROC FARPUSH AXPUSH BXPUSH CXPUSH DXPOP DXPOP CXPOP BXPOP AXRETSUBPR ENDP,2. 主程序和过程间的参数传递,CPU内部寄存器传递参数 指定内存单元(变量)传递参数 通过地址表传送变量地址 通过堆栈传送参数或参数地址,1)CPU内部寄存器传递参
30、数,例:编写一过程,完成将4位十六进制ASCII码转换为等值二进制数。已知:4位十六进制ASCII码存放在内存的某一区域中,且低位数的地址号低,高位数的地址号高。转换过程:从最低位ASCII码开始,逐位将一个字节的ASCII码转换为等值的二进制数,最后拼装起来即可。,;入口参数:存放4位十六进制ASCII码的内存首地址送入DS:SI,ASCII码位数CL ;出口参数:DX(转换结果)AS_BI PROC FARPUSH AX ;保护寄存器内容MOV CH,CL ;位数送CHCLD ;方向标志清零XOR AX,AX ;AX,DX清零MOV DX,AX AGAIN: LODSB ;(DS:SI)A
31、L,(SI)+1 SIAND AL,7FH ; AL7位ASCII码CMP AL,9 ; AL9?JG A_TO_FSUB AL,30HJMP SHORT ROTATE A_TO_F:SUB AL,37H ROTATE:OR DL,AL ;拼装各位转换结果ROR DX,CLDEC CHJNZ AGAINPOP AXRET AS_BI ENDP,2)内存单元(变量)传递参数,例:编写一过程,完成对N元素的数组求和。且过程和主程序在同一代码段。,DSEG SEGMENT ARY DW 100 DUP(?) COUNT DW ? SUM DW 2 DUP(?) DSEG ENDS SSEG SEGM
32、ENT STACKDB 100 DUP(?) TOP LABEL WORD SSEG ENDS CSEG SEGMENTCALL PROADD PROADD PROC NEARPUSH AXPUSH CXPUSH DXPUSH SILEA SI,ARYMOV CX,COUNTXOR AX,AXMOV DX,AX AGAIN: ADD AX,SI ;累加N个元素的低位字JNC NEXTINC DX ;若有进位,则和的高位字加1 NEXT: ADD SI,2LOOP AGAINMOV SUM,AXMOV SUM2,DXPOP SIPOP DXPOP CXPOP AXRET PROADD ENDP
33、CSEG ENDSEND START,例511 定义一个显示两位十六进制数的子程序 程序说明:;名称:DISPP;功能:显示两位十六进制数;所用寄存器CX,DX;人口参数:AL存放两位十六进制数;出口参数:无;调其它子程序:DISP1,子程序; DISPP PROC NEARPUSH DXPUSH CXMOV DL, ALMOV CL, 4ROL DL, CLAND DL, 0FHCALL DISP1MOV DL, ALAND DL, 0FHCALL DISP1POP CXPOP DXRETDISPP ENDP,DISP1 PROCOR DL,30HCMP DL,3AHJB DDDADD DL
34、,07HDDD: MOV AH,2INT 21HRET DISP1 ENDP,2、子程序的调用和返回 例512 编制显示四位十六进制数的子程序 1) 明确任务,确定算法。 2)绘流程图 3)根据流程图编写汇编语言程序,DISP4 PROC NEAR PUSH BX PUSH CX PUSH DXPUSH AXMOV AL, AHCALL DISP2POP AXCALL DISP2POP DXPOP CX POP BXRET DISP4 ENDP DISP2 PROC NEARMOV BL, ALMOV DL, ALMOV CL,4,ROL DL,CLAND DL,0FHCALL DISP1 M
35、OV DL,BL AND DL,0FHCALL DISP1 RET DISP2 ENDP DISP1 PROCOR DL,30HCMP DL,3AHJB DDDADD DL,07HDDD: MOV AH,2INT 21HRET DISP1 ENDP,实验1:编写一程序,把20个字节的数组分成正数组和负 数组,并分别计算两个数组中数据的个数,分析:已知一个含20个字节数据的数组正数组预留20个字节的存储空间负数组预留20个字节的存储空间若应用存储器存储两个数组中数据的个数,则需: 预留1个字节的存储空间存放正数个数 预留1个字节的存储空间存放负数个数 关键:采用何种方式选取变量中的某个项,实验2
36、 编写一程序实现将32位数左移4位,并将高四位存入CH中,已知32位数存放在DX:AX中。,开始,4CL,CH=0,40位数(CH、DX、AX 内容)左移1位,(CL)-1=0?,N,Y,结束,分析:32位数存放在DX:AX中,即DX存放高字,AX存放低字。根据题意,左移4位可通过把CH:DX:AX寄存器内容每次左移1位,循环移位4次来实现。 关键:如何实现左移1位,题1:编一程序,完成10个一位十进制数累加,累加结果以未组合形式存放于AH(高位)、AL(低位)寄存器。题2:编一程序,将2个字节的二进制数,变成用ASCII码表示的四位十六进制数题3:试用串操作指令SCAS,在10个字节的数据块BLOCK中,搜索与5EH相等的数,如找到,将该数地址号存于ADR中,并在SIGNAL单元中做标记FFH;否则,SIGNAL为00H题4. 编写一个程序,将一个数组中正数与负数分成两个数组,并分别显示正数与负数的个数。题5. 在变量DATA中存放着10个无符号的字节数据,试变成找出其中最大的数,并存入MAX中。,练习题:,课后练习题 p2022. 3(1)(3),