280 likes | 451 Views
第 5 章. 汇编语言与 程序设计. 5.1 汇编语言基础. 计算机语言包括:. 汇编语言. 机器语言. 高级语言. 面向机器的语言. 汇编语言: 用助记符表示指令 汇编语言源程序: 用 汇编语言 编写的程序 汇编 程序: 编译汇编语言源程序的程序. 程序设计与执行过程. 建立源程序 ( 文件名 .ASM ). 用编辑软件 ( 如 EDIT.EXE ). 编译成目标文件 ( 文件名 .OBJ ). 用汇编程序 ( 如 TASM.EXE ). 生成可执行文件 ( 文件名 .EXE ).
E N D
第 5 章 汇编语言与 程序设计
5.1 汇编语言基础 • 计算机语言包括: 汇编语言 机器语言 高级语言 面向机器的语言 • 汇编语言:用助记符表示指令 • 汇编语言源程序:用汇编语言编写的程序 • 汇编程序:编译汇编语言源程序的程序
程序设计与执行过程 建立源程序(文件名.ASM) 用编辑软件(如EDIT.EXE) 编译成目标文件(文件名.OBJ) 用汇编程序(如TASM.EXE) 生成可执行文件(文件名.EXE) 用链接程序(如TLINK.EXE) 用调试程序(如TD.EXE) 也可直接运行可执行文件 调试和运行程序
汇编语言包括的语句 • 指令性语句: CPU执行的指令,编译后生成目标代码, 要求的操作在执行程序时完成。 • 指示性语句: CPU不执行的指令,编译后生不生成目标代码, 要求的操作由汇编程序完成。 下面分别介绍
指令性语句 • 由CPU执行的指令, 编译后生成目标代码 • 语句格式: [标号:] [前缀] 助记符 [操作数] , [操作数] [ ; 注释] 例MIUS: ADD AX , BX ; 加法指令 INC BX ; BX加1 指令的符号地址 操作码 注释前加分号
指示性语句 • CPU不执行的指令; • 由汇编程序执行,编译后不生成目标代码; • 用于分配内存空间、定义变量、指示程序开始和结束等。 • 指令格式: [名字] 伪指令助记符 操作数 [,操作数,…] [ ;注释] 例Y EQU 100 ;用符号(变量)Y代替数据100
指示性语句中的操作数 可以是: • 寄存器 • 存储器单元 • 常量:数值或字符、字符串 • 变量:代表内存的数据区,程序视为存储器操作数 • 表达式:可包括各种运算符
5.2 常用伪指令 • 段定义伪指令 • 指定段寄存器伪指令 • 过程定义伪指令 • 变量定义伪指令 • 符号定义伪指令 下面分别介绍
段定义伪指令 • 说明逻辑段的起始和结束 • 说明不同程序模块中同类逻辑段之间的联系形态 段名 SEGMENT [定位类型] [组合类型] [’类别’] ┇ 段名 ENDS 例 定义数据段 DATA SEGMENT MEM1 DB 11H , 22H MEM2 DW 1234H DATA ENDS 说明逻辑段的起点 与其他段的关系 段的类别
指定段寄存器伪指令 • 功能: 用于说明指向逻辑段的寄存器 • 格式: ASSUME 段寄存器名: 段名 [,段寄存器名: 段名,… ] 例DATA SEGMENT ;定义数据段 ┇ DATA ENDS CODE SEGMENT ;定义代码段 ASSUME CS: CODE , DS: DATA ;指定段寄存器 ┇ CODE ENDS
过程定义伪指令和返回指令 • 过程定义伪指令用于定义过程体 • 格式: 过程名 PROC [ NEAR / FAR ] ┇ RET 过程名 ENDP • 过程的返回指令:RET • 该指令一般位于子程序的最后 • 用于从堆栈中弹出断点地址,返回原程序。
变量定义伪指令DB/DW/DD • 变量定义伪指令用于在数据段中定义变量,并按照变量类型分配存储单元和赋初值。 • 格式1:[变量名] {DB/DW/DD}表达式 • 格式2:[变量名] [重复次数]{DB/DW/DD}DUP 表达式 • 例如: • ONE DB 25H ;定义1个字节变量ONE,存入初值25H • TWO DB 5,7 ;定义2个连续的字节单元,分别存入初值5和7 • THREE DB ? ;定义1个字节,数据任意 • DATA1 DW 1234H ;定义1个字(2个字节),存入数据1234H
符号定义伪指令(EQU/=) • 符号定义伪指令用于为常量、变量、表达式或其他符号定义一个名字,但不分配内存单元。 • 格式1:符号名 EQU 数值表达式 • 格式2:符号名 = 数值表达式 • 例如: • CONSTANT EQU 10 ;用符号CONSTANT表示常数10 • VAR EQU 30H+99H ;用符号VAR表示表达式30H+99H • PURGE CONSTANT ;解除符号CONSTANT,以便重新定义 • CONSTANT EQU 20 ;用符号CONSTANT表示常数20 • DATA = 3 ;用符号DATA 表示3 • DATA = 4 ;把符号DATA改为表示4
汇编语言程序设计 • 简单程序设计入门 • 汇编语言程序在一些对内存储器容量和存取速度要求比较高的情况下,如I/O接口驱动程序、实时控制程序、系统软件等设计中常被使用,而且比用高级语言仿佛还要便当些。 • 其实,用汇编语言编写程序,首先确定算法,然后紧紧抓住每条指令的格式、功能以及数据的寻址方式,用户也可以编写出高质量的汇编语言程序。
1.寄存器的加法 • 下面给出了一个简单的汇编语言程序段,是用寄存器EAX、EBX、ECX和EDX实现加法运算,依此来说明寄存器加法是如何用汇编语言实现的。形成的32位的累加和被存放在EAX寄存器。 • ; 4个32位寄存器EAX,EBX,ECX与EDX内容相加,累加和存放在EAX内 • ┋ • ADD EAX,EBX ;EBX寄存器内容与 EAX寄存器内容相 • 加,结果存放在EAX上 • ADD EAX,ECX ;ECX寄存器内容与 EAX寄存器内容相加, • 结果存放在EAX上 • ADD EAX,EDX ;EDX寄存器内容与 EAX寄存器内容相加, • 结果存放在EAX上 • ┋
2.存储器与寄存器加法 • 用存储器中的数据与寄存器中的内容进行操作运算,是用存放在存储器的数据段内,其偏移地址为NUMB和NUMB+1的两个连续单元的字节数据,与AX寄存器的内容进行累加,其累加和存放在AX寄存器上。 • ;用NUMB与NUMB+l存储单元内的数据与AL寄存器内容进行求和,结果存放在AX中 • ┋ • MOV DI,OFFSET NUMB ;将偏移地址NUMB传送到DI寄存器 • MOV AX,1234H ;把常数1234H传送到AX寄存器 • ADD AX,[DI] ;AX寄存器内容与地址NUMB内的数据 • ;进行加运算,结果存放在AX寄存器 • ADD AX,[DI+1] ;AX寄存器内容与地址NUMB+1内的 • ;数据进行加运算,结果存放在AX寄存器
3.数组元素加法操作 • 数组,是存储器中顺序排列的一个数据表。假定一个名为ARRAY的一维数组,共有10个数组元素,且数组元素是字节数据,数组元素的下标是0~9。试用汇编语言编写一个程序,实现三个数组元素ARRAY(3)、ARRAY(5)、ARRAY(7)的累加。 • ;三个数组元素数据进行累加运算,累加结果存放在AX中 • ;注意该过程破坏了SI的内容 • ┋ • MOV AX, 0 ;由于累加和要存放在AX内,首先将其清0 • MOV SI, 3 ;将常数3传送到源变址寄存器SI • ADD AX, ARRAY[SI] ;AX寄存器数据与数组元素ARRAY(3)相加 • ;结果存放在AX寄存器 • ADD AX, ARRAY[SI+2] ;AX寄存器数据与数组元素ARRAY(5) • ; 相加结果存放在AX寄存器 • ADD AX,ARRAY[SI+4] ;AX寄存器数据与数组元素ARRAY(7)相加 • ;结果存放在AX寄存器
4.数组元素加法 • 下面程序段是32位的程序,采用的是比例变址寻址方式,求数组ARRAY中三个数组元素ARRAY(3)、ARRAY(5)、ARRAY(7)的累加和。且数组元素是16位的操作数,并把数组元素的和存放在寄存器EAX中。 • ;程序段是采用比例变址进行寻址的32位操作数的程序 • ┋ • MOV EBX,OFFSET ARRAY ;将数组地址ARRAY传送到寄存器EBX • MOV ECX,3 ;将常数3传送到ECX,ECX保存着数组元素的序号 • MOV EAX,[EBX+2*ECX] ;将数组元素ARRAY(3)的值传送到寄存器EAX • MOV ECX,5 ;将常数5传送到ECX,ECX保存着数组元素的序号 • ADD EAX,[EBX+2*ECX] ;数组元素ARRAY(3)与数组元素ARRAY(5)相加 • ;结果存放在寄存器EAX • MOV ECX,7 ;将常数7传送到ECX,ECX保存着数组元素的序号 • ADD EAX,[EBX+2*ECX] ;数组元素ARRAY(3)+ARRAY(5)+ARRAY(7) • ; 相加,结果存放在寄存器EAX
5. 乘法程序设计 • 下面这个程序段是实现寄存器BX上的数据与寄存器CX上的数据相乘的程序段。假设BX中存放的是数据55,在CX中存放的是数据110,两数进行乘法操作,产生的32位乘积存放在寄存器对DX-AX中。 • ;寄存器BX上的数据与寄存器CX上的数据相乘, • ;乘积存放在寄存器对DX-AX中 • ┋ • MOV BX, 55 ;将字数据55装到寄存器BX上 • MOV CX,110 ;将字数据110装到寄存器CX上 • MOV AX,CX ;将寄存器CX上的数据110,传送到寄存器AX上 • MUL BX ;寄存器AX上的数据与寄存器BX上的数据相乘 • ;结果存放在寄存器对DX-AX中
6. 除法程序设计 • 下面的程序段是两个16位有符号数的除法,即AX中的-100除以CX中的+9。执行除法之前,要用指令CWD将AX中的-100转换成寄存器对DX-AX中的-100,除法操作执行后,结果存放在寄存器对DX-AX对中,其中商-11存放在AX中,而余数-l则是被存放在DX中。 • ;寄存器AX中的-100除以寄存器CX中的+9,商存放在AX中, • 余数存放在DX中 • ┋ • MOV AX,-100 ;将有符号数-l00传送到寄存器AX • MOV CX,9 ;将有符号数+9传送到寄存器CX • CWD ;将AX中的-100转换成寄存器对DX-AX中的-100 • IDIV CX ;用寄存器对DX-AX中的-100,除以寄存器CX上的+9 • ;在AX中存放商-11,在DX中存放余数-l
完整的汇编源程序结构 DATA SEGMENT ;定义数据段 MEM1 DB 11H , 22H ┇ DATA ENDS CODE SEGMENT ;定义代码段 ASSUME CS:CODE ,DS:DATA START: MOV AX,DATA ┇ CODE ENDS END START ;程序结束
顺序结构程序设计 • 顺序结构的程序是完全按指令书写的先后顺序逐条执行的。这种结构的汇编程序既无分支、又无循环,只会自上而下地线性地顺序地运行,这种结构的汇编程序通常是比较简单的程序。 • 下面所展示出的程序就是一个顺序结构汇编程序的框架。 • Program 5.1 顺序结构汇编程序的框架 • .DOSSEG ; 连接时按DOS方式排列段 • .MODEL SMALL ; 程序存储模式: 小模式 • .486 ; 80486伪指令 • .STACK 300H ; 建立程序堆栈段:768字节 • .DATA ; 建立程序数据段 • DB 16 DUP(?) ; WINDOWS保留数据区:16字节 • ; 其它程序数据 • .CODE ; 建立程序代码段 • START: ; 程序开始执行地址 • MOV AX, @DATA • MOV DS, AX ; 设置数据段地址 • ; 插入实际程序代码 • MOV AH, 4CH • INT 21H ; 返回DOS • END START ; 程序结束
判定条件 判定条件 分支程序设计 • 分支程序结构可以用如图所示的两种形式表示。他们的结构分别相当于高级语言中的 IF-THEN-ELSE 语句和CASE语句,这种结构常用于根据不同的条件作出不同处理的情况。IF-THEN-ELSE 语句可以有两个分支,CASE语句则可以有多个分支。但不论是哪一种形式,他们的共同特点是:其运行方向是向前的,在确定的条件下,只能执行多个分支中的一个分支。
START: MOV AX, @DATA MOV DS, AX MOV EAX, X1 ; 取X1数值 CMP EAX, X2 ; 与X2比较 JE EQUAL ; 相等? JG GREAT ; X1大于X2 ? MOV DX, OFFSET MSG2 ; 比较结果: X1<X2 JMP OK GREAT: MOV DX, OFFSET MSG1 ; 比较结果: X1>X2 JMP OK EQUAL: MOV DX, OFFSET MSGE ; 比较结果: X1=X2 OK: MOV AH, 09H ; 显示比较结果 INT 21H MOV AH, 4CH INT 21H END START Program 5.3 分支结构的程序示例程序 ;显示两个数x1,x2的比较结果 .DOSSEG .MODEL SMALL ; 程序存储模式: 小模式 .486 ;80486伪指令 .STACK 300H .DATA DB 16 DUP(?) X1 DD 1000 ; 两个数X1,X2 X2 DD 2000 ; 数值可任意指定 MSG1 DB "X1>X2",13,10,"$" ; 比较结果分为大于、小于、等于三种情况 MSG2 DB "X1<X2",13,10,"$" ; MSGE DB "X1=X2",13,10,"$" ; .CODE
循环初始状态 循环初始状态 循环控制条件 循环体 循环控制条件 循环体 循环程序设计 在程序中,如果需要多次重复执行相同或相似的功能,就可以使用循环结构。 循环结构总是包含了三个部分: 1)初始化,设置循环执行的初始状态。 2)循环体,需要多次重复执行的部分。 3)循环条件,用于控制循环体的执行。循环体每次执行后,应该修改循环条件,使得循环能够在适当的时候终止执行。 (1)DO-WHILE 结构形式 (2)DO-UNTIL结构形式
AGAIN: CMP AX , [BX] JGE NEXT1 MOV AX , [BX] ;将大的数 ;放在AX之内 NEXT1: CMP DX , [BX] JLE NEXT2 MOV DX , [BX] ;将较小的 ;数放DX之内 NEXT2:INC BX INC BX LOOP AGAIN ;实现循环 MOV BIG , AX ;存放最大数 MOV LITLE , DX ;存放最小数 MOV AH , 4CH ;返回DOS INT 21H CODE ENDS END START 下面是循环程序设计一范例。其功能是选出一组数据中的最大者放到big单元;而将最小者放到little单元。 DATA SEGMENT A DW 88,89,92,78,76,69,63,96,60,100 ;一组数据 BIG DW ? LITTLE DW ? DATA ENDS CODE SEGMENT ASSUME CS:CODE ,DS:DATA START: MOV AX , DATA MOV DS , AX MOV BX , OFFSET A MOV AX , [BX] MOV DX , AX INC BX INC BX MOV CX , 9 ;循环次数放在CX之内
子程序 如果有一段程序在一个程序中需多次使用,或在多个程序中均需使用,可将这段程序单独存放,每当需用这段程序时,就用调用指令使程序转到这段程序去执行,执行完后再返回原来的程序。这样的一段程序就叫子程序或过程。而调用它的程序被称之为主程序或调用程序。 主程序向子程序转移被称之为子程序调用或过程调用,从子程序返回主程序则叫返回主程序。
START:MOV AX , DATA MOV DS , AX MOV BX , OFFSET A MOV SI , 0 AGAIN: MOV AL , [BX] ;边长放AL CMP AL , 0 ; 为0 则结束 JE EXIT CALL MULTI ;调用子程序 INC BX ;过渡到下一个边长 INC SI INC SI JMP AGAIN ;求下一正方形面积 EXIT: MOV AH , 4CH INT 21H CODE ENDS END START 下面展示出的是一汇编语言子程序设计,它的功能是求不同边长的正方形面积。 DATA SEGMENT A DB 8,9,2,7,6,5,0 ;一组边长,以0 结束 AREA DW 10 DUP(?) DATA ENDS CODE SEGMENT ASSUME CS:CODE , DS:DATA MULTI PROC ;定义一个求正方形面积的子程序 IMUL AL MOV AREA[SI] , AX ;边长在 AL中,面积放AREA数组 MOV AH , 2 MOV DL , 7 ;每算完一个则 ;响铃一次 INT 21H RET MULTI ENDP