Download presentation
Presentation is loading. Please wait.
Published by祭錡 项 Modified 7年之前
4
第四章 80x86汇编语言程序设计 第一节 汇编语言概述 第二节 汇编语言语句的组成 第三节 汇编语言的语句 第四节 宏汇编指令
第一节 汇编语言概述 第二节 汇编语言语句的组成 第三节 汇编语言的语句 第四节 宏汇编指令 第五节 编写完整的汇编语言程序 第六节 汇编语言程序设计
5
助记符——用便于记忆的英语单词表示的指令操作码。它反映了指令的功能和主要特征,便于人们理解和记忆。
第一节 汇编语言概述 机器语言——二进制数形式的指令和数据。 B0 64 是什么意思?这就是机器语言。既不直观,又不易理解和记忆. MOV AL,64H ;很容易记忆理解,这就是助记符。 助记符——用便于记忆的英语单词表示的指令操作码。它反映了指令的功能和主要特征,便于人们理解和记忆。
6
汇编语言——指令助记符,符号地址,标号,伪指令等语言元素的集合以及这些元素使用的规则。 用汇编语言编写的程序叫汇编语言源程序。
指令除了操作码以外,还有一个操作数问题。 操作数可能放在存储器中,这就涉及操作数的地址。程序中遇到转移指令或调用指令,也需要知道转移地址,若采用具体地址就很不方便,一旦有错,改动也很麻烦。于是人们采用标号或符号来代替地址,例: LP1: mov ax,VAR … loop LP1 汇编语言——指令助记符,符号地址,标号,伪指令等语言元素的集合以及这些元素使用的规则。 用汇编语言编写的程序叫汇编语言源程序。
7
高级语言 面向过程的语言,如C、C++、BASIC、PASCAL等 优点:更接近人类语言的语法习惯,易于掌握,便于建立数学模型和实现复杂算法
缺点:与机器语言无明显对应关系,因此编译出来的机器语言程序效率相对较低,占用内存多,执行时间长。
8
汇编程序 汇编源程序需翻译成机器语言,变成可执行文件,机器才能执行,这个翻译过程叫汇编。——高级语言中称该过程为“解释”或“编译”。执行翻译的程序称为“汇编程序”。 汇编语言源程序 汇编程序 机器语言目标程序 源程序的编译程序
9
汇编语言程序设计与执行过程 输入汇编语言源程序 源文件 .ASM 汇编(编译) 目标文件 .OBJ 链接 可执行文件 .EXE
调试 最终程序 编辑器: EDIT.exe 编程序: MASM.exe 连接程序:LINK.exe 调试程序:DEBUG.exe
10
一个简单的8086系统下的汇编语言程序: 数据段 代码段
DATA SEGMENT STRING DB ‘HELLO WORLD!’, 0DH, 0AH, ‘$’ DATA ENDS CODE SEGMENT ASSUME CS:CODE, DS:DATA BEGIN: MOV AX, DATA MOV DS, AX ;初始化数据段的段地址 MOV AH, 09H LEA DX, STRING;输出字符串 INT 21H MOV AH, 4CH INT 21H;调用4CH号系统功能返回DOS CODE ENDS END BEGIN 数据段 代码段
11
第二节 汇编语言语句的组成 一、字符集 汇编语言程序的语句中包含的元素 四、表达式及运算符 二、保留字与标识符 三、常量、变量与标号
12
一、字符集 允许使用的字符: 注意: 字母,包括大写字母A~Z和小写字母a~z; 数字,包括0~9;
特殊字符,包括:+ - * / =()[ ] < > ; , ‘ “ . — $ & 及空格、制表符、回车、换行等。 注意: 除了字符串,字母都是不区分大小写 一系列相连的空格、制表符效果相当于一个空格 一系列相连的回车换行相当于一次回车换行 分号“;”后一直到行尾的内容都是注释 字符“&”若用于某行的开头,则表示该行是上一行的续行
13
二、保留字与标识符 1、保留字 在汇编语言中有特定意义的词,可分为: 指令助记符及指令前缀 如:MOV、ADD、REP等 寄存器名
如:AX、EBX、CL等 伪指令助记符 如: DB、SEGMENT等 其他保留字,包括运算符、操作符等 如: EQ、LT、OFFSET、SEG等
14
2、标识符 标识符是程序员自己起的名字,如变量名、标号、段名、过程名等 标识符的命名规则:
标识符必须由字母、数字和几个特殊字符(包括 $ ? :)组成,而且第一个字符不能是数字(否则可能与16进制的数字混淆) 标识符不能与某个保留字相同,以免混淆 尽量用有意义的英文单词或缩写来命名,以增加程序的可读性
15
三、常量、变量与标号 1、常量 数字常量 二进制:以B结尾,如10101010B 八进制:以Q结尾,如123Q,67Q
十进制:以D结尾,“D”可省略,如1234D,5678 十六进制:以H结尾,A~F开头的数须在前面加“0” 如:1234H,0FFFFH 字符串常量 用单引号或双引号引起来的一个或多个ASCII字符 每个字符的值等于其ASCII码值 例:‘A’=41H一个字节,‘12’=31H、32H两个字节
16
2、变量 变量是存放在存储器中的操作数 可通过变量的名字来访问变量 变量具有三个属性: 段属性,即变量所在的段的基地址;
偏移量属性,即变量相对于段的起始地址的偏移量; 类型属性,包括BYTE(字节)、WORD(字)、DWORD(双字)
17
3、标号 标号是一条指令性语句的起始地址 标号具有三个属性: 段属性,即标号所在的段的基地址;
偏移量属性,即标号相对于段的起始地址的偏移量; 类型属性,包括NEAR(近程,即段内)、FAR(远程,即段间)
18
四、表达式及运算符 由常量、变量、标号和一些运算符、操作符构成的式子 表达式的值在汇编的过程中就已经被汇编程序计算出来 运算符的分类:
算术运算符 逻辑运算符 关系运算符 属性运算符 数值返回操作符
19
1、算术运算符 五种算术运算: 合法地址表达式:地址-地址(处在同个段中);地址±常数
加:+、 减:-、 乘:*、 除:/、 模:MOD 合法地址表达式:地址-地址(处在同个段中);地址±常数 ADDR1-ADDR2(假设两个地址处在同个段中) ADDR1+1 ADDR2-2 非法地址表达式:地址+地址;地址*地址;地址/地址;常量-地址;地址-地址(处在不同段中) ADDR1+ADDR2 ADDR1*ADDR2 ADDR1/2 100-ADDR1 SEG1_A-SEG2_B (假设两个地址处在不同段中)
20
2、逻辑运算符 五种逻辑运算: 只用于数字表达式中 例: 与AND、或OR、异或XOR、非NOT、逻辑左移SHL、逻辑右移SHR
MOV AL, B AND B ;AL← B MOV AX, B XOR B ;AX← B
21
3、关系运算符 六种关系运算符: 运算结果: EQ(Equal,相等) NE(Not Equal,不等) LT(Less Than,小于)
LE(Less than or Equal,小于或等于) GT(Great Than,大于) GE(Great than or Equal,大于或等于) 运算结果: 关系为真,则运算结果为0FFFFH 关系为假,则运算结果为0 如:MOV BX,1 EQ 2; 结果 BX=0 MOV AX,(3 LT 4) AND 1;结果 AX=1
22
(1)型重新指定操作符PTR 4、属性运算符 功能: 格式: 例: 类型 PTR 表达式 VAR_W DW 1234H
临时指定或修改存储器操作数的数据类型属性或地址类型属性 格式: 类型 PTR 表达式 例: VAR_W DW 1234H MOV AX,VAR_W ;AX←1234H MOV AL,BYTE PTR VAR_W ;AL←34H
23
PTR与EQU连用 作用: 定义与表达式类型不同的新变量名或新标号,但不分配新的存储单元 例: 数据段定义: 代码段:
DATA_B DB ,2,3,4 DATA_W EQU WORD PTR DATA_B 代码段: MOV AL,DATA_B ;AL←1 MOV AX,WORD PTR DATA_B ;AX←0201H MOV AX,DATA_W ;AX←0201H (第2、3条指令等价)
24
(2)类型指定操作符THIS 功能: 例1: 例2: 指定或说明变量或标号的类型 DATA_W EQU THIS WORD
DATA_B DB 1,2,3,4 MOV AL,DATA_B ;AL←1 MOV AX,WORD PTR DATA_B ;AX←0201H MOV AX,DATA_W ;AX←0201H 例2: ADDR_F EQU THIS FAR ADDR_N: MOV AX,1 JMP ADDR_F ;等价于:JMP FAR PTR ADDR_N
25
(3)短转移操作符SHORT 一般用在JMP指令 告诉汇编程序该JMP指令是一个短程转移指令 功能: 例: JMP SHORT LAB ……
26
(1)SEG、OFFSET 5、数值返回操作符 功能: 例如,对于代码段中的一条指令: SEG操作符用于求一个标号或变量所在段的基地址
2000H:1234H ADDR: INC CX ;段地址=2000H,偏移量=1234H 则有: MOV AX,SEG ADDR ;AX←2000H MOV AX,OFFSET ADDR ;AX←1234H ;与指令 “LEA AX,ADDR” 等价
27
(2)TYPE、LENGTH、SIZE 功能: TYPE:求变量的数值类型属性,即变量具有的字节数
BYTE:返回1;WORD:返回2;DWORD :返回4; NEAR:返回0FFH(-1);FAR:返回0FEH(-2) LENGTH:求变量所占用的内存单元数 用于由重复操作符DUP()定义的存储器变量 对于其他变量,LENGTH的返回值都是1 SIZE:计算变量所占存储器的总字节数 关系: SIZE = LENGTH × TYPE
28
例: DATA1 DW 1234H DATA2 DB ‘HELLO’ DATA3 DD 100 DUP(0);表示定义100个值为0的双字
MOV AL,TYPE DATA1 ;AL←2 MOV AL,TYPE DATA2 ;AL←1 MOV AL,TYPE DATA3 ;AL←4 MOV BL,LENGTH DATA1 ;BL←1 MOV BL,LENGTH DATA2 ;BL←1 MOV BL,LENGTH DATA3 ;BL←100 MOV CL,SIZE DATA1 ;CL←2×1=2 MOV CL,SIZE DATA2 ;CL←1×1=1 MOV CL,SIZE DATA3 ;CL←4×100=400
29
6、运算符的优先级 表达式计算顺序: 优先级顺序: 先处理优先级别高的运算符 对于优先级相等的运算符,则按从左至右的顺序进行处理
()、[](优先级最高) LENGTH、SIZE PTR、THIS、SEG、OFFSET、TYPE HIGH、LOW *、/、MOD、SHL、SHR +、- EQ、NE、LT、LE、GT、GE NOT AND OR、XOR SHORT(优先级最低)
30
第三节 汇编语言的语句 汇编语言由指令性语句和指示性语句组成
第三节 汇编语言的语句 汇编语言由指令性语句和指示性语句组成 指令性语句由CPU执行,每一条指令性语句都有一条机器码指令与其对应; 指示性语句由汇编程序执行。它指出汇编程序应如何对源程序进行汇编,如何定义变量、分配存储单元以及指示程序开始和结束等。指示性语句无机器码指令与其相对应。 指令性语句汇编时生成机器码; 指示性语句汇编时不生成机器码。
31
第三节 汇编语言的语句 一、指示性语句 格式([]里的内容可选): 名字:变量名、段名等,与指令地址无关,后面不能加冒号
第三节 汇编语言的语句 一、指示性语句 格式([]里的内容可选): [名字] 伪指令符 操作数,操作数,…… [;注释] 名字:变量名、段名等,与指令地址无关,后面不能加冒号 伪指令符:指定汇编程序要完成的具体操作 操作数:常量、变量或表达式等 注释:说明、解释当前语句的作用 31
32
1、数据定义伪指令 功能: 格式: 六种数据定义伪指令: 为变量分配存储空间 DB(字节定义):每个操作数占1个字节
[变量名] 伪指令符 操作数,操作数,…… [;注释] 六种数据定义伪指令: DB(字节定义):每个操作数占1个字节 DW(字定义):每个操作数占1个字,即2个字节 DD(双字定义):每个操作数的长度为双字,即4个字节
33
例: 可同时定义多个数据: NUM DW 12H,-1 ;定义2个字 STRING DB ‘HELLO’,0DH,0AH;定义字符串
省略变量名: BUF DB ,10,100 DB ;省略变量名 ;但该数据仍可通过“BUF+3”访问 无初始化数据定义:用问号“?”代替操作数 BUFFER DB ,?,?,? ;定义4个字节 ;其中后3个字节不初始化
34
DUP操作符: 格式: 重复的次数 DUP(重复的内容) 例: ARRAY DB 3 DUP(1,2)
BUF_W DW 100 DUP(?) ;定义100个字,但不初始化 DUP的嵌套使用: ARRAY2 DB 2 DUP(1,3 DUP(0)) ;等价于:ARRAY2 DB 1,0,0,0,1,0,0,0
35
只能用DW、DD定义 DW:变量/标号的偏移量 DD:变量/标号的段地址和偏移量 例: 地址表达式作为操作数:
DATA1 DW ADDR1+1 ;把ADDR1偏移量加1后存放到DATA1对应的存储单元中 DATA2 DD DATA1 ;把DATA1的偏移量和段地址存放到DATA2对应的存储单 元中,其中偏移量放低地址,段地址放高地址。
36
地址计数器“$” “$”:表示到目前为止该段已经使用的地址空间 例1: 设VAR1地址偏移量为1000H,则: VAR1 DB 100H DUP (?) 之后,$=1100H,因此: ADDR1 DW $ 等价于“ADDR1 DW 1100H”,也等价于“ADDR1 DW ADDR1” 例2: STRING DB ‘ABC’ LEN DW $-STRING ;LEN的值为STRING的长度
37
2、符号定义伪指令 (1)等价伪指令EQU 格式: 功能: 例: 符号名 EQU 表达式 为常量、表达式及其他各种符号定义一个别名
NUM EQU ;给数值定义符号名 NUM2 EQU NUM+10 ;给12+10=22定义符号名 ADDR EQU DS:[BX+SI] ;给寻址表达式定义符号名 COUNT EQU CX ;给寄存器CX定义符号名 CLEAR EQU XOR AX,AX ;给指令定义符号名
38
(2)解除伪指令PURGE 格式: 作用: 例: PURGE 符号名,符号名,……
EQU伪指令不能直接对一个符号名重定义,必须先用PURGE解除 例: COUNT EQU CX PURGE COUNT COUNT EQU CL
39
(3)等号“=”伪指令 格式: 功能: 例: 符号名 = 表达式 为常量、表达式及其他各种符号定义一个等价的符号名
符号名 = 表达式 功能: 为常量、表达式及其他各种符号定义一个等价的符号名 允许对符号名多次重复定义,且以最后一次定义的值为准 例: CONST = ;给数值1定义符号名CONST ADDR = [BP+DI] ;给寻址表达式定义符号名ADDR CONST = ;重定义CONST
40
3、段定义伪指令 格式: 段名 SEGMENT [定位方式][组合方式][使用类型][‘类名’] 功能:定义一个段 例:
…… ;段中的内容 段名 ENDS 功能:定义一个段 例: DATA SEGMENT VAR DB ? DATA ENDS 得到段地址的两种方法: MOV AX,DATA MOV AX,SEG VAR
41
(1)定位方式 作用: 分类: 设置该段在存储器中的起始边界 BYTE:可从任意的绝对地址开始,如12345H。
WORD:可从偶地址开始。如12346H。 DWORD:可以任何一个双字的边界开始,如12348H。 PARA(缺省方式):必须从存储器的16字节的边界开始,如12340H(最后一位为0)。 PAGE:起始地址必须能被256整除,如12300H。
42
(2)类名 如:在模块1中有段定义: seg1 SEGMENT PARA STACK ‘stack’ … seg1 ENDS
用单引号括起来的字符串 连接定位时,具有相同类名的逻辑段会被组合在一起 如:在模块1中有段定义: seg1 SEGMENT PARA STACK ‘stack’ … seg1 ENDS 在模块2中有段定义: seg2 SEGMENT PARA STACK ‘stack’ seg2 ENDS 则连接时这两个段被安排在一起。
43
(3)使用类型(386以上) USE16:缺省类型,表示该段采用16位寻址方式,段基址和段内偏移量都是16位 USE32:表示该段采用32位寻址方式,段选择子为16位,段内偏移量则是32位
44
(4)组合方式 作用: 分类: 指定同类名段的组合方法 PRIVATE(缺省方式):不组合 PUBLIC:同类名段按照前后次序连接在一起
COMMON:与其他模块中的同类名段有相同的起始物理地址 STACK:与其他模块中的同类名段用覆盖的方式连接,从高地址开始覆盖 MEMORY:该段必须放在同类名的各个段中的最后 AT表达式:直接指定该段的段地址
45
4、假定伪指令ASSUME 格式: 功能: 例: ASSUME 段寄存器:段名[,段寄存器:段名,……] 告诉汇编程序段与段寄存器的对应关系
DATA SEGMENT VAR1 DB ? DATA ENDS CODE SEGMENT ASSUME CS:CODE,DS:DATA BEGIN: …… ASSUME指令:假定CS为代码段,DS为数据段
46
5、地址对准伪指令 ORG 格式: 功能: 例: ORG 数值表达式 用于指定下一个指令或数据在段内的起始地址 LAB1: PUSH AX
ORG 2000H LAB2: MOV AL,34 则LAB2的地址偏移量为2000H。
47
6、过程定义伪指令PROC、ENDP 功能: 格式: 过程属性: 定义一个过程 NEAR:缺省属性,表示段内调用/返回
…… 返回指令RET 过程名 ENDP 过程属性: NEAR:缺省属性,表示段内调用/返回 FAR:表示段间调用/返回
48
7、源程序结束伪指令END 格式: 功能: 例: END 标号 标号的地址必须是程序的入口地址,即第一条可执行语句
告诉汇编程序,源程序到此已经结束 告诉汇编程序,源程序的入口地址是多少 例: CODE SEGMENT ASSUME CS:CODE BEGIN: MOV AX,0 ;第一条指令语句 …… CODE ENDS END BEGIN ;源程序到此为止
49
8、高级数据结构定义伪指令 (1)结构类型数据定义伪指令STRUC/ENDS 结构的定义: 结构名 STRUC
…… ;DB、DW之类的数据定义伪指令语句序列 结构名 ENDS 例: DATA STRUC X DW 0 Y DB 1 Z DD 2 DATA ENDS 结构定义时并没有分配存储空间
50
结构变量的申请与赋初值 结构的访问 结构变量名 结构名 <初始值表> 例: NEW _DATA DATA <,,0>
结构变量名 结构名 <初始值表> 例: NEW _DATA DATA <,,0> ;申请结构变量“NEW _DATA”,其中X=0,Y=1,Z=0 ;缺省的初始值表示使用定义时的预设值 结构的访问 结构变量名.字段名 MOV AX,NEW_DATA.X MOV BL, NEW_DATA.Y
51
(2)记录定义伪指令RECORD 记录的定义 记录名 RECORD 字段说明,字段说明…… 其中,字段说明的格式是:
字段名:宽度 [=预赋值] 例: REC RECORD A:8=12H, B:5=10, C:3 定义了一个字,其中: A占高8位,预赋值= B B占接下来5位,预赋值=10 C占低3位,预赋值为空
52
00010010B 00001B 010B 记录变量的的申请与赋初值 格式: 记录变量名 记录名 <初始值表> 例:
记录变量名 记录名 <初始值表> 例: REC_VAR REC <,1,2> 申请了一个变量REC_VAR,其值为: B B B 预赋值12H 初始化为 初始化为2
53
记录的访问 WIDTH操作符: 求记录或记录中某个字段的宽度(即位数)。格式: WIDTH 记录名或记录字段名 记录字段名:
求该字段的最低位右移到所在记录最右边所需的移位次数 MASK操作符: 返回一个8位或16位二进制数,这个数中,对应于指定字段的各位均是1,其余各位均是0。格式: MASK 记录字段名 例: MOV AX,REC_VAR ;AX← B MOV BL,WIDTH REC_VAR ;BL←REC_VAR的总宽度16 MOV BH,WIDTH A ;BH←字段A的宽度8 MOV CL,B ;CL←3 MOV DX,MASK C ;DX← B
54
二、指令性语句 NIL指令 格式: NIL指令并不属于80x86的指令系统 只用于宏汇编中 作用:保留一个空行 例:
[标号:] 指令助记符 操作数,操作数,…… [;注释] NIL指令 NIL指令并不属于80x86的指令系统 只用于宏汇编中 作用:保留一个空行 例: L: NIL ;留下一个空行,方便以后对程序的修改 LOOP L 等价于:L:LOOP L
55
DOS系统功能调用介绍 系统功能调用——由OS提供的一组实现特殊功能的子程序供程序员在程序中调用,以减轻编程工作量。
系统功能调用有两种,一种称为DOS功能调用,另一种称为BIOS功能调用。 用户程序在调用这些系统服务程序时,不是用CALL命令,而是采用软中断指令INT n来实现。 在DOS系统中,功能调用都是用软中断指令INT 21H来实现的。
56
格式: 将调用功能所需的入口参数存入指定的寄存器或存储单元中; 在寄存器AH中存放所要调用功能的功能号; 执行INT 21H指令,转入中断子程序; 中断子程序运行完后,从指定的寄存器或存储单元中取得出口参数。
57
(1)单字符显示(功能号:02H) (2)单字符输入(功能号:01H、07H) 功能:将指定的字符送到显示器显示 例:
MOV DL,‘A’ ;入口参数,DL存放字符的ASCII码 MOV AH,02H ;02H号功能调用 INT 21H ;显示字符‘A’ (2)单字符输入(功能号:01H、07H) 功能:从键盘输入字符→AL MOV AH,01H;01H号键盘输入功能调用 INT 21H ;AL←输入字符的ASCII码,并显示字符 07H号功能调用与01H号相似,但输入的字符没有在屏幕上显示
58
(3)检测键盘状态(功能号:0BH) 功能: RUN:…… ;循环运行的程序段 …… MOV AH,0BH ;0BH号功能调用
检测当前时刻键盘是否有键按下。如果有,则出口参数AL=0FFH,否则AL=0。该功能不清除输入缓冲。 例:循环运行程序段,直到有按键按下为止 RUN:…… ;循环运行的程序段 …… MOV AH,0BH ;0BH号功能调用 INT H ;检测键盘状态 CMP AL,0 JZ RUN ;AL=0表示没有键按下 MOV AH,01H ;没有清除缓冲,仍可读到按键 INT H
59
(4)直接控制台I/O(功能号:06H) 功能: 输入 / 输出字符:
入口参数DL=0FFH:检测当前时刻键盘是否有键按下。如果有,则出口参数AL=输入的字符,ZF=0,清除输入缓冲区;如果没有,则ZF=1。 入口参数DL≠0FFH:将DL中的ASCII码送显示器上显示 例:循环运行程序段,直到有按键按下为止 RUN:…… ;循环运行的程序段 …… MOV AH,06H ;06H号功能调用 MOV DL,0FFH ;DL=0FFH,输入功能调用 INT H ;检测键盘状态 JZ RUN
60
(5)字符串显示(功能号:09H) 功能: 字符串的首地址→DS:DX中, 字符串一定要以字符‘$’作为结尾标志 例:
将数据段中的字符串输出到屏幕上 字符串的首地址→DS:DX中, 字符串一定要以字符‘$’作为结尾标志 例: DATA SEGMENT STRING DB ‘HELLO’,0DH,0AH,‘$’;需以‘$’结尾 DATA ENDS 代码段: MOV AX,DATA MOV DS,AX ;DS←字符串所在段的段地址 LEA DX,STRING ;DX←字符串首地址的偏移量 MOV AH,09H ;09H号功能调用 INT 21H ;在屏幕上显示“HELLO”
61
(6)字符串输入(功能号:0AH) 功能:字符串输入,回车键结束 入口参数: DS:DX:缓冲区首地址 (DS:DX):允许输入的最多字符数
例: BUF DB 10H,100 DUP(?);输入字符数不超过16 MOV AX,DATA MOV DS,AX ;DS←缓冲区所在段的段地址 LEA DX,BUF ;DX←缓冲区首地址的偏移量 MOV AH,0AH ;0AH号功能调用 INT H ;输入字符串 若输入“123”,则BUF中的内容为: 10H,03H(输入3个字符),31H,32H,33H,0DH(回车)
62
(7)打印输出(功能号:05H) (8)结束调用(功能号:4CH) 功能:将DL寄存器中的字符送打印机打印 例:
MOV DL,‘A’ ;需打印的字符‘A’ MOV AH,05H ;05H号功能调用 INT 21H ;送打印机打印 (8)结束调用(功能号:4CH) 功能:终止当前程序,并返回到DOS中 MOV AH,4CH INT 21H
63
第四节 宏汇编指令 一、宏操作伪指令 宏定义伪指令 MACRO、ENDM 取消宏定义伪指令 PURGE
第四节 宏汇编指令 一、宏操作伪指令 宏定义伪指令 MACRO、ENDM 取消宏定义伪指令 PURGE 重复伪指令 REPT、IRP、IRPC 局部符号伪指令 LOCAL
64
1、宏定义伪指令MACRO、ENDM 格式: 例1: 宏名 MACRO [形式参数1,形式参数2,……] …… ;宏体
…… ;宏体 ENDM ;宏定义结束 例1: OUTPUT MACRO MOV AH,02H INT 21H ENDM 则: OUTPUT 等价于 “MOV AH,02H,INT 21H”
65
例2: OUTPUT MACRO ASC ;“ASC”为形式参数 MOV DL,ASC MOV AH,02H INT 21H ENDM 则:
OUTPUT 30H 等价于: MOV DL,30H
66
2、取消宏定义伪指令PURGE 功能: 使用MACRO定义的宏,如果不再需要,就可以用PURGE来注销 格式:
例: PURGE OUTPUT
67
3、重复伪指令REPT、IRP、IRPC 格式: 功能: 例如,下面的宏能将AL中的值逻辑左移4位: REPT REPT 表达式
…… ;宏体 ENDM 功能: 重复执行宏体中的语句,重复次数为表达式的值。 例如,下面的宏能将AL中的值逻辑左移4位: REPT 4 SHL AL,1
68
例,把AX、BX、CX、DX都压入栈中:
IRP 格式: IRP 形式参量,<参数,参数,……> …… ;宏体 ENDM 功能: 重复执行宏体,重复的次数是由参数的个数决定 例,把AX、BX、CX、DX都压入栈中: IRP REG,<AX,BX,CX,DX> PUSH REG
69
格式: 功能: 例如: IRPC IRPC 形式参量,字符串 …… ;宏体 ENDM
…… ;宏体 ENDM 功能: 重复执行宏体,其参数列表是字符串,一个字符为一个参数 例如: IRPC NUM,1234 ;“1234”表示4个参数1、2、3、4 DB NUM 等效于:DB 1,2,3,4
70
4、局部符号伪指令LOCAL 格式: 功能: 例: 正确: 错误: IRP REG,<AX,BX>
将宏中的标号定义为局部符号,避免重复 例: 正确: IRP REG,<AX,BX> LOCAL LAB LAB: PUSH REG ENDM 展开后: ??0000: PUSH AX ??0001: PUSH BX 错误: IRP REG,<AX,BX> LAB: PUSH REG ENDM 展开后: LAB: PUSH AX LAB: PUSH BX (LAB重复使用,出错)
71
二、条件汇编 格式: 功能: IFxx <条件表达式> …… ;条件块1 [ELSE] …… ;条件块2 ENDIF
…… ;条件块1 [ELSE] …… ;条件块2 ENDIF 功能: 根据某个表达式的真假,决定是否对指定的程序段进行编译
72
第五节 编写完整的汇编语言程序 一、汇编语言程序与MS-DOS 二、一般的汇编语言程序的整体框架 三、模块化程序设计的思想
73
一、汇编语言程序与MS-DOS 1、DOS的装入功能 确定用于存放程序的内存地址空间
建立程序段前缀PSP(Program Segment Prefix) 100H个字节,存放程序有关信息及进程间的控制信息 最开始的两个字节是一条INT 20H软中断指令 在PSP后装入可执行程序: 数据段 附加段 代码段 堆栈段
74
初始化各个相关寄存器的值: DS、ES:PSP所在段的段地址 CS、IP:程序的入口地址 SS初始化为堆栈段的段地址 SP指向堆栈段的栈底
入口地址 = 第一条可执行语句的段地址和偏移量 这个地址是从END语句中标号的地址属性得到的 SS初始化为堆栈段的段地址 SP指向堆栈段的栈底
75
2、DOS的返回 方法一: 执行PSP中的“INT 20H”指令: CS←PSP的段地址 IP←0 具体过程: 程序开头:
PUSH DS ;开始时(DS)=PSP的段地址 MOV AX,0 PUSH AX ;“0”入栈 程序过程,要求PUSH与POP配对 程序结束: RET ;CS←PSP的段地址,IP←0
76
例: CODE SEGMENT ASSUME CS:CODE MAIN PROC FAR BEGIN: PUSH DS ;PSP的段地址入栈
MOV AX,0 ;INT 20H的偏移量为0 PUSH AX ;把偏移量入栈 …… RET ;IP←0,CS←PSP段地址 MAIN ENDP CODE ENDS END BEGIN
77
方法二: 调用DOS系统的4CH 功能,实现DOS返回: MOV AH,4CH INT 21H 例: CODE SEGMENT
ASSUME CS:CODE BEGIN: …… …… MOV AH,4CH ;返回DOS INT 21H CODE ENDS END BEGIN
78
二、一般的汇编语言程序的整体框架 数据段、附加段 注释 堆栈段 END伪指令 ASSUME伪指令 代码段
79
源程序结构框架 框架一: 数据段 堆栈段 DATA SEGMENT ;数据段 …… ;定义变量、缓冲区等 DATA ENDS
…… ;定义变量、缓冲区等 DATA ENDS STACK SEGMENT PARA STACK ‘STACK’ ;堆栈段部分 DB XXXX DUP(?) ;定义堆栈的长度 STACK ENDS CODE SEGMENT ;代码段部分 ASSUME CS:CODE,DS:DATA,SS:STACK,ES:DATA MAIN PROC FAR BEGIN: PUSH DS MOV AX,0 ; 为RET提供转移地址 PUSH AX 数据段 堆栈段
80
MOV AX,DATA MOV DS,AX ;初始化段寄存器DS、ES MOV ES,AX …… ;程序部分 RET ;返回DOS MAIN ENDP PROC_1 PROC NEAR/FAR …… ;定义其他过程 RET PROC_1 ENDP CODE ENDS END MAIN
81
框架二: 采用“4CH”功能返回:(代码段部分) CODE SEGMENT ;代码段 ASSUME CS:CODE,DS:DATA,
& SS:STACK,ES:DATA BEGIN: MOV AX,DATA MOV DS,AX ;初始化DS、ES MOV ES,AX …… ;程序部分 MOV AH,4CH ;4CH号功能调用 INT 21H ;返回DOS CODE ENDS END BEGIN
82
三、模块化程序设计的思想 1、模块命名伪指令NAME、TITLE 2、逻辑段与物理段 格式: 作用: 为模块命名,指示给连接程序进行连接用
编译连接时,同类逻辑段将组合成一个大的物理段
83
3、同类名的组合方式 PRIVATE(缺省方式):不组合 PUBLIC:同类名段按照前后次序连接在一起
COMMON:与其他模块中的同类名段有相同的起始物理地址 STACK:与其他模块中的同类名段用覆盖的方式连接,从高地址开始覆盖 MEMORY:该段必须放在同类名的各个段中的最后 AT表达式:直接指定该段的段地址
84
4、模块之间的通信 格式: 功能: PUBLIC与EXTRN: PUBLIC 标识符,标识符,……
85
例: 模块1: NAME MOD1 PUBLIC VAR1 ;公用标识符VAR1
DATA1 SEGMENT PARA PUBLIC ‘DATA’ VAR1 DB ? ;字节变量VAR1 DATA1 ENDS 模块2: NAME MOD2 EXTRN VAR1:BYTE ;说明VAR1是字节 CODE2 SEGMENT PARA PUBLIC ‘CODE’ …… MOV AL,VAR1 ;访问MOD1中的字节变量VAR1
86
第六节 汇编语言程序设计 一、程序设计基本方法 分析实际问题,确定基本思路及程序算法 绘制程序流程图 根据流程图编写程序 调试程序
87
1、流程图 起止框:表示程序的开始和结束 工作框:说明该步骤的功能 判断框:说明判断的条件 调用框:说明调用过程的名字、参数等
连线: 表示程序的走向 功能 条件? 子程序 起止框 工作框 条件框 调用框 连线
88
2、程序的基本结构形式 顺序结构 分支结构 按直线顺序执行程序 含判断语句,根据判断结果选择分支 例: CMP AL,BL
JZ L1 ;相等 L2: …… ;不等 JMP NEXT L1: …… NEXT:…… 程序段1 程序段2 程序段3 顺序结构 条件? 程序段1 程序段2 分支结构 Y N
89
(3)循环结构 初始化部分 循环体部分 循环条件判断部分 例: MOV CX,100 ;初始化部分 L: …… ;循环体开始 ……
DEC CX ;修改循环变量 JNZ L ;循环条件判断 条件? 循环体 初始化 循环结构 Y N
90
(4)子程序结构 寄存器的保护与恢复 主程序与子程序之间的参数传递 子程序可嵌套调用
在程序中需要多次出现的程序段,可定义为一个子程序,在主程序需要的时候就可以直接调用它 寄存器的保护与恢复 主程序与子程序之间的参数传递 子程序可嵌套调用 程序段1 程序段2 过程调用 子程结构
91
子程序嵌套
92
二、程序设计举例 (1)顺序结构--32位无符号数相乘 H1 L1 H2 L2 L2×L1 L2×H1 H2×L1 H2×H1 64位结果
思路:分为高字部分和低字部分,模拟笔算的方法,做4次16位的乘法运 算,得到4个部分和A、B、C、D,再加起来得到结果 H1 L1 H2 L2 L2×L1 L2×H1 H2×L1 H2×H1 64位结果 被乘数 乘数 部分和A 部分和B 部分和C 部分和D × + 92
93
32位无符号数相乘流程图 开始 计算部分和C= 计算部分和A= C的低字部分叠加至RES+2 C的高字部分叠加至RES+4
计算部分和B= A的低字部分 RES A的高字部分 RES+2 B的低字部分叠加至RES+2 B的高字部分叠加至RES+4 计算部分和C= 计算部分和D= C的低字部分叠加至RES+2 C的高字部分叠加至RES+4 D的低字部分叠加至RES+4 D的高字部分叠加至RES+6 结束 开始 32位无符号数相乘流程图
94
DATA SEGMENT MUL1 DW 5678H, 1234H ;被乘数 H MUL2 DW 789AH, 3456H ;乘数 AH RES DW 4 DUP(0) ;存放64位结果,初始化为0 DATA ENDS CODE SEGMENT ASSUME CS:CODE, DS:DATA MAIN PROC FAR PUSH DS MOV AX, 0 PUSH AX MOV AX, DATA MOV DS, AX 94
95
;计算部分和A=L2×L1 MOV AX, MUL2 ;AX←L2 MUL MUL1 ;(DXAX)←L2×L1 MOV RES, AX ;保存A的低字部分 MOV RES+2, DX ;保存A的高字部分 ;计算部分和B=L2×H1 MUL MUL1+2 ;(DXAX)←L2×H1 ADD RES+2, AX ;叠加B的低字部分 ADC RES+4, DX ;叠加B的高字部分 ;计算部分和C=H2×L1 MOV AX, MUL2+2 ;AX←H2 MUL MUL1 ;(DXAX)←H2×L1 ADD RES+2, AX ;叠加C的低字部分 ADC RES+4, DX ;叠加C的高字部分 95
96
相乘结果: 03B8C7B8E8544430H ;计算部分和D=H2×H1 MOV AX, MUL2+2 ;AX←H2
MUL MUL1+2 ;(DXAX)←H2×H1 ADD RES+4, AX ;叠加D的低字部分 ADC RES+6, DX ;叠加D的高字部分 RET MAIN ENDP CODE ENDS END MAIN 相乘结果: 03B8C7B8E H 96
97
(2)分支结构—符号函数的实现
98
开始 初始化指针、循环次数 读入 x的值 x AL=0FFH AL=00H AL=01H 保存AL,修改指针 完成? 结束 <0 >0 =0 N Y
99
DATA SEGMENT X DB 12H,34H,00H,0FFH,0ABH ;X的值 COUNT EQU $-X ;X的个数 SGNX DB COUNT DUP(?) ;保存结果 DATA ENDS CODE SEGMENT ASSUME CS:CODE,DS:DATA,ES:DATA MAIN PROC FAR PUSH DS MOV AX,0 PUSH AX MOV AX,DATA MOV DS,AX MOV ES,AX LEA SI,X ;初始化源指针 LEA DI,SGNX ;初始化目的指针 MOV CX,COUNT ;循环次数
100
AGAIN:LODSB ;读入X的值 OR AL,AL ;把X的特征反映在标志寄存器上 JZ ZERO ;如果ZF=0,则说明X=0 JS MINUS ;如果SF=1,则说明X<0 MOV AL,01H ;否则X>0,所以sgn(x)=1 JMP NEXT ZERO:MOV AL,00H ;X=0,所以sgn(x)=1 MINUS:MOV AL,0FFH ;X<0,所以sgn(x)=-1 NEXT:STOSB LOOP AGAIN RET MAIN ENDP CODE ENDS END MAIN
101
(3)循环结构--显示二进制数的ASCII码形式
在内存中有几个8位的二进制数,编写程序将它们转换成二进制数的ASCII码,并输出到屏幕上,例如对于字节12H,转换后能在屏幕上显示“ B”
102
开始 初始化指针SI、计数值CX DL=30H BH逻辑左移1位 N CF=0? Y 显示字符 BL减1 BL=0? SI加1,CX减1
转换完成? DL加1 N Y 结束
103
DATA SEGMENT NUM DB 12H,34H,0ABH,0CDH ;需显示的字节 COUNT EQU $-NUM ;字节数 AFTER DB 'B',0DH,0AH,'$' ;‘B’、回车换行 DATA ENDS CODE SEGMENT ASSUME CS:CODE, DS:DATA MAIN PROC FAR PUSH DS MOV AX, 0 PUSH AX MOV AX, DATA MOV DS, AX 103
104
LEA SI, NUM ;数据的地址 MOV CX, COUNT ;字节数 AGAIN: MOV BH, [SI] ;需显示的数←BH MOV BL, 8 ;左移8次 PRINT: MOV DL, 30H SHL BH, 1 ;逻辑左移1位 JNC ZERO ;CF=0,则DL=30H INC DL ;CF=1,则DL=31H ZERO: MOV AH, 02H INT 21H ;显示‘0’或‘1’ DEC BL ;是否8个位都显示 JNZ PRINT ;否,则继续 LEA DX, AFTER ;显示‘B’、回车换行 MOV AH, 09H INT 21H
105
INC SI LOOP AGAIN ;循环显示所有字节 RET MAIN ENDP CODE ENDS END MAIN 运行结果: B B B B
106
(4)子程序结构--显示16进制数的ASCII码形式
在内存中有几个16位的二进制数,编写程序将它们转换成16进制数的ASCII码,并输出到屏幕上,如对于数字1234H,须将其转换成“1”、“2”、“3”、“4”四个字符,并分别送显示器显示 编程时,把对每个二进制数的处理写成一个子程序SHOW_W ,在这个子程序中,将二进制数每4位分成一段,每段又调用子程序SHOW_1 ,转换成ASCII码并输出
107
读取高8位 前4位 SHOW_1 后4位 读取低8位 显示’H’,换行 返回 (b) SHOW_W >9? DL+30H DL+7H 显示字符 (c) SHOW_1 N Y 二进制转16进制ASCII码的程序流程图 初始化SI CX←个数 SHOW_W 完成? 开始 结束 (a) MAIN
108
DATA SEGMENT NUM DW 1234H, 5678H, 9ABCH, 0DEF0H ;要显示的数字(字) LTH_W DW ($-NUM)/2 ;数字的个数(每个数占2字节) AFTER DB ‘H’, 0DH, 0AH,‘$’ ;每个数后面显示“H”然后回车换行 DATA ENDS STACK SEGMENT PARA STACK 'STACK' DB 100 DUP(?) ;堆栈长度 STACK ENDS CODE SEGMENT ASSUME CS:CODE, DS:DATA, SS:STACK MAIN PROC FAR PUSH DS MOV AX, 0 PUSH AX ;保存DOS返回指令的地址 MOV AX, DATA MOV DS, AX ;初始化DS MOV CX, LTH_W LEA SI, NUM
109
L: CALL SHOW_W ;调用子程序显示一个数字
INC SI INC SI ;一个数字占用2字节 LOOP L RET MAIN ENDP SHOW_W PROC ;子程序,能将[SI]中的16位数字显示出来 PUSH CX ;保护CX MOV DL, [SI+1] ;先处理高8位 MOV CL, 4 SHR DL, CL ;前4位 CALL SHOW_1 ;显示前4位的16进制数 MOV DL, [SI+1] AND DL, 0FH ;后4位 CALL SHOW_1 ;显示后4位的16进制数
110
MOV DL, [SI] ;再处理低8位 MOV CL, 4 SHR DL, CL ;前4位 CALL SHOW_1 ;显示前4位的16进制数 MOV DL, [SI] AND DL, 0FH ;后4位 CALL SHOW_1 ;显示后4位的16进制数 LEA DX, AFTER MOV AH, 09H INT 21H ;显示数字后面的“H”,并回车、换行 POP CX ;恢复CX RET SHOW_W ENDP
111
SHOW_1 PROC CMP DL, 9 JBE NEXT ADD DL, 7 ;如果大于9,则需加37H,如‘A’=41H= H NEXT: ADD DL, 30H;如果不大于9,则需加30H,如‘1’=31H=1+30H MOV AH, 02H INT 21H ;显示一位16进制数 RET SHOW_1 ENDP CODE ENDS END MAIN 程序运行结果,屏幕上显示: 1234H 5678H 9ABCH DEF0H
112
其他例子: 逻辑尺控制程序 例:对BUF中16个字节进行处理: 将第1、3、7、12、16个数据的值减2 将其它数据的值加3 利用逻辑尺:
(AX) = B AX逻辑左移1位 移出的位 = 0:BUF[SI]的值-2; 移出的位 = 1:BUF[SI]的值+3; 循环上一步16次
113
开始 初始化指针、循环次数 读入逻辑尺的值 读入一个数据 左移逻辑尺 数据的值-2 数据的值+3 结束 N Y CF=0?
保存数据,修改指针、循环次数 循环完成? 结束 N Y
114
DATA SEGMENT BUF DB 12,23,34,45,56,67,78,89,98,87,76,65,54,43,32,21 RES DB 16 DUP(?) ;存放结果的缓冲区 LOG_RUL DW 5DEEH ;逻辑尺 DATA ENDS CODE SEGMENT ASSUME CS:CODE, DS:DATA, ES:DATA MAIN PROC FAR PUSH DS MOV AX, 0 PUSH AX MOV AX, DATA MOV DS, AX MOV ES, AX
115
LEA SI, BUF LEA DI, RES MOV BX, LOG_RUL ;读入逻辑尺常数 MOV CX, 16 ;循环次数 AGAIN: LODSB ;读入温度值 SHL BX, 1 ;逻辑尺左移 JC PROC1 ;如果CF=1则转“+3”程序段 PROC0: SUB AL, 2 ;否则CF=0,进行“-2”运算 JMP NEXT PROC1: ADD AL, 3 ;“+3”运算 NEXT: STOSB ;处理完毕保存结果 LOOP AGAIN ;循环处理 RET MAIN ENDP CODE ENDS END MAIN
116
本章结束!
Similar presentations