第三章 汇编语言与汇编程序
机器语言 —计算机能够直接识别并执行的二进制机器指令序列
优点,开销小、运行速度快 ;
缺点:难以编写和理解,编程效率很低。
汇编语言 ( Assembly Language) —用助记符号表示机器指令
代码、变量地址,标号等的符号指令序列。
优点,易记、易理解,易编写程序,大大提高了编程效率 ;
问题:需要将助记符号翻译为机器语言。
汇编语言源程序,用汇编语言 编写的程序 。
汇编程序,将助记符号翻译为机器语言的 语言处理程序,以便
计算机能够识别。
汇编,将助记符号 翻译 为机器语言的 过程 。
理解以上几个名词概念:
汇编语言、汇编语言源程序、汇编程序、汇编
3.1 汇编程序功能及上机过程
3.1.1 汇编程序功能
汇编程序的 主要功能 如下:
( 1) 检测语法错 显示错误信息
( 2) 源程序文件 二进制目标文件 ( 并输出 *.LST文件 )
( 3) 展开宏指令
一般汇编程序都应具有如下功能,
? 宏汇编功能
? 支持地址和数据的符号表示
? 支持内存管理
? 支持程序的模块化组织
? 支持多种类型的数据表示等
汇编程序 依赖于硬件,不同机型的系统有自己的汇编程序。
3.1.2 上机过程
上机过程
如图所示
上机操作步骤:
( 1) 汇编源程序 (用 ML.EXE命令)
ML.EXE命令行格式如下:
ML [/参数选项 ] 源程序文件列表 [/LINK 连接参数选项 ]
例 1 汇编源程序文件 myprg.asm
ML /c myprg.asm
选项 /c——只进行汇编产生二进制目标文件 myprg.obj, 不
做连接 。
例 2 汇编源程序文件 myprg.asm并产生列表文件, 可 执行文件 。
ML /Fl /Sg myprg.asm
无 /c选项 —产生目标文件 myprg.obj,并 自动连接产生执行文件
myprg.exe
/Fl选项 —产生列表文件 myprg.lst
/Sg选项 —在列表文件中给出 myprg.asm中用到的汇编语言高级
语法等伪指令所产生的系统机器指令
( 2) 连接产生执行文件 ( LINK.EXE)
连接的操作步骤如下:
C:> LINK myprg?
Microsoft( R) Overlay Linker Version 5,03
Copyright( C) Microsoft Corp1984-1989,Allrightreserved.
Run File [myprg.EXE],?
List File [NUL.MAP],?
Libraries [.LIB],?
Definitions File [NUL.DEF] ?
( 3) 执行程序
C:>myprg?
3.2 汇编语言源程序的结构与书写格式
汇编语言源程序是段结构的,代码段、数据段、堆栈段、附加段
源程序 由段组成,每段有一个 段名, segment定义段起点,
ends定义段结束点。每段由若干 语句行 组成,源程序以 end结束。
例 3-3 p43
例 3-3
字符串传送
3.3 汇编语言语句格式与分类
汇编语言语句一般格式为:
[标识符 /语句标号 ] 指令名 [操作数序列 ] [;注释 ]
标识符 ——用来为变量, 段及过程等命名
语句标号 ——标识符后加 ?,?, 提供转移地址
指令名 ——指令可分为三类:机器指令, 伪指令和宏指令 。
机器指令,指令系统中的指令, 程序运行时 由 CPU执行 ;
伪指令,汇编程序执行 的操作, 规定汇编程序如何按要求
进行汇编及分配内存 。
宏指令,由一系列指令或伪指令构成, 汇编时展开 成若干
条机器指令, 用于提高编程效率 。
操作数序列 ——可以是常量, 变量, 表达式, 寄存器名或
标号等, 用逗号隔开 。
( 伪指令和宏指令由汇编程序在汇编期间处理 )
注释符 ——,;, 后可给出语句注释, 提高可读性和可理解性 。
3.4 常量、变量、标号、运算符和表达式
( 1)常量
00110110B 389D 467O B407H
3.475E+5 'Input a number'
( 2)变量
变量名:存储单元的符号地址
变量值:存储单元中的数据
MOV AL,'A'
mov al,'a'
变量的三种属性:
段值( SEG):变量所在 段的起始地址
偏移量( OFFSET):段起点距离变量所在存储单
元位置的 字节数
50



段起点
?
类型( TYPE):变量 占用的字节数
用,RADIX 伪指令改变默认进制, 其格式为:
.RADIX n ( n为默认进制的基数 )
例如,.RADIX 16 定义十六进制为默认的进制
( 3)标号
标号,存放指令的存储单元的 符号地址,常用作转移地址。
NEAR, 2字节转移地址

