第04章汇编语言程序设计

Download Report

Transcript 第04章汇编语言程序设计

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