1、,概述汇编语言源程序的结构常用伪指令数据项及表达式DOS功能调用(数据的输入和输出)基本结构程序设计,第4章 汇编语言程序设计,概述,机器语言用二进制数来表示指令和数据 例如,B0 64 什么意思?所以,机器语言既不直观,又不易理解和记忆汇编语言是使用助记符的一种编程语言例如,MOV AL,64H 容易记忆理解,这就是助记符的作用助记符用英语单词表示的指令操作码。它反映指令的功能和主要特征,便于人们理解和记忆。,概述,汇编语言是一种面向CPU指令系统的程序设计语言。它使用助记符表示操作码,用符号代表操作数或操作数地址; 用汇编语言编写的程序叫汇编源程序; 汇编源程序需翻译成机器语言,变成可执行
2、文件,机器才能执行,这个翻译过程叫汇编; 汇编语言是面向具体计算机硬件的语言,和机器密切相关。,概述,高级语言编程时不需要对机器指令系统有深入了解,稍加培训即可掌握。可读性强,功能强。 为什么要用汇编语言? 汇编语言编写的程序节省内存,执行速度快,并为用户 直接控制对象提供了手段,故系统程序和实时控制程 序多采用汇编语言编写。,汇编语言源程序结构,汇编语言源程序通常由一个或几个程序模块组成;每个模块包括数据段、堆栈段和代码段。其中,数据段和堆栈段由一系列伪指令组成,代码段可由具体的执行语句组成。,一个基本的汇编语言程序框架如下:stack SEGMENTDB 100 DUP(stack)sta
3、ck ENDSdata SEGMENTdata ENDScode SEGMENTASSUME CS:code, DS:data, ES:data SS:stack start: MOV AX, dataMOV DS, AXMOV ES, AXMOV AH, 4CHINT 21Hcode ENDSEND start,堆栈段,数据段,代码段,汇编语言的语句与格式,汇编语言的语句有两种: 执行性语句由8088指令助记符构成的语句 说明性语句由伪指令构成的语句 执行性语句的格式为:标号: 指令助记符 目的操作数,源操作数 ;注释说明性语句的格式为:名字 伪指令 操作数1,操作数2,操作数n ;注释注:
4、各部分之间至少要用一个空格作为分隔符,执行性语句由CPU执行;每一条执行性语句都有一条机器码指令与其对应;说明性语句由汇编程序执行;它指出汇编程序应如何对源程序进行汇编,如何定义变量、分配存储单元以及指示程序开始和结束等;说明性语句无机器码指令与其相对应; 执行性语句汇编时生成机器码;说明性语句汇编时不生成机器码。,汇编语言的语句与格式,标号指令的符号地址,用来代表指令在存储器中的地址。只能出现在执行性语句中,标号后应加上冒号。 名字段、过程、变量的名字,用来代表它们在存储器中的地址。只能出现在说明性语句中,名字后不加冒号。 指令助记符8088助记符、伪指令 操作数即指令的操作对象 对执行性语
5、句0,1,2个 对说明性语句根据需要而定 操作数之间以逗号分隔 操作数可以是:寄存器、存储单元、常数或表达式 例如:AX,DI+BX+10,200,16*8+TABLE,等等,汇编语言语句的构成元素,注释以分号开头,可放在指令后,也可单独一行。注意注解的写法。要写明指令在程序中的作用,而不要写指令的操作。例如:以下为同一条指令写的注释1)MOV CX,100 ;传送100到CX2)MOV CX,100 ;循环计数器置初值显然,第二种写法要比第一种写法要好。,汇编语言的一个实例: hello.asmdata SEGMENT Hello DB Hello, world!,0DH,0AH,$ dat
6、a ENDS prog SEGMENTASSUME CS:prog,DS:data start: MOV AX,dataMOV DS,AXLEA DX,hello ;取字符串首地址MOV AH,9INT 21H ;显示字符串MOV AH,4CHINT 21H ;退回DOS prog ENDSEND start,名字,标号,常用伪指令,符号定义伪指令 数据定义伪指令 段定义伪指令 段寄存器说明伪指令 定位伪指令 过程定义伪指令,符号定义伪指令,1.等值伪指令EQU 格式: 符号名 EQU 表达式或: 新符号名 EQU 老符号名 例: CONSTANT EQU 100NEW_PORT EQU PO
7、RT_VAL+1 EQU伪指令在未解除前,不能重新定义,2.等号伪指令 格式:符号名 = 表达式 与EQU类似,但允许重新定义 例: EMP=7 ;值为7EMP=EMP+1 ;值为8,符号定义伪指令,3.解除伪指令PURGE 格式: PURGE 符号1,符号2, 可用PURGE解除已用EQU定义的符号,再重新定义例:PURGE NEW_PORTNEW_PORT EQU POTR_VAL+8,符号定义伪指令,这类伪指令格式为: 变量名 伪指令助记符 操作数 ;注释 其中, 变量名用符号地址表示,后面不能跟冒号 数据定义伪指令助记符有如下几种: DB 用来定义 字节DW 用来定义 字DD 用来定义
8、 双字操作数可以是常数或表达式注释用来说明伪指令的功能,它亦可有可无,数据定义伪指令,汇编后如下图所示:(内存分配),DATA_BYTE,DATA_DW,DATA_WORD,10,5,10H,100H,100,-4,60,0FFFBH,例: DATA_BYTE DB 10,5,10H DATA_WORD DW 100H,100,-4 DATA_DW DD 2*30,0FFFBH,当操作数可以是字符串MASTERLI DB HELLO 汇编后如下:,MASTERLI,操作数?是一个特别数据 用来保留存储空间,但不存入数据 例: ABC DB 0,1,?,?,?LPI DW ?,54,? 汇编后如
9、下图示:,ABC,LPI,0,1,?,?,?,?,?,54,复制操作符DUP 操作数字段还可以用复制操作符DUP来进行缩写表示 如 ABC DB 0,1,?,?,? 等价于ABC DB 0,1,3 DUP(?) 又如: DO-2 DB 2 DUP(0,1,2,?) 等价于 与 DO-2 DB 0,1,2,?,0,1,2,?,数据定义伪指令,段定义伪指令,8086/8088 CPU对存储器是分段管理数据段、堆栈段、代码段都需要在程序中进行定义;一个程序模块就是由各段构成段的定义使用由段定义伪指令语句段定义伪指令的格式如下:段名 SEGMENT 段名 ENDS,这两个伪指令总是成对出现,二者前面的
10、段名一致 二者之间的删节部分:对数据段、附加段及堆栈段,是符号和变量定义等伪指令 对于代码段,是指令及其他的伪指令 例: DATA1 SEGMENTX=123Y DB 10HDATA1 ENDS,段定义伪指令,段寄存器说明伪指令,段定义完成后,必须说明各定义段与各段寄存器的关系 使用ASSUME伪指令实现指令格式为:ASSUME Seg-reg:SEGNAME ,其中,段寄存器名必须是CS、DS、ES或SS中的一个段名则是由SEGMENT及ENDS定义的段名,需指出的一点,ASSUME伪指令只是告知汇编程序有关段寄存器与段的关系,并没有给段寄存器赋予实际的初值;实际的段基址需要用传送指令赋值
11、如: MOV AX,DATAMOV DS,AXMOV ES,AX如程序中用到堆栈段,也需装入实际的初值但代码段不需要用户说明,由初始化程序装入,段寄存器说明伪指令,伪指令ORG规定了段内程序或数据存储的起始地址或偏移地址,其格式为:ORG 表达式的值即为段内的起始地址或偏移地址,从此地址起连续存放程序或数据。如需要从偶地址开始存储程序或数据,则需要使用伪指令:EVEN,定位伪指令,DATA SEGMENTX DB 10HEVENY DW 0200HORG 06HZ DB A DATA ENDS,偏移地址,内容,定位伪指令,过程定义伪指令,过程就是子程序;一个过程可以被其它程序所调用(用CALL
12、指令),过程的最后一条指令一般是返回指令(RET) 过程定义伪指令的格式:PROC 类型 RETENDP,过程的类型有两种:NEAR 表示段内调用(默认类型)FAR 表示段间调用调用一个过程的格式为:CALL ,过程定义伪指令,数据项及表达式,数据项包括常量、变量、标号及表达式 1.常量 (1)数字常量二进制常量,以B结尾,如01000001B十进制常量,以D结尾,如56D十六进制常量,以H结尾,如0A8C6H,(2)字符串常量 用引号引起来的字符或字符串称为字符串常量 例: A,BCDE,汇编时被翻译成对应的ASCII码41H和42H,43H,44H,45H。如:MOV AL, AMOV A
13、L, 41H,数据项及表达式,变量是内存中的数据区,在程序中作为存储器操作数来使用;代表存放数据的存储单元的符号地址 变量有三种属性: 段属性变量所在的逻辑段 偏移属性变量在逻辑段中的偏移地址 类型属性有字节、字和双字三种,变量,标号是某条指令所存放单元的符号地址,可作为转移指令或CALL指令的转移地址 标号有三种属性:段值属性:指令代码所在的逻辑段,总是在CS段寄存器中偏移量属性:概念与变量相同类型属性:分NEAR和FAR两种 NEAR表示标号所在语句与转移指令或调用指令在同一码段内,只需改变IP即可。 FAR表示标号所在语句与转移指令或调用指令不在同一码段内 若没有对类型进行说明,默认为N
14、EAR。,标号,表达式,表达式是常数、寄存器、标号、变量与一些运算符组合的序列,分数字表达式和地址表达式两种 汇编时按一定的优先规则对表达式进行计算后可得到一个数值或一个地址 下面介绍五种运算符:,算术运算符有+、-、*、/,以及MOD MOD表示除法运算后得到的余数。例:19/7的商是2,19 MOD 7则为5(余数) 算术运算符可以用于数字表达式,例:MOV AL,2*7 算术运算符也可以用于地址表达式 地址运算的结果应有明确的物理意义,例两个地址的乘或除无意义,而加或减则可以 例: LEA SI,SUM+3;表示变量SUM的地址加上3得到的和作为新存储器地址,算术运算符,逻辑运算符有AN
15、D、OR、XOR和NOT,它们只能用于数字表达式中例:MOV CL, 36H AND 0FH,逻辑运算符,这些逻辑运算符也是8086/8088的指令助记符,会不会造成混乱呢? 如:AND DX,PORT_VAR AND 0FEH 说明: 后一个逻辑运算符AND在汇编时进行,若PORT_VAR为81H,则汇编后表达式算出为80H.执行前一个指令助记符AND时,将(DX)与80H相与,结果在DX中。,逻辑运算符,关系运算符共有6个,它们为:EQ(相等),NE(不等),LT(小于),GT(大于),LE(小于或等于),GE(大于或等于) 关系运算符的两个操作数必须都是数字或者是同一段内的两个存储器地址
16、运算关系为真,结果为0FFFFH(全1)运算关系为假,结果为0 (全0),关系运算符,例:MOV BX,PORT_VAL GE 5 若PORT_VAL的值大于等于5,则汇编后为:MOV BX,0FFFFH 若PORT_VAL的值小于5, 则汇编后为:MOV BX,0,关系运算符,可以把存储器一些特征作为数值送回 这些操作符有OFFSET,SEG,TYPE,SIZE及LENGTH 例:MOV SI,OFFSET STRI1 ;代表将变量 STRI1 处的偏移地址取到SI中 注意与 MOV SI,STRI1的差别与此类似,SEG运算符用来取存储单元的段基址值,例:MOV AX,SEG STRI1
17、;将变量STRI1所MOV DS,AX ;在段基址取到DS中,数值返回操作符或取值运算符,求类型值TYPE TYPE操作符用来取存储器的单元数据的类型;各单元类型对应值如下:存储器单元类型 对应值DB(字节) 1DW(字) 2DD(双字) 4,数值返回操作符或取值运算符,LENGTH操作符用来计算复制操作DUP定义的变量的复制次数; 如果未使用DUP伪指令定义变量,则LENGTH返回值为1 例:若FEES被定义为:FEES DW 4,5,6则 MOV CX,LENGTH FEES汇编后 MOV CX,1 SIZE操作符用来计算变量字节总数;它等于类型TYPE与复制次数LENGTH的乘积,数值返
18、回操作符或取值运算符,例:若BUFFER2存储区是用如下伪指令定义的: BUFFER2 DW 200 DUP(0)则:TYPE BUFFER2 等于2LENGTH BUFFER2 等于200SIZE BUFFER2 等于400,数值返回操作符或取值运算符,符号类型操作符PTR是用来对操作数(如存储单元)指定类型,通常和伪指令BYTE,WORD等连起来使用例:MOV BYTE PTRDI,0MOV WORD PTRDI,0而 MOV DI,0 ;类型不定PTR也可用来对已经规定了类型进行更改,符号类型操作符PTR,DOS功能调用与 INT 21H,系统功能调用由OS提供的一组实现特殊功能的子程序
19、供程序员在程序中调用,以减轻编程工作量 用户程序在调用这些系统服务程序时,不是用CALL命令,而是采用软中断指令INT n来实现 在DOS系统中,功能调用都是用软中断指令INT 21H来实现的,(1) 从键盘输入一个字符(功能号=1)MOV AH,1INT 21H,1. DOS键盘功能调用,例:程序中有时需要用户对提示做出应答。GET_KEY: MOV AH,1 ;等待键入字符INT 21H ;结果在AL中CMP AL,Y ;是Y?JZ YES ;是,转YESCMP AL,N ;是N?JZ NO ;是,转NOJMP GET_KEY ;否则继续等待输入YES: NO: ,(2) 输入字符串(功能
20、号=0AH) 此功能调用从键盘输入一串字符并把它存入用户指定的缓冲区中MOV AH, 0AHLEA DX, INT 21H,(预留的N1个字节的存储单元),0DH,N2,N1,N1: 缓冲区长度(最大键入字符数)N2: 实际键入的字符数(不包括回车符),用户定义的输入字符串的缓冲区格式,若用户键入的字符数(包括回车)定义的N1,本功能调用将不再接收新的键入,且光标不再向右移动 例:设在数据段定义键盘缓冲区如下:STR1 DB 10,?,10 DUP(?) 调用DOS功能的0AH号功能的程序段为:LEA DX,STR1MOV AH,0AHINT 21H 此程序段最多从键盘接收10个按键(包括回车
21、),DOS显示功能调用,(1) 在显示器上显示一个字符(功能号=2)MOV AH, 2MOV DL, INT 21H例:在显示器上显示一个字符AMOV AH, 2MOV DL, A ;或MOV DL, 41HINT 21H,MOV AH, 9LEA DX, INT 21H被显示的字符串必须以$结束,(2)显示字符串(功能号=9),DOS显示功能调用,例:在屏幕上显示:HELLO,WORLD! 在数据段定义字符串:DATA SEGMENTSTR1 DB HELLO,WORLD!$DATA ENDS 在代码段中进行显示输出MOV AH,9LEA DX,STR1INT 21H,顺序结构程序设计分支结
22、构程序设计循环结构程序设计,基本结构程序设计,例. 设0-9的平方值连续存放在以TABLE开始的存储区域中,求VARX单元内容(设为0-9中某个数)的平方值,要求结果存放在RSLT单元.,STACK SEGMENT ;堆栈段DB 100 DUP (?) STACK ENDS DATA SEGMENT ;数据段VARX DB 5RSLT DB ?TABLE DB 0,1,4,9,16,25,36,49,64,81 DATA ENDS CODE SEGMENTASSUME CS:CODE,DS:DATA,SS:STACK START PROC FARPUSH DSMOV AX,0PUSH AX ;
23、保证返回DOSMOV AX,DATAMOV DS,AX ;为DS赋值LEA BX,TABLE ;取有效地址,MOV AL,VARXMOV AH,0ADD BX,AX ;获得所求地址MOV AL,BX MOV RSLT,AL ;存储结果RET START ENDP CODE ENDSEND START ;指明开始执行,例.比较两个无符号数X1和X2的大小,把其中的大数存入MAX单元.,DATA SEGMENT ;数据段SOURCE DB X1,X2 ;两个无符号数MAX DB ? DATA ENDS STACK SEGMENT STACK STACK;堆栈段DB 100H DUP (?) STA
24、CK ENDS CODE SEGMENTASSUME CS:CODE,DS:DATA,SS:STACK START: MOV AX,DATAMOV DS,AX ;为DS赋值MOV AL,SOURCECMP AL,SOURCE+1JNC BRANCH ;CF判断无符号数MOV AL,SOURCE+1 BRANCH: MOV MAX,AL,MOV AX,4C00HINT 21H ;返回DOS CODE ENDSEND START ;指明开始执行,例.编写一个程序求10个数的和.,DATA SEGMENT ;数据段BUFFER DW a1,a2,a3,a10SUM DW ? DATA ENDS STACK SEGMENT STACK STACKDB 100 DUP (?) STACK ENDS CODE SEGMENTASSUME CS:CODE,DS:DATA START: MOV AX,DATAMOV DS,AX ;DS赋值MOV AX,0MOV DI,OFFSET SUMMOV BX OFFSET BUFFERMOV CX,10 LOOP1: ADD AX,BX,INC BXINC BXDEC CXJNZ LOOP1MOV DI,AXMOV AX,4C00HINT 21H ;返回DOS CODE ENDSEND START ;指明开始执行,