CMP AX,BX
JNE NEXT

NEXT,MOV AX,0

标号的三种属性:
段值( SEG):标号所在段的起始地址
偏移量( OFFSET):段起点距离标号所指存储单
元位置的字节数
类型( TYPE), NEAR, FAR
(偏移地址) 短指针 (近指针 ) 段内转移
FAR, 4字节转移地址 (段、偏移地址) 长指针 (远指针 ) 段间转移
1)计算运算符
( 4)运算符和表达式
表达式,由汇编程序在汇编期间计算
写正确表达式的原则,表达式的值必须能够在汇编期间
确定地计算出来。
例如:
MOV AX,BX+CNT ?
LEA AX,BUF+3 ?
运算符分四类:
( 1)算术运算符
MOV AL,19 MOD 7 MOV AL,5
同一段 内两种有意义的地址运算:
? 两个单元地址相减,
? 一个单元地址加减一个常量,
差是两个单元之间相距的 字节数
产生的新地址是该单元 邻近单元的地址
例如, BUF2- BUF1
?
BUF1
BUF2
BUF2 - BUF1 = BUF1缓冲区的长度
例如,VAL+3
VAL
VAL+1
VAL+2
VAL+3
( 2)移位运算符
表达式 SHR n (移位位数)
( SHL)
例如:
MOV AX,01001001B SHR 4 MOV AX,00000100B
SHL AX,00000101B SHR 2 SHL AX,00000001B
( 3)逻辑运算符
AND, OR,XOR,NOT
例如:
MOV AX,NOT 0FFH MOV AX,0FF00H
( 4)关系运算符
比较两个表达式的关系,EQ,NE,LT,LE,GT,GE
例如:
MOV BX,0F0H GE 0AFH ( BX) = FFFFH
3.5 伪指令
伪指令,由汇编程序在 汇编时执行的操作
功能:数据定义、存储区分配、段定义及过程定义等
分类:
( 1)符号定义伪指令 ( 2)数据定义伪指令
( 3)段定义伪指令 ( 4) 过程定义伪指令
( 5)条件汇编伪指令 ( 6)宏指令
( 7)结构与记录
1)符号定义伪指令
符号定义伪指令, 为表达式赋予符号名
? EQU 伪指令
符号名 EQU 表达式
? = 伪指令
例如:
COUNT EQU 2000
COUNT2 EQU COUNT+200
CNT EQU CX
B5 EQU ES,[BX+5]
应用符号定义的 优点,
、可修改性,简化程序书写。
限制, 同一符号名只能定义一次
允许同一符号名多次定义
例如:
VALUE = 100
VALUE = 200
VALUE = VALUE +100
提高程序的可读性
2)数据定义伪指令
数据定义伪指令,为数据 分配存储单元
并 定义 存储单元的 符号地址,为存储单元 赋初值
符号名 DB 初值表
DW
DD
DQ
DT
字节

