汇编语言 程序设计
第 4章 汇编语言与源程序结构
◆ 汇编语言源程序与汇编程序
◆ 汇编语言语句种类及其格式
◆ 汇编语言数据与运算符
◆ 伪指令
◆ 源程序结构模式
汇编语言 程序设计
4.1 汇编语言源程序与汇编程序
1,汇编语言源程序
汇编语言源程序是用汇编语言编写的程序, 简称汇编语
言程序 。 汇编语言程序通过编辑程序在计算机中建立汇编语
言源程序文件 ( ASM文件 ) 。
2,汇编程序
将汇编语言源程序编译成目标程序的加工程序称为汇编
程序 。 这一加工过程称为汇编 。
汇编程序的作用就是把源程序文件 ( ASM文件 ) 转换成用
二进制代码表示的目标程序文件 ( OBJ文件 ) 。
汇编程序的主要功能有:
① 检查源程序 。 ② 测出源程序语法错误, 并给出错误 。
③ 产生目标程序, 并可给出列表文件 ④ 展开宏指令 。
返回
汇编语言 程序设计
4.2 汇编语言语句种类及其格式
语句是汇编语言源程序的基本组成单位 。 一个汇编语言
源程序中有 3种基本语句:指令语句, 伪指令语句和宏指令
语句 。 前两种是最常见, 最基本的语句 。 指令语句和伪指令
语句不仅在程序中的功能不同, 而且实现其功能的方法和时
间也是不同的 。
1,指令语句
指令语句就是计算机中指令系统的各条指令, 每条指令
语句在汇编时都产生一个供 CPU执行的机器目标代码, 所以
这种语句又称为可执行语句 。
计算机中每条指令语句表示一种基本功能, 这些基本功
能是在程序运行期间由计算机硬件来实现的 。 一条指令语句
由四个字段组成, 其一般格式如下:
[标号,] 指令助记符 [操作数 ] [;注释 ]
汇编语言 程序设计
( 1)标号
标号是指令语句的符号地址, 它代表指令代码存放地址
的第一个字节地址 。
标号是指令语句的可选项, 通常在一个程序段或子程序
的入口指令语句选用标号, 当程序需要转入这个程序段或
调用子程序时, 就可直接引用这标号 。 标号通常在代码段
中定义, 后面跟冒号 ?, ?, 它经常在转移指令或 CALL指
令中引用, 用以表示转向地址, 引用时标号后不跟冒号 。
( 2) 指令助记符
指令助记符为指令语句的核心, 是不可省略的主要部分,
如 MOV,ADD,XOR,RCL等等, 它表示指令语句要求 CPU完成
的具体操作 。
汇编语言 程序设计
( 3) 操作数
操作数表示指令助记符的操作对象, 不同的指令所带
的操作数不同, 有一个操作数的指令 ( 如 INC,NOT等 ),
有二个操作数的指令 ( 如 ADD,XOR等 ), 无操作数指令
( 如 CLC,STD等 ) 。
若需要操作数, 则每一个操作数要依据寻址方式来表示 。
操作数可以是常数, 寄存器, 标号, 变量和表达式 。
(4) 注释
注释是用来说明一段程序或一条或多条指令的功能, 它
是可选项, 注释均以分号 ? ; ? 开始, 它可占一行或多行 。
注释还通常用于调试程序 。 注释是语句的非执行部分, 因
此, 它不出现在机器目标代码中, 也不影响指令语句的功
能 。
汇编语言 程序设计
2、伪指令语句
伪指令语句指示汇编程序在汇编源程序时完成某些工作,
比如完成数据定义, 分配存储区, 指示程序结束等 。
伪指令属于汇编控制命令, 它所指示的操作是由汇编程
序在汇编源程序时完成的, 在汇编时, 它不产生目标代码,
在将源程序汇编成目标程序后, 它就不复存在了 。
综上所述可知, 伪指令语句与指令语句的主要区别是:
伪指令语句经汇编后不产生机器目标代码, 而指令语句经
汇编后将产生相应的机器目标代码;伪指令语句所指示的
操作是在程序汇编时完成的, 而指令语句的操作必须在程
序运行时才能完成 。 一条伪指令语句也由四个字段组成,
其一般格式如下:
[符号名 ] 伪指令符 操作数 [;注释 ]
汇编语言 程序设计
( 1)符号名
符号名在伪指令语句中是一个可选项,符号名后面没有
冒号,符号名可以是常量名、变量名、过程名等。
( 2) 伪指令符
伪指令符指定汇编程序要完成的具体操作, 它是伪指令语
句的核心部分, 如数据定义伪指令 DB,DW,DD,段定义伪指
令 SEGMENT,定义过程伪指令 PROC等等 。
( 3) 操作数
伪指令中的操作数可以是常数, 字符串, 变量, 表达式,
其个数由具体的伪指令决定, 各个操作数之间用 ?, ? 分隔 。
( 4) 注释
伪指令语句的注释也是可选项, 需要时必须以 ? ; ? 开始 。
汇编语言 程序设计
3、标识符
指令语句中的标号和伪指令语句中的符号名统称为标识
符 。 它们由若干字符组成, 标识符的组成规则如下:
( 1) 一个标识符由 1--3个字符组成 。
( 2) 组成标识符的字符可以是字母 ( A--Z或 a--z), 数
字 ( 0--9), 专用字符 ( ?? ?, ? · ?, ? @?, ? $?,
? 下划线 _? ) 。
( 3) 除数字外, 上述其余字符均可作为标识符的首字符,
? · ? 只能作为标识符的首字符 。
( 4) 不能使用属于系统的专用保留字 。
返回
汇编语言 程序设计
4.3 汇编语言数据与运算符
汇编语言的指令语句和伪指令语句操作数一般为常量,
变量, 标号, 表达式 。
1,常量
常量是没有任何属性的纯数值, 它的值在汇编期间已能
完全确定, 且在程序运行中也不会发生变化 。 常量分为数值
常量, 字符串常量和符号常量, 它主要用于指令语句中的立
即数或伪指令语句中给变量赋初值等 。
( 1) 数值常量
数值常量分为整数和实数 。
例如,11100011B, 45693, 0FF2AH, 356703Q都是正
确的整数形式,
又如,543.567,﹣ 45.23,1.2E﹣ 2,﹣ 45.4E﹢ 9都是正
确的实数形式 。
汇编语言 程序设计
( 2)字符串常量
字符串常量是用单引号括起来的一个字符或多个字符 。
字符串常量以单引号中各字符的 ASCII码形式存储在内存
中, 如 ‘ H’,在内存中就是 41H,‘12’就是 31H,32H。 使用
时可在单引号内直接写字符序列, 如 ‘ 12AB’,也可写字
符的 ASCII码, ASCII码之间用逗号分隔 ( 此时不需要用单
引号 ), 如 31H,32H,41H,42H表示字符串 ‘ 12AB’。
( 3) 符号常量
符号常量是指用 EQU伪指令或赋值语句 ? =? 定义过的符
号名, 可作操作数项或在表达式中使用 。
汇编语言 程序设计
2、变量
在汇编语言中, 变量是一个数据存储单元的名称, 即数据
存放地址的符号表示 。 它代表存放在某些存储单元的数据,
这些数据在程序运行期间随时可以改变 。 为方便访问变量,
在程序中通过变量名来使用变量 。
( 1) 变量的定义
变量通常在数据段或附加段中使用数据定义伪指令来定义,
定义变量就是给数据分配存储单元, 有时为存储单元赋予一
个变量名, 并可同时为这些存储单元预置初值 。 数据定义伪
指令的格式为:
[变量名 ] DB(DW,DD,DQ,DT) 表达式 1,表达式 2,…
汇编语言 程序设计
其中:变量名是可选项,它仅代表所定义数据存储区
第一个单元的地址; DB,DW,DD,DQ和 DT是伪指令符,具
体一条数据定义伪指令取 5种之一。
DB定义的是字节类型的变量,每个表达式被分配 1个字
节单元。
DW定义的是字类型的变量, 每一个表达式被分配 1个字单
元 ( 2个字节 ) 。
DD定义的是双字类型的变量, 每一个表达式被分配 2个字
单元 ( 4个字节 ) 。
DQ定义的是四字类型的变量, 每一个表达式被分配 4个字
单元 ( 8个字节 ) 。
DT定义的是十字节类型的变量, 每一个表达式被分配 10
个字节单元 。
汇编语言 程序设计
表达式 1,表达式 2…… 是给变量或指定的存储单元赋
予初值,它们有以下几种形式:
( a) 数值表达式
数据定义伪指令可以为一个或连续的存储单元设置数
值初值 。
( b) 字符串表达式
对于 DB伪指令, 字符串的长度允许超过 2个字符, 但不
能超过 255个字符, 字符串必须用单引号括起来, 它可为
字符串中的每个字符分配 1字节单元, 字符串从左至右以
字符的 ASCII码形式按地址递增的顺序依次存放 。
汇编语言 程序设计
( c)? 表达式
不带引号的?, 用于为变量预留内存单元, 暂时不存入
数据, 即表示所定义的变量无确定的初值 。
例如,A DW?,? 为变量 A预留 2个字单元 。
( d) 地址表达式
操作数为地址表达式时, 只适用于 DW和 DD这两种数据定
义伪指令 。 如果地址表达式为一变量 ( 标号 ) 名, 用 DW伪
指令则是取它的偏移地址来初始化变量;用 DD伪指令则是
取它的段首地址和偏移地址来初始化变量 。
( e) 带 DUP的表达式
格式为,n DUP (表达式 ),其中 n为重复因子, 只能取
正整数, 它表示定义了 n个数据存储单元 。
汇编语言 程序设计
( 2)变量的属性
由于存储器是分段使用的, 因而源程序定义的变量具有 3
个属性:
( a) 段属性 ( SEG)
变量的段属性是指定义变量时它所在段的段首地址 。
( b) 偏移属性 ( OFFSET)
变量的偏移属性是指所在段的段首地址到定义该变量的
位置之间的字节数 ( 即偏移地址 ) 。 上述的段属性和偏移
属性值就构成了一个变量的逻辑地址 。
( c) 类型属性 ( TYPE)
变量的类型属性表示存储变量时所占存储单元的字节个
数 。
汇编语言 程序设计
( 3)变量的使用
定义后的变量, 在程序中的引用有两种情况:
( a) 在指令语句中, 采用存储器操作数的几种寻址方式,
除寄存器间接寻址方式不使用变量名外, 其余各种寻址方
式均可使用变量名 。
例如, 某数据段已定义一变量 ARRAY:
ARRAY DW 5000H,4000H
( b) 在数据定义伪指令 DW和 DD中, 操作数字段可直接引
用已定义过的变量名 。
如,A DB 50H,40H
B DW A
C DD B
汇编语言 程序设计
3、标号
标号是一条指令语句的符号地址,在汇编源程序中,只
有在需要转向一条指令语句时,才为该指令语句设置标号,
以便在控制转移指令中直接引用这个标号。标号一般在代码
段中定义和引用。由于标号代表了指令的符号地址,所以标
号也有 3个属性:
( a) 段属性 ( SEG) 。 标号的段属性是指标号定义所在段的
段首地址 。
( b) 偏移属性 ( OFFSET) 。 标号的偏移属性是指标号所在
段的段首地址到该标号的字节距离 。
( c) 类型属性 ( TYPE) 。 标号的类型属性表示了它的转移
特性, 即该标号是作为段内还是段间转移 ( 或调用 ) 指令的
目标地址 。 标号的类型属性有 2种,NEAR类型和 FAR类型 。
汇编语言 程序设计
4、表达式和运算符
汇编语言的指令语句和伪指令语句中, 表达式是操作
数项的常见形式, 表达式是由常量, 变量, 标号用运算
符连接而成有意义的式子 。 表达式分为数值表达式和地
址表达式, 任一表达式的值只计算一次, 表达式的计算
是在源程序汇编过程中进行的, 而不是在程序运行中进
行的, 汇编程序将表达式计算后得到一个数值或一个地
址 。
在 8086汇编语言中, 运算符分为:算术运算符, 逻辑
运算符, 关系运算符, 数值返回运算符, 属性运算符和
字节分离运算符 。
汇编语言 程序设计
( 1)数值表达式
数值表达式是由常量与算术运算符, 逻辑运算符或关系
运算符构成的有意义的式子 。 数值表达式在汇编期间进行
运算, 运算结果为一数值常量, 它只有大小而没有属性 。
( 2) 地址表达式
地址表达式是由常量, 变量, 标号, 寄存器 ( BX,BP、
SI,DI) 内容 ( 用寄存器名加方括号表示 ) 和运算符组成
的有意义的式子 。 单个的变量, 标号, 寄存器的内容是地
址表达式的特例 。
地址表达式中可以使用算术运算符中的 ? +?, ? -? 运
算符和关系运算符 。
在地址表达式中, 常用的形式是:变量 ± 常量 。
汇编语言 程序设计
地址表达式除使用数值表达式的运算符外, 还可以使
用特殊算符 。
( a) 属性运算符
属性运算符主要用于临时修改变量, 标号或某个内存单
元中的操作数的类型属性 。
① 段超越前缀 ?, ? 。
其格式为:段寄存器名:地址表达式
或段名:地址表达式
② 类型运算符 PTR。
其使用格式为:类型 PTR 地址表达式
根据地址表达式的不同值, 类型可以是 BYTE,WORD、
DWORD,NEAR,FAR等 。
③ 定义类型运算符 THIS。
其格式为:标识符 EQU THIS 类型
汇编语言 程序设计
( b) 数值返回运算符
数值返回运算符有 5种, 这些运算符的运算对象必须是变
量或标号, 其功能是分离出变量或标号的段, 偏移地址及
类型的属性值, 运算结果为一数值常量 。
① SEG运算符
格式,SEG 变量或标号
功能:分离出其后变量或标号所在段的段首地址 。
② OFFSET运算符
格式,OFFSET 变量或标号
功能:分离出其后变量或标号的偏移地址 。
③ TYPE运算符
格式,TYPE 变量或标号
功能:分离出其后变量或标号的类型值 。
汇编语言 程序设计
④ LENGTH运算符
格式,LENGTH 变量
功能:取出变量所含的数据存储单元个数 。 该运算符只
对变量起作用, 它的取值根据定义该变量时数据定义伪指
令后面第一个表达式的形式而定 。 如果第一个表达式为重
复子句 ? n DUP ( 表达式 ) ? 的形式, 则取值为前面的重
复因子 n。 如果为其它形式的表达式, 则取值均为 1。
⑤ SIZE运算符
格式,SIZE 变量
功能:取出变量所含的数据存储区的总字节数 。 其返回
值为该变量的 LENGTH值和 TYPE值的乘积, 即,LENGTH 变量
* YTPE 变量 。
汇编语言 程序设计
( c) 分离运算符
① 分离高字节运算符 HIGH。
格式,HIGH 常量或地址表达式
功能:用来分离出其后 16位常量或地址表达式的偏移地
址的高字节 。
② 分离低字节运算符 LOW。
格式,LOW 常量或地址表达式
功能:用来分离出其后 16位常量或地址表达式的偏移地
址的低字节 。
( d) 其他运算符
SHORT运算符:用于说明其后的标号在短距离
( -128--27之间 ) 内 。
( ) 运算符用于改变运算的优先级别 。
[ ] 运算符用于表示间接寻址 。 返回
汇编语言 程序设计
4.4 伪指令
伪指令又称为伪操作, 伪指令是汇编语言程序设计的一
个重要部分, 由于汇编程序在汇编过程中无法区分源程序中
的分段情况, 哪些是数据, 哪些是指令, 也无法识别数据的
类型, 以及源程序在哪结束, 因此, 80X86宏汇编语言提供
了多种伪指令, 它主要告诉汇编程序如何正确地将汇编源程
序汇编成目标程序 。
1,数据定义伪指令
常用的数据定义伪指令有 DB,DW,DD,DQ,DT。
格式,[变量 ] 数据定义伪指令 表达式 [, 表达式, … ]
功能:定义数据存储区, 类型由数据定义伪指令确定, 初
值由表达式给定 。
汇编语言 程序设计
2,符号定义伪指令
符号定义伪指令用于为程序中多次出现的同一个常量或
表达式定义为一个标识符, 以便在源程序中以标识符来代
替对应的常量或表达式 。 符号定义伪指令有以下两种 。
( 1) 等价伪指令 EQU
格式:符号名 EQU 表达式
功能:为常量或表达式及其它各种符号定义一个等价的
符号名, 但它不申请分配存储单元 。
说明:
① 表达式可以是常量或数值表达式;地址表达式;变
量, 标号或指令助记符 。
② 符号名不占存储单元, 没有段, 偏移和类型 3种属性
③ 在同一源程序中, 使用 EQU定义的符号不能与本程序
中的其它符号名同名;另外, 同一符号不能用 EQU伪指令重
新定义 。
汇编语言 程序设计
EQU伪指令主要有以下 3方面应用:
① 定义符号常量 。 用符号名表示常量, 数值表达式 。
② EQU与属性运算符 PTR或 THIS连用, 可以给变量或标号
定义新的类型属性并重新命名 。 但其段属性和偏移属性不
变 。
③ 利用 EQU可以用一个符号名替代一个复杂的地址表
达式和其它一些符号, 如指令助记符, 变量名, 标号, 段
名, 寄存器名, 宏定义名等 。
( 2) 等号伪指令
格式:符号名 = 表达式
功能:该语句的功能与 EQU语句类似, 不同的是等号伪
指令能对所定义的符号名多次重新定义, 且以最后一次定
义的值为准 。
汇编语言 程序设计
3,段结构伪指令
编制一个 80X86汇编语言源程序, 段是基础, 这有两方面
含义:一是必须按段来构造程序, 二是在程序执行时, 要凭
借四个段寄存器对各个段的存储单元进行访问 。 段结构伪指
令主要有两条语句, 即段定义伪指令和假定伪指令 。
( 1) 段定义伪指令 SEGMENT/ ENDS
格式:段名 SEGMENT [定位类型 ] [组合类型 ] [‘ 类别
’ ]
┇ 段体
段名 ENDS
功能:定义一个逻辑段, 指定段的名字和范围, 段在内存
中的起始位置, 段与段之间的连接关系 。
说明,① 段名由用户指定, 开始与结束的段名须一致 。
② SEGMENT/ ENDS伪指令把程序分成若干逻辑段 。
③ 删节号为段体, 段体内为指令和伪指令序列 。
汇编语言 程序设计
( 2) 假定伪指令 ASSUME
假定伪指令主要用于指示汇编程序哪些段是当前段以及这
些段与段寄存器之间的对应关系 。
格式,ASSUME 段寄存器名,段名 [,段寄存器名,段名,… ]
其中, 段名是指用 SEGMENT/ ENDS语句已定义的段名, 也可
以是表达式 ? SEG 变量或标号 ?, 或者是关键字 NOTHING; 段
寄存器名可为 CS,DS,SS,ES四者之一 。
功能:该语句一般出现在代码段中, 用来设定段寄存器与段
之间的对应关系, 以便汇编程序知道段的结构和在执行各种
指令时知道应访问哪个段;也可用来取消段寄存器与段之间
的对应关系 ( 使用 NOTHING时 ) 。
说明:
① ASSUME伪指令设置在代码段内, 第一个 ASSUME语句一般放
在段定义语句之后, 是说明性语句 。
汇编语言 程序设计
② 在一个代码段中, 如果没有另外的 ASSUME伪指令重
新设置, 原有 ASSUME语句的设置一直有效 。
③ 不在当前段中的变量和数据存储单元均是不可访问
的, 否则, 会在汇编时产生错误或运行时造成混乱, 产生逻
辑上的错误, 得出错误结果 。
④ ASSUME伪指令不产生任何目标代码, 它仅仅是告诉汇
编程序, 哪些段是当前段, 而且它们分别由哪个段寄存器指
向 。
⑤ 汇编程序不能检查在程序运行期间段寄存器内容是否
与上述 ASSUME语句的设置一致 。 如果在程序中间用 ASSUME语
句重建了 DS或 ES与某段的关系时, 就一定要紧跟着将这个新
段首地址送入 DS或 ES中, 否则, 会因段寄存器的内容未更改
而使得后面数据的读写仍在原来的数据段中进行, 这样的错
误, 系统是检查不出来的, 即出现逻辑错误 。
汇编语言 程序设计
4,源程序开始和结束伪指令
( 1) 源程序开始伪指令
在源程序开始处可以用 NAME或 TITLE为模块取名字 。
① NAME伪指令
格式,NAME 模块名
汇编程序将以给出的 ? 模块名 ? 作为模块的名字 。
② TITLE伪指令
如果程序中没有 NAME伪指令, 则也可使用 TITLE伪指令 。
格式,TITLE text
TITLE伪指令可指定每一页上打印的标题 。 同时, 若程序中
没有 NAME伪指令, 则汇编程序将用 text 中的前 6个字符作为
模块名 。 text最多可有 60个字符 。
若程序中既无 NAME又无 TITLE伪指令, 则将用源程序名作为
模块名 。 所以 NAME及 TITLE伪指令并不是必要的, 但一般常使
用 TITLE,以便在列表文件中能打印出标题来 。
汇编语言 程序设计
( 2) 源程序结束伪指令
格式,END [ 地址表达式 ]
功能:该语句为源程序的最后一个语句, 用以标志整
个程序的结束, 即告诉汇编程序汇编工作到此
结束 。
其中, 地址表达式为可选项, 若选用地址表达式, 则
表示此程序是主程序, 它可以单独执行, 其地址表达式
为该程序的启动地址, 即程序开始运行的第一条指令的
地址, 例如, ? END START”,此 START是第一条指令的
标号;若不选用表达式, 则说明此程序为一子程序, 不
能单独运行, 只能被其它程序调用 。
汇编语言 程序设计
5,定位伪指令 ORG与汇编地址计数器 ( $)
汇编程序在汇编源程序时, 每遇到一新段, 就为该段
设置一个初值为 0的汇编地址计数器, 汇编程序使用汇编
地址计数器记载正在汇编的数据或指令的目标代码在当前
段内的偏移地址 。
当前汇编地址计数器的值可用符号 $表示, 用户可在程
序中直接使用 $,表示引用当前汇编地址计数器的值 。 例
如:
ARRAY DW 4000H,5000H,6000H
COUNT EQU ( $ - ARRAY) / 2
汇编地址计数器的值可以用定位伪指令 ORG设置 。
ORG伪指令格式,ORG 数值表达式
功能:将数值表达式的值赋给汇编地址计数器 。
汇编语言 程序设计
6,过程定义伪指令 PROC/ENDP
在程序设计中, 常把具有某种功能的程序段设计成一个
过程 。 80X86宏汇编语言用于过程定义的伪指令的格式为
,过程名 PROC [ NEAR 或 FAR ]
┆ ; 过程体
过程名 ENDP
其中过程名是过程入口地址的符号表示, 它由程序员
指定, 且开始处和结束处的过程名一致 。 过程名同标号一
样, 具有三种属性:段属性, 偏移属性和类型属性, 类型
属性可指定为 NEAR或 FAR两种 。 具有 NEAR属性的子程序与
调用程序应在同一个逻辑段中, 而具有 FAR属性的子程序
和调用程序不在同一个逻辑段内 。 即段内调用的子程序一
般为 NEAR类型, 段间调用的子程序一般为 FAR类型, 若为
NEAR类型, 定义过程时, 参数 NEAR可省略 。 过程体为过程
内的指令和伪指令序列 。 返回
汇编语言 程序设计
4.5 源程序结构模式
一个汇编源程序一般由几个段组成, 其中, 必不可少
的是代码段和堆栈段, 堆栈段也可以不用显示定义, 可以
直接使用隐式堆栈段, 如果程序中需要使用数据存储区,
还要定义数据段, 必要时还要定义附加段 。 一般情况下,
对于不太复杂的程序只需要三个段 ( 即数据段, 堆栈段和
代码段 ) 就可以了, 而对于复杂的程序, 除了使用上述三
个段以外还可以使用多个段, 甚至可以使用多个程序模块 。
汇编语言源程序结构通常有两种, 它们的区别在于代
码段中某些部分的编写稍有不同 。 具体地说, 就是用户程
序运行结束后, 返回 DOS的方法上有所不同 。
汇编语言 程序设计
1,用 INT 21H返回 DOS的程序结构模式
INT 21H是 DOS系统功能调用, 用这种方法返回 DOS的程
序结构比较简单, 我们编写程序常采用此结构, 具体编
写时只要在用户程序的最后安排两条指令即可, 即:
MOV AH,4CH
INT 21H
2,用过程返回 DOS的程序结构模式
采用此种方法返回 DOS的程序结构, 要求将用户程序定
义为一个类型为 FAR的过程, 在用户程序的开始处要将 DS
的值压栈, 偏移地址 0压栈, 在程序的最后安排一条 RET
指令 。 这样当程序运行到 RET指令后便可返回 DOS。
返回