双字
四字
10 字节
例 1,BYTES DB 10,4,?,10H
BYTES+0
BYTES+1
BYTES+2
BYTES+3
0A
04
-
10
( 10D)
( 4D)
( -)
( 16)
STRING DB 'ABC'
' A '
' B '
' C '
STRING+1
STRING+2
41
42
43
STRING DB 41H,42H,43H
STRING+0
例 2,0400H,2000H D_WORD DD 3CH,?
ADDA DW D_WORD
ADDAD DD D_WORD
D_WORD
-
-
-
-
3C
00
00
00
00
04
00
20
00
20
ADDA
ADDAD
偏移地址
偏移地址
段地址
例 3:
NUM DQ 2.647E+2
例 4:定义 5个字节单元,并都初始化为 0
1) 复制操作符
格式, 表达式 DUP (初值表)
ARRAY DB 100 DUP( 0)
定义大量具有一定规律的数据,
ARRAY1 DB 2 DUP( 1,2,3)
定义的数据, 1, 2, 3, 1, 2,3
ARRAY2 DB 100 DUP ( 3,4,2 DUP (1,2),2 DUP( 0 ) )
定义 100组数据, 3,4,1,2,1,2,0,0
DUP 可嵌套,
2)分析运算符 — 获取变量或标号的属性
( 1) SEG运算符,获取变量或标号的 段地址
ARRAY DB 0,0,0,0,0
例,3150H,0100H XP DW 5000H
2000H,0400H ARRAY DW 100 DUP(?)
?
MOV BX,SEG XP
MOV AX,SEG ARRAY
( BX) 3150H
MOV DS,AX 使 DS指向 ARRAY数组所在的数据段
( 2) OFFSET运算符,获取变量或标号的 偏移地址
例,MOV SI,OFFSET XP
MOV AX,[SI]
( AX) 2000H
( SI) 100H
( AX) 5000H
LEA SI,XP
显示串、串操作、寄存器 间接寻址操作等常用到取地址操作。
( 3) TYPE运算符,获取变量或标号的类型。
变量和标号的类型值见 P52 的 表 3-4。
例,X1 DB ?STRING ?
X2 DW 4000H
X3 DQ?
MOV AL,TYPE X1
MOV CL,TYPE X2
MOV DL,TYPE X3
( AL) 1
( CL) 2
( DL) 8
( 4) LENGTH 运算符,获取数组变量的长度。
限制:只用于 非嵌套 DUP操作符 定义的 数组变量 。
例,CH1 DW 200 DUP (?)
CH2 DB 1,2,3
CH3 DW 100 DUP (1,2,3,4 DUP(0))
CH4 DB ?length ?
MOV CX,LENGTH CH1
MOV AH,LENGTH CH2
MOV CL,LENGTH CH3
MOV CH,LENGTH CH4
( CX) 200
( AH) 1
( CL) 100
( CH) 1
( 5) SIZE 运算符,获取数组变量占用 的字节数。
例,MOV AL,SIZE CH1 ( AL) 400
SIZE CH1=( LENGTH CH1 ) * ( TYPE CH1 )
3)属性修改运算符 —修改变量或标号的属性
( 1) PTR 运算符
和 EQU联用,为 已定义的存储单元 建立 新类型 的符号地址。
类型名 PTR 表达式
例,TWO_BYTE DW 0 TWO_BYTE 00
00
ONE_BYTE
ONE_BYTE EQU BYTE PTR TWO_BYTE
MOV AL,TWO_BYTE?
?MOV AL,ONE_BYTE
PTR 运算符的应用,?满足语法要求
?内存单元共享P53 例 3-22
MOV AX,TWO_BYTE ?
例,用 PTR指定操作数类型
INC BYTE PTR [BX]
ADD WORD PTR [DI],37H
例,用 PTR修改标号类型
?
LAB,MOV AX,100
?
JMP LAB
?
LABF EQU FAR PTR LAB
?
JMP LABF (跨段转移)
或者 JMP FAR PTR LAB
LABEL 伪指令,
符号名 LABEL 类型名
例,LABF LABEL FAR
LAB,MOV AX,100
例:
D_WORD LABEL WORD
D_BYTE DB 100 DUP (?)
3)段定义伪指令
( 1) SEGMENT … ENDS 伪指令
段名 SEGMENT [定位类型 ] [组合类型 ] [段字 ][类别名 ]
?
段名 ENDS
?定位类型 ( 4 种)
?组合类型 ( 6 种)
PAGE 页边界地址 ( 256字节 /页)
PARA 小段边界 地址 ( 16字节 /小段)
WORD 字边界地址
BYTE 字节边界地址
( 缺省 )
NONE 独立段
PUBLIC 连续段
COMMON 覆盖段
STACK 堆栈段
AT 表达式 定位于表达式指定的地址处
MEMORY 定位于所有段之前
( 缺省 )
?段字
USE16 / USE32
选择用 16/32位 cpu指令
?类别名
相同类别名的段按组合
类型连接在一起。
( 2) ASSUME 伪指令
ASSUME 段寄存器:段名
ASSUME CS:CODE,DS:DATA,ES:EXTRA,SS:STACK
?由系统初始化
SS寄存器初始化,
STACK SEGMENT PARA STACK ‘STACK’
DB 200 DUP(?)
STACK ENDS
?
CODE SEGMENT
ASSUME CS,CCODE,SS,STACK
?
STACK
?
0000
0001
00C7
00C6
00C8
?
SP
SP
( SS) = STACK
( SP) = 200
?由程序初始化
STACK SEGMENT
DB 200 DUP(?)
TOP LABEL WORD
STACK ENDS
CODE SEGMENT
?
MOV AX,STACK
MOV SS,AX
MOV SP,OFFSET TOP
? SP
SP
TOP
STACK
?
0000
0001
00C7
00C6
00C8
?
200
( 3) ORG 伪指令
地址计数器, 当前值指出 下一个可分配存储单元的地址 。
当前值用‘ $’表示 。
ORG 表达式 (将表达式 的值赋给 地址计数器 ) P58 例 3-30
( 4)过程定义伪指令
过程名 PROC NEAR/FAR
?
RET
过程名 ENDP
用于程序的模块化组织
?由系统初始化
CS寄存器初始化,
END 启动地址
例,END START START 段地址 ( CS)偏移地址 ( IP)
?由调用指令、转移指令、中断指令等修改 CS,IP
next例 3-31
例 3-30 ORG伪指令的用法
DATA SEGMENT
ORG 100H
VALUE l DB 47H,0A5H
ORG $+40H
VALUE2 DB ?string?
LEN EQU $-VALUE2
DATA ENDS
100H
142H
148H-142H=6H
LEN EQU $-VALUE2
LEN EQU 6
?string_len?
14CH-142H=AH
返回
?
3.2 简化段定义伪指令
简化段定义 源程序格式如下:
.model small ;定义程序的存储模式
.stack ;定义堆栈段
.data ;定义数据段
? ;变量与数据定义
.code ;定义代码段
.startup ;程序执行起点
? ;程序代码
.exit 0 ;程序执行结束
? ;子程序代码
end ;源程序结束
1)存储模式伪指令
决定程序代码和数据的存储空间规模,规定子程序调用指令、
转移指令和数据存取的缺省属性。
第一条语句必须是存储模式伪指令,格式为
.MODEL 存储模式 [,语言类型 ] [,操作系统类型 ] [,堆栈选项 ]
存储模式有 7种,
TINY模式(微型) —类似 COM格式,代码、数据和堆栈都
包含在一个 64K的段内;
SMALL模式(小型) —代码和数据各分配一个 64K的段
(常用模式 );
COMPACT模式 (紧凑型) —用于数据量大、代码量小的程序
MEDIUM模式(中型) —用于代码量大、数据量小的程序
LARGE模式(大型) —是较大型程序通常采用的存储模式
HUGE模式(巨型) —与 LARGE模式类似,但静态数据存储
空间可以超过 64KB
FLAT模式 —不划分段,仅用于 32位 Windows系统下编程 ;
MODEL伪指令自动产生程序需要的 ASSUME语句 。
语言类型,C,PASCAL,StdCall,SysCall等
语言类型 指定语言的 命名规则 和子程序调用 参数传递方式 。
操作系统类型,默认为 DOS系统
堆栈选项,NEARSTACK,FARSTACK
NEARSTACK—( SS) =( DS ) (默认值 )
FARSTACK —( SS) ?( DS)
2)代码段、数据段和堆栈段简化伪指令
格式:
.STACK [堆栈长度 ] ;堆栈段定义伪指令
.DATA ;数据段定义伪指令
.DATA? ;数据段定义伪指令 ( 不初始化变量 )
.CONST ;常量段定义伪指令
.CODE [段名 ]
上述伪指令将分别产生相应的一组 SEGMENT-ENDS伪指令
FLAT和 前三种 模式的 缺省段名, _TEXT,STACK (1024字节 ),_DATA
后三种 模式的 缺省段名,模块名 _TEXT
小型程序常用的 SMALL模式 段属性如教材表 3-6所示 。
3)程序开始伪指令
.STARTUP ; MASM 6.x支持该伪指令
.STARTUP伪指令按照 CPU类型, 存储模式, 操作系统类型
及 堆栈类型 产生程序开始执行的代码,指定程序的 起始执行地
址,在 DOS系统下还将 初始化 DS,调整 SS和 SP的值 。
4)程序终止伪指令
.EXIT [返回状态码 ] ; MASM 6.x支持该伪指令
.EXIT伪指令产生终止执行程序、返回 DOS的指令,并可以给
出一个返回状态码,通常用 0表示正常返回。
.EXIT 0 伪指令实际上翻译为下述代码:
MOV AX,4C00H ; DOS系统功能调用的 4C子功能:返回 DOS
INT 21H
MOV AX,@data ;使用 MASM 5.x时的数据段初始化
MOV DS,AX
.model small ; SMALL存储模式
.stack 200 ;定义 200个字节 的 堆栈
.data ;定义数据段
mess db 'How are you?$' ;定义字符信息串
.code ;定义代码段
.startup ;程序执行起点
lea dx,mess ;取字符串起始地址 mess
mov ah,9 ;调用 DOS系统 9号子功能
int 21h ;输出字符串
.exit 0 ;返回 DOS
end
例 3-33 用简化段伪指令写出字符串输出程序。
课堂练习,编写完整的段定义程序,功能与上述程序例子相同,
参考 P43的例子。
提示,可以将程序定义为 两段结构 。 next
返回
data segment
mess db ' How are you? $ ' ;定义字符串
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 ;初始化数据段
lea dx,mess
mov ah,9 ;输出字符串
int 21h
ret
main endp
code ends
end main
参考答案,
3.6 条件汇编
根据条件 汇编 不同的程序段,只产生 被汇编 的程序段的
目标代码。
格式:
IF XXXX
? 程序段 1
?
[ELSE]
? 程序段 2
?
ENDIF
条件伪指令见 P62 表 3-7
注意, 条件汇编是 汇编阶段 的分支,不是 程序执行时 的分支。
例:将 AL 寄存器中的字符进行大小写转换。
设( AL) =字母字符的 ASCII码
CHANG DB 0
?
IFE CHANG
or AL,20H
ELSE
and AL,0DFH
ENDIF
3.7 宏指令 (简化程序书写,方便编程)
( 1) 宏定义,
( 2) 宏调用, 宏名 [实参表 ]
( 3) 宏展开,
(实参字符串代替形参字符串)
汇编时用 宏定义中的指令组代替宏 。
宏名 MACRO [形参表 ]
? 宏体
ENDM
条件汇编的用处,
?提高软件的可移植性
?减小目标代码的长度
MOV CL,4
SAL AL,CL
例如:
宏展开,
MOV AL,0A5H
1 MOV CL,4
1 SAL AL,CL
SHT MACRO (宏定义)
ENDM
程序中 宏调用,
MOV AL,0A5H
SHT
?
SHT MACRO X,Y
MOV CL,X
SAL Y,CL
ENDM
程序中 宏调用,
MOV BL,0A5H
SHT 6,BL
?
宏展开,
MOV BL,0A5H
1 MOV CL,6
1 SAL BL,CL
考虑程序的功能完善和优化
带参数宏定义:
SHT MACRO X,Y,Z
MOV CL,X
S&Z Y,CL
ENDM
程序:
MOV BL,0A5H
SHT 3,BL,AR
?
宏展开:
MOV BL,0A5H
1 MOV CL,3
1 SAR BL,CL
( 4)宏定义中的标号
ABS MACRO OPS
CMP OPS,0
JGE PLUS
NEG OPS
PLUS,MOV AX,OPS
ENDM
LOCAL PLUS
0000,0001, …,FFFF
功能, 将 OPS取绝对值
宏调用:
ABS CX
MOV BX,AX
ABS DX
宏展开:
?
1 CMP CX,0
1 JGE0000
1 NEG CX
10000,MOV AX,CX
MOV BX,AX
1 CMP DX,0
1 JGE0001
1 NEG DX
10001,MOV AX,DX
( 5)递归宏调用
例如,计算 2N *X
POW MACRO X,N
SAL X,1
COU NT = COUNT+1
IF COUNT-N
POW X,N
ENDIF
ENDM 宏展开,1 SAL AX,1
宏调用,( 设 N=3)
COUNT = 0
POW AX,3
1 SAL AX,1
1 SAL AX,1
1) REPT伪指令
REPT 表达式
? 重复块
ENDM
宏指令与子程序的区别:
宏指令 子程序
汇编时宏展开 程序执行时调用与返回
宏调用时插入宏体 子程序调用时转入子程序执行一次
空间开销大 空间开销小
时间开销小 时间开销大
实、形参字符串原样替换 参数传递
共同处, 简化程序书写
宏指令:短小且要求运算快的程序
子程序:需要共享且较长的程序
( 6)重复汇编 ( REPT,IRP,IRPC)
(对重复块重复汇编的次数)
例如:定义 26个字节的数组 ARRAY,并初始化为 字母 ?a ?~?z ? 。
ARRAY DB ?a ?
CHAR = ?a ?
REPT 25
CHAR = CHAR+1
DB CHAR
ENDM
定义结果:
ARRAY DB 61H
DB 62H
?
DB 7AH
小 结
本章要求:
( 1)了解 汇编程序 的功能和 汇编 的概念,并能熟练
地对汇编语言源程序进行 汇编、连接、运行和调试 。
( 2)掌握常用的 运算符, 伪指令 以及 条件汇编 和 宏
指令 。重点掌握取地址运算符( OFFSET)、属性修
改运算符( PTR),符号定义, 过程定义 和 数据定义
伪指令。
( 3)掌握 汇编语言源程序 的 结构 和 语句格式,重点
掌握 简化段定义 伪指令,一般情况下使用简化段定义
源程序书写格式,要求能够编写语法正确的完整的汇
编语言源程序。
认真复习,融会贯通
GOTO 第四章