第 3 章教学重点第 2章学习了 8086硬指令,
第 3章介绍 MASM基本的伪指令 。 第 3章重点掌握:
程序的格式,开发方法
参数的表达,变量的定义
变量和标号的属性第 3章 硬指令和伪指令
硬指令 —— 使 CPU产生动作,并在程序执行时才处理的语句,就是第 2章学习的处理器指令
伪指令 ( Directive) —— 不产生 CPU
动作,在程序执行前由汇编程序处理的说明性语句,例如,数据说明,变量定义等等
伪指令与具体的处理器类型无关,但与汇编程序的版本有关本课程采用微软宏汇编程序 MASM 6.11
第 3章 3.1 汇编语言程序的开发
本节从汇编语言程序的 语句格式出发,给出第一个示范性的汇编语言 源程序,并演示汇编语言程序的过程:
编辑 汇编 连接 调试
即汇编语言程序的开发方法语句格式
⑴ 执行性语句 —— 由硬指令构成的语句,
它通常对应一条机器指令,出现在程序的代码段中:
标号,硬指令助记符 操作数,操作数 ;注释
⑵ 说明性语句 —— 由伪指令构成的语句,
它通常指示汇编程序如何汇编源程序:
名字 伪指令助记符 参数,参数,… ;注释第 3章
MOV CX,0 ;传送指令,具有 2个操作数
DELAY:NOP;空操作指令,没有操作数,带有标号
LOOP DELAY;循环指令,标号 DELAY说明转移位置
BUFFERDB 1,2,3,4,5,6,7;数据定义伪指令,在主存中开辟 7个连续的字节单元,初值依次为 1~ 7,BUFFER表示首地址标号,名字与标识符
标号 是反映硬指令位置 ( 逻辑地址 ) 的标识符,
后跟一个冒号分隔
名字 是反映伪指令位置 ( 逻辑地址 ) 和属性的标识符,后跟空格或制表符分隔,没有一个冒号
标识符 ( Identifier) 一般最多由 31个字母,数字及规定的特殊符号 ( 如 _,$,?,@) 组成,
不能以数字开头 。 默认情况下,汇编程序不区别标识符中的字母大小写
一个程序中,每个标识符的定义是唯一的,还不能是汇编语言采用的保留字第 3章保留字
保留字 ( Reserved Word) 是汇编程序已经利用的标识符,主要有:
o 硬指令助记符 —— 例如,MOV,ADD
o 伪指令助记符 —— 例如,DB,EQU
o 操作符 —— 例如,OFFSET,PTR
o 寄存器名 —— 例如,AX,CS
o 预定义符号 —— 例如,@data
第 3章汇编语言大小写不敏感第 3章 助记符
硬指令助记符 可以是任何一条处理器指令,也可以是一条宏指令
伪指令助记符 将在本章和下章学习
前一章引入的定义字节数据和字符串的
DB就是伪指令第 3章 操作数与参数
处理器指令的 操作数 可以是立即数,寄存器和存储单元
伪指令的 参数 可以是常数,变量名,表达式等,可以有多个,
参数之间用逗号分隔第 3章 注释
语句中由分号,;,开始的部分为注释内容,用以增加源程序的可读性
必要时,一个语句行也可以由分号开始作为阶段性注释
汇编程序在翻译源程序时将跳过该部分,不对它们做任何处理第 3章 分隔符
语句的 4个组成部分要用分隔符分开
标号后用冒号,注释前用分号
操作数之间和参数之间使用逗号分隔
其他部分通常采用空格或制表符
多个空格和制表符的作用与一个相同
MASM支持续行符,\”
第 3章 汇编语言源程序的组成原则
完整的汇编语言源程序由段组成
一个汇编语言源程序可以包含若干个代码段,
数据段,附加段或堆栈段,段与段之间的顺序可随意排列
需独立运行的程序必须包含一个代码段,并指示程序执行的起始点,一个程序只有一个起始点
所有的可执行性语句必须位于某一个代码段内,说明性语句可根据需要位于任一段内
通常,程序还需要一个堆栈段第 3章 汇编语言源程序
源程序分别用两种格式书写
第一种格式从 MASM 5.0开始支持
简化段定义格式
第二种格式 MASM 5.0以前就具有
完整段定义格式
Hello,Everybody !
程序功能;lt301a.asm( 文件名 )
.model small ;定义程序的存储模式
.stack ;定义堆栈段
.data ;定义数据段
string db ’Hello,Everybody !’,0dh,0ah,’$’;在数据段定义要显示的字符串
.code ;定义代码段
.startup ;程序起始点,建立 DS,SS
mov dx,offset string ;指定字符串
mov ah,9
int 21h ;利用功能调用显示信息
.exit 0 ;程序结束点,返回 DOS
end ;汇编结束;SampleA.ASM
.model small
.stack
.data
..,;在数据段定义数据
.code
.startup ;( 注 1)
..,;在代码段填入指令序列
.exit 0 ;( 注 2)
..,;子程序代码
end ;( 注 3)
简化段定义格式
MASM 6.x支持;SampleC.ASM
.model small
.stack
.data
..,;在数据段定义数据
.code
start,mov ax,@data
mov ds,ax
..,;在代码段填入指令序列
mov ax,4c00h
int 21h
..,;子程序代码
end start
简化段定义格式
MASM 5.x支持;lt301b.asm( 文件名 )
stack segment stack ;定义堆栈段
dw 512 dup(?);堆栈段有 512字 ( 1024字节 ) 空间
stack ends ;堆栈段结束
data segment ;定义数据段
string db ’Hello,Everybody !’,0dh,0ah,’$’
data ends
code segment ’code’;定义代码段
assume cs:code,ds:data,ss:stack
start,mov ax,data ;建立 DS段地址
mov ds,ax
mov dx,offset string
mov ah,9
int 21h
mov ax,4c00h
int 21h ;利用功能调用返回 DOS
code ends ;代码段结束
end start;汇编结束,同时指明程序起始点;SampleB.ASM
stack segment stack
dw 512 dup(?)
stack ends
data segment
..,;在数据段定义数据
data ends
code segment ’code’
assume cs:code,ds:data,ss:stack
start,mov ax,data
mov ds,ax
..,;在代码段填入指令序列
mov ax,4c00h
int 21h
..,;子程序代码
code ends
end start
完整段定义格式
MASM 5.x支持汇编语言程序的开发过程编辑文本编辑器,如 EDIT.COM
源程序:文件名,asm
汇编汇编程序,如 ML.EXE
目标模块:文件名,obj
连接连接程序,如 LINK.EXE
可执行文件:文件名,exe
调试调试程序,如 DEBUG.EXE
应用程序 错误错误错误错误开发过程 1:源程序的编辑源程序文件要以 ASM为扩展名源程序文件的形成 ( 编辑 ) 可以通过任何一个文本编辑器实现,
DOS中的全屏幕文本编辑器 EDIT
其他程序开发工具中的编辑环境
MASM程序员工作平台 PWB中的编辑环境
EDIT lt301a.asm
开发过程 2:源程序的汇编汇编是将源程序翻译成由机器代码组成的目标模块文件的过程
MASM 6.x提供的汇编程序是 ML.EXE:
ML /c lt301a.asm
如果源程序中没有语法错误,MASM将自动生成一个目标模块文件 ( lt301a.obj) ;
否则 MASM将给出相应的错误信息这时应根据错误信息,重新编辑修改源程序后,再进行汇编开发过程 3:目标模块的连接连接程序能把一个或多个目标文件和库文件合成一个可执行程序 (,EXE,.COM文件 ),
LINK lt301a.obj
如果没有严重错误,LINK将生成一个可执行文件 ( lt301a.exe) ;否则将提示相应的错误信息这时需要根据错误信息重新修改源程序后再汇编,链接,直到生成可执行文件汇编和连接过程可以依次自动完成汇编和连接的依次自动实现
ML汇编程序可自动调用 LINK连接程序,
实现汇编和连接的依次进行
ML lt301a.asm
汇编程序 ML.EXE可带其他参数,常用
ML /Fl /Sg lt301a.asm
该命令除产生模块文件 lt301a.obj和可执行文件 lt301a.exe外,还将生成列表文件 lt301a.lst
列表文件是一种文本文件,含有源程序和目标代码,对我们学习汇编语言程序设计和发现错误很有用 。 采用 /Sg选项,将在列表文件中得到有些伪指令相应的硬指令开发过程 4:可执行程序的调试经汇编,连接生成的可执行程序在操作系统下只要输入文件名就可以运行:
lt301a
操作系统装载该文件进入主存,并开始运行如果出现运行错误,可以从源程序开始排错,也可以利用调试程序帮助发现错误采用 DEBUG.EXE调试程序:
DEBUG lt301a.exe
第 3章 3.2 参数,变量和标号
本节详细讨论汇编语言程序语句的主要部分:
参数 变量名 标号
并引出相关的伪指令和操作符
本节重点掌握:
常数的表达,
变量定义伪指令 DB/DW/DD、
地址操作符和类型操作符第 3章 3.2.1 数值型参数
在源程序语句格式的 4个组成部分中,
参数是指令的操作对象 ( 在学习硬指令时被称为操作数 ),参数之间用逗号分隔
参数根据指令不同可以没有,可以有 1
个,2个或多个
汇编语言程序中,指令参数有数值型,
它的主要形式是 常数 和 数值表达式 ;
硬指令的操作数有立即数;立即数就要用数值型参数表达第 3章 常数
常数 ( 常量 ) 表示一个固定的数值
它又分成多种形式:
( 1) 十进制常数
( 2) 十六进制常数
( 3) 二进制常数
( 4) 八进制常数
( 5) 字符串常数
( 6) 符号常数第 3章 数值表达式
数值表达式一般是指由运算符连接的各种常数所构成的表达式
汇编程序在汇编过程中计算表达式,
最终得到一个数值
程序运行之前,就已经计算出了表达式;所以,程序运行速度没有变慢,
但增强程序的可读性
MASM对除伪指令外各种汇编时处理的指令统称为操作符 ( Operator)
第 3章 运算符
算术运算符
+ - * / MOD
逻辑运算符
AND OR XOR NOT
移位运算符
SHL SHR
关系运算符
EQ NE GT LT GE LE
高低分离符
HIGH LOW HIGHWORD LOWWORD
第 3章 操作符的优先级
1 () <> [] ·LENGTH SIZE WIDTH MASK
2 PTR OFFSET SEG TPYE THIS,
3 HIGE LOW
4 * / MOD SHL SHR
5 + -
6 EQ NE GT LT GE LE
7 NOT
8 AND
9 OR XOR
10 SHORT
建议采用圆括号,( ),显式表达,它可以极大地提高程序的可阅读性第 3章 地址型参数
汇编语言程序中,指令参数还有地址型,它的主要形式是标号和名字 ( 变量名,段名,过程名等 )
硬指令的操作数有存储单元;存储单元就应该用地址型参数 ( 存储器操作数 ) 表达第 3章 3.2.2 变量定义伪指令
变量定义 ( Define) 伪指令为变量申请固定长度的存储空间,并可同时将相应的存储单元初始化变量名 伪指令助记符 初值表变量定义伪指令最常使用第 3章 变量名
变量名为用户自定义标识符,表示初值表首元素的逻辑地址 ;用这个符号表示地址,常称为符号地址
变量名可以没有 。 这种情况,汇编程序将直接为初值表分配空间,无符号地址
设置变量名是为了方便存取它指示的存储单元第 3章 初值表
初值表是用逗号分隔的参数
主要由数值常数,表达式或?,
DUP组成
? —— 表示初值不确定,即未赋初值;
DUP—— 表示重复初值
DUP的格式为:
重复次数 DUP(重复参数 )
第 3章 变量定义伪指令助记符
变量定义伪指令根据申请的主存空间单位分类
DB—— 定义字节伪指令
DW—— 定义字伪指令
DD—— 定义双字伪指令
DF—— 定义 3字伪指令
DQ—— 定义 4字伪指令
DT—— 定义 10字节伪指令
还有定位伪指令定义字节单元伪指令 DB
DB伪指令用于分配一个或多个字节单元,
并可以将它们初始化为指定值初 值 表 中 每 个 数 据 一 定 是 字 节 量
( Byte),存放一个 8位数据:
可以是 0~255的无符号数或是- 128~+ 127带符号数也可以是字符串常数
data segment ;数据段
X db 'a',-5
db 2 dup(100),?
Y db 'ABC'
data ends
定义字单元伪指令 DW
DW伪指令用于分配一个或多个字单元,并可以将它们初始化为指定值初 值 表 中 每 个 数 据 一 定 是 字 量
( Word),一个字单元可用于存放任何 16位数据:
一个段地址一个偏移地址两个字符
0~ 65535之间的无符号数
- 32768~+ 32767之间的带符号数
data segment ;数据段
count dw 8000h,?,'AB'
maxintequ 64h
numberdw maxint
array dw maxint dup(0)
data ends
字变量和字常量的定义:
WNUM EQU 5678H ;定义 WNUM为常量
COUNTDW 20H;定义 COUNT变量,假设在数据段的偏移地址为 10H
字变量和字常量的应用:
MOV AX,[BX+SI+WNUM] ; MOV AX,[BX+SI+5678H]
MOV AX,COUNT ; MOV AX,[0010H]
MOV AX,[SI+COUNT] ; MOV AX,COUNT[SI]; MOV AX,[SI+10H]
LEA BX,COUNT ; LEA BX,[0010H]
MOV BX,OFFSET COUNT ; MOV BX,0010H
定义双字单元伪指令 DD
DD伪指令 用于分配一个或多个双字单元,
并可以将它们初始化为指定值初值表中每个数据是一个 32位的双字量
( Double Word),
可以是有符号或无符号的 32位整数也可以用来表达 16位段地址 ( 高位字 ) 和
16位的偏移地址 ( 低位字 ) 的远指针
vardd DD 0,?,12345678h
farpoint DD 00400078h
其他数据单元定义伪指令
定义 3字伪指令 DF——用于为一个或多个 6
字节变量分配空间及初始化
6字节常用在 32位 CPU中表示一个 48位远指针
( 16位段选择器,32位偏移地址 )
定义 4字伪指令 DQ——用于为一个或多个 8
字节变量分配空间及初始化
8字节变量可以表达一个 64位整数
定义 10字节伪指令 DT—— 用于为一个或多个 10字节变量分配空间及初始化
10字节变量可以表达扩展精度浮点数例 3.2,数据定义综合应用- 1/2
.model small
.stack
.data
bvar DB 16
wvar DW 4*3
dvar DD 4294967295 ;= 232- 1
qvar DQ?
DB 1,2,3,4,5
tvar DT 2345 ;定义了 BCD码 2345H
abc DB 'a','b','c'
msg DB 'Hello',13,10,'$'
bbuf DB 12 DUP('month')
dbuf DD 25 DUP(?)
CALLDOS EQU <int 21h>
例 3.2,数据定义综合应用- 2/2
.code
.startup
mov bl,bvar
mov ax,word ptr dvar[0]
mov dx,word ptr dvar[2] ;取双字到 DX.AX
mov dx,offset msg
mov ah,09h
CALLDOS
.exit 0
end
例 3.3,数据复制和显示- 1/2
.model small
.stack
.data
source db 33h,34h,35h,36h ;定义 4个字符数据
target db 80 dup(?) ;分配数据空间 4× 20=80
.code
.startup
mov ax,ds
mov es,ax ;data也作为附加段
cld
mov si,offset source
mov di,offset target
mov cx,80
例 3.3,数据复制和显示- 2/2
rep movsb ;串传送
mov si,0 ;显示
mov bx,offset target
again,mov dl,[bx+si]
mov ah,2
int 21h
inc si
cmp si,80
jb again
.exit 0
end
定位伪指令定位伪指令控制数据的偏移地址
ORG 参数
ORG伪指令是将当前偏移地址指针指向参数表达的偏移地址:
ORG 100h ;从 100h处安排数据或程序
ORG $+10;使偏移地址加 10,即跳过 10个字节空间
MASM中,符号,$”表示当前偏移地址值
EVEN ;从偶地址开始
ALIGN n ;从 n的整数倍地址开始第 3章 3.2.3 变量和标号的属性
标号和名字一经定义便具有以下两类三种属性:
① 段值
标号和名字对应存储单元的段地址
② 偏移值
标号和名字对应存储单元的偏移地址
③ 类型
标号,子程序名的类型可以是 NEAR( 近 )
和 FAR( 远 ),分别表示段内或段间
变量名的类型可以是 BYTE( 字节 ),
WORD( 字 ) 和 DWORD( 双字 ) 等地址属性类型属性地址操作符
取得名字或标号的段地址和偏移地址两个属性
[ ] 将括起的表达式作为存储器地址
$ 当前偏移地址
,采用指定的段地址寄存器
OFFSET 名字 /标号返回名字或标号的偏移地址
SEG 名字 /标号返回名字或标号的段地址
org $+10
array db 45,45h
.code
mov ax,seg array
mov ds,ax
mov bx,offset array;等价于 lea bx,array
mov cl,array+4;等效于 mov cl,array[4]
mov ax,es:[2000h]
加 4个字节单元类型操作符
类型操作符对名字或标号的类型属性进行有关设置类型名 PTR 名字 /标号
THIS 类型名
SHORT 标号
TYPE 名字 /标号
SIZEOF 变量名
LENGTHOF 变量名
PTR操作符类型名 PTR 名字 /标号
PTR操作符使名字或标号具有指定的类型
类型名可以是
BYTE/WORD/DWORD/FWORD/QWORD/TBYTE
或者是 NEAR/FAR,还可以是由 STRUCT,RECORD、
UNION以及 TYPEDEF定义的类型
mov al,byte ptr w_var ;w_var是一个字变量
jmp far ptr n_label ;n_label是一个标号
使用 PTR操作符,可以临时改变名字或标号的类型
THIS操作符THIS 类型名
利用 THIS说明的操作数具有汇编时的当前逻辑地址,
但具有指定的类型
b_var equ THIS byte;按字节访问变量 b_var,但与 w_var的地址相同
w_var dw 10 dup(0) ;按字访问变量 w_var
f_jump equ THIS far;用 f_jump为段间转移 ( f_jump label far)
n_jump,mov ax,w_var;用 n_jump为段内近转移,但两者指向同一条指令
LABEL伪指令的功能等同于,EQU THIS”
SHORT操作符
SHORT 标名
指定标号作为 -128~ +127字节范围内的短转移
jmp short n_jump
当然,如果标号实际上超出了这个范围,则出错 。
对高版本 MASM已无意义
TYPE操作符TYPE 名字 /标名
返回表明名字或标号类型的一个字量数值
对字节,字和双字变量依次返回 1,2和 4;
对短,近和远转移依次返回 ff01h,ff02h和 ff05h
mov ax,TYPE w_var ;汇编结果为 mov ax,2
mov ax,TYPE n_jump;汇编结果为 mov ax,0ff02h( near标号 )
操作符 SIZEOF返回整个变量占用的字节数
LENGTHOF返回整个变量的数据项数 ( 即元素数 )
SIZEOF = LENGTHOF × TYPE
例题:属性及其 应用- 1/5
.model small
.stack
.data
v_byte equ this byte;v_byte是字节类型,与变量 v_word的地址相同
v_word dw 3332h,3735h;v_word是字类型的变量
target dw 5 dup(20h);分配数据空间 2× 5= 10字节
crlf db 0dh,0ah,'$'
flag db 0
n_point dw offset s_label;取得标号 s_label的偏移地址例题:属性及其 应用- 2/5
.code
.startup
mov al,byte ptr v_word;用 PTR改变 v_word的类型,否则类型不匹配
dec al
mov v_byte,al;对 v_word的头一个字节操作,原为 32H,现为 31H
n_label,cmp flag,1
jz s_label ;flag单元为 1转移
inc flag
jmp short n_label ;进行短转移例题:属性及其 应用- 3/5
s_label,cmp flag,2
jz next ;flag单元为 2转移
inc flag
jmp n_point;段内的存储器间接寻址,转移到 s_label标号处
next,mov ax,type v_word;汇编结果为 mov ax,2
mov cx,lengthof target;汇编结果为 mov cx,5
例题:属性及其 应用- 4/5
mov si,offset target
w_again,mov [si],ax ;对字单元操作
inc si ;SI指针加 2
inc si
loop w_again ;循环
mov cx,sizeof target;汇编结果为 mov cx,0ah
mov al,'?'
mov di,offset target
b_again,mov [di],al ;对字节单元操作
inc di ;DI指针加 1
loop b_again ;循环例题:属性及其 应用- 5/5
mov dx,offset v_word;显示结果,1357
mov ah,9
int 21h
.exit 0
end 习题 5( p109)
3.5 3.9 3.14 3.15
第 3章 3.3 程序段的定义和属性
详述汇编语言程序格式的组成部分首先,简单了解 DOS支持的 exe程序和
com程序其次,重点掌握简化段定义格式的各条伪指令最后,理解完整段定义格式所包含的各种段属性
exe程序
利用程序开发工具,通常将生成 EXE结构的可执行程序 ( 扩展名为,EXE的文件 )
它可以有独立的代码,数据和堆栈段,还可以有多个代码段或多个数据段,程序长度可以超过
64KB,执行起始处可以任意指定
当 DOS装入或执行一个程序时,DOS确定当时主存最低的可用地址作为该程序的装入起始点 。 此点以下的区域称为程序段 。 在程序段内偏移 0处,
DOS为该程序建立一个程序段前缀控制块 PSP
( Program Segment Prefix),它占 256( =100h)
个字节;而在偏移 100h处才装入程序本身
com程序
COM程序是一种将代码,数据和堆栈段合一的结构紧凑的程序,所有代码,数据都在一个逻辑段内,不超过 64KB
在程序开发时,需要满足一定要求并采用相应参数才能正确生成 COM结构的程序
COM文件存储在磁盘上是主存的完全影象,不包含重新定位的加载信息,与 EXE文件相比其加载速度更快,占用的磁盘空间也少
尽管 DOS也为 COM程序建立程序段前缀 PSP,但由于两种文件结构不同,所以加载到主存后各段设置并不完全一样;SampleA.ASM
.model small
.stack
.data
..,;在数据段定义数据
.code
.startup
..,;在代码段填入指令序列
.exit 0
..,;子程序代码
end
简化段定义格式
MASM 6.x支持存储模式伪指令
.MODEL 存储模式
使用简化段定义,必须有存储模式伪指令
,model语句必须位于所有段定义语句之前
存储模式决定一个程序的规模,确定进行子程序调用,指令转移和数据访问的缺省属性
MASM有 7种不同的存储模式:
① TINY ② SMALL
③ COMPACT ④ MEDIUM
⑤ LARGE ⑥ HUGE
⑦ FLAT
TINY微型模式
微型模式是 MASM 6.0才引入的用于创建 COM类型程序
用微型模式编写汇编语言程序时,所有的段地址寄存器都被设置为同一值这意味着代码段,数据段,堆栈段都在同 一个段 内,不大于 64KB;访问操作数或指令都只需要使用 16位偏移地址
SMALL小型模式
一般的程序 ( 例如本书的绝大多数程序示例和习题 ) 都 可用这种模式
在小型模式下,一个程序至多 只能有一个代码段和一个数据段,每段不大于 64KB
这里的数据段是指数据段,堆栈段和附加段的总和,它们共用同一个段基址,总长度不可超过
64KB;因此小模式下程序的最大长度为 128KB
访问操作数或指令都只需要使用 16位偏移地址;
这意味着诸如指令转移,程序调用以及数据访问等都是 近属性 ( NEAR),即小型模式下的调用类型和数据指针缺省分别为近调用和近指针
COMPACT紧凑模式
适合于数据量大但代码量小的程序
紧凑模式下,代码段 被限制在 一个 不大于 64KB的段内;而 数据段则可以有多个,超过 64KB
这种模式下的调用类型缺省仍为近调用;而数据指针缺省为远 ( FAR) 指针,
因为必须用段地址来区别多个数据段
MEDIUM中型模式
中型模式是与紧凑模式互补的模式适合于数据量小但代码量大的程序
中型模式的 代码段可以 超过 64KB,有多个 ;但 数据段只能有一个 不大于 64KB
的段这种模式下的数据指针缺省为近指针;
但调用类型缺省是远 ( FAR) 调用,因为要利用段地址区别多个代码段
LARGE大型模式
较大型程序通常采用的存储模式
大型模式 允许的代码段和数据段都有多个,
都可以超过 64KB;但全部的静态数据 ( 不能改变的数据 ) 仍限制在 64K字节内大型模式下的调用类型和数据指针缺省分别为远调用和远指针
HUGE( 巨型模式 ) 与大型模式基本相同,
只是静态数据不再被限制在 64K字节之内
FLAT平展模式
平展模式用于 创建一个 32位的程序,
它只能运行在 32位 x86 CPU上 。
DOS下不能使用 FLAT模式,
而编写 32位 Windows 9.x或 Windows-
NT的程序时,必须采用 FLAT模式 。
DOS下编程可选择前六种模式,一般可以选用 SMALL模式
TINY模式产生 COM程序,其他模式产生
EXE程序,FLAT模式只能用于 32位程序简化段定义伪指令
.STACK [大小 ] ;堆栈段开始
.DATA ;数据段开始
.CODE [段名 ] ;代码段开始
简化段定义伪指令指明一个逻辑段的开始,同时自动结束前面的一个段采用简化段定义伪指令前,需有,model语句
使用简化段定义,各段名称和其他用户所需的信息可以使用 MASM预定义符号,例如:
@data表示由,data等定义的数据段的段名堆栈段伪指令
.STACK [大小 ]
堆栈段伪指令,STACK创建一个堆栈段,
段名是,stack
它的参数指定堆栈段所占存储区的字节数,默认是 1KB( = 1024 = 400h字节 )
数据段伪指令
.DATA
数据段伪指令,data创建一个数据段,段名是,_DATA。 它用于定义具有初值的变量,当然也允许定义无初值的变量
无初值变量可以安排在另一个段中,它用,data?伪指令创建,数据段名是,_BSS
,const伪指令用于建立只读的常量数据段 ( 段名,CONST)
代码段伪指令
.CODE [段名 ]
代码段伪指令,code创建一个代码段,它的参数指定该代码段的段名
如果没有给出段名,则采用默认段名:
在 TINY,SMALL,COMPACT和 FLAT
模式下,默认的代码段名是,_TEXT
在 MEDIUM,LARGE和 HUGE模式下,
默认的代码段名是:模块名 _TEXT
程序开始伪指令.STARTUP
按照 CPU类型,存储模式,操作系统和堆栈类型,产生程序开始执行的代码;同时还指定程序开始执行的起始点
在 DOS下,还将设置
DS值,调整 SS和 SP值
mov dx,dgroup
mov ds,dx ;设置 DS
mov bx,ss
sub bx,dx
shl bx,1
shl bx,1
shl bx,1
shl bx,1
cli ;关中断
mov ss,dx ;调整 SS和 SP
add sp,bx
sti ;开中断
mov dx,@data
mov ds,dx
程序终止伪指令.EXIT [返回参数 ]
产生终止程序执行返回操作系统的指令代码
它的可选参数是一个返回的数码,通常用 0
表示没有错误 。 例如,exit 0对应的代码是:
mov ax,4c00h
int 21h
DOS功能调用的 4ch子功能 ( 返回 DOS),
入口参数,AH= 4ch,AL=返回数码汇编结束伪指令END [标号 ]
指示汇编程序 MASM到此结束汇编过程
源程序的最后必须有一条 END语句
可选的标号用于指定程序开始执行点,连接程序将据此设置 CS,IP值
采用了,startup伪指令就不需要再用,end
标号,指明开始执行点,但还要有 end伪指令
———— 不要糊涂 ————
程序终止和汇编结束是两码事第 3章 com程序的编写
利用 MASM 6.x的简化段定义格式,可以非常容易地创建一个 COM程序
遵循的规则:
采用 TINY模式
源程序只设置代码段,无数据,堆栈等段
程序必须从偏移地址 100h处开始执行
数据只能安排在代码段中,注意不能与可执行代码相冲突,通常在程序最后
.model tiny ;微型存储模式
.code ;只有代码段
.startup ;程序起始点,= ORG 100H
mov dx,offset string
mov ah,9 ;显示信息
int 21h
mov ah,01h ;等待按键
int 21h
mov ah,02h ;响铃
mov dl,07h
int 21h
.exit 0 ;程序结束点,返回 DOS
string db ‘Press any key to continue !$’;数据安排在此
end ;汇编结束;SampleD.ASM
.model tiny
.code ;只有代码段
.startup ;= org 100h
..,;填入指令序列
.exit 0
..,;子程序代码
..,;在此定义数据
end
COM程序格式
MASM 6.x支持;SampleB.ASM
stack segment stack
dw 512 dup(?)
stack ends
data segment
..,;在数据段定义数据
data ends
code segment ’code’
assume cs:code,ds:data,ss:stack
start,mov ax,data
mov ds,ax
..,;在代码段填入指令序列
mov ax,4c00h
int 21h
..,;子程序代码
code ends
end start
完整段定义格式
MASM 5.x支持完整段定义伪指令段名 segment 定位 组合 段字 '类别 '
..,;语句序列段名 ends
完整段定义由 SEGMENT和 ENDS这一对伪指令实现,
SEGMENT伪指令定义一个逻辑段的开始,ENDS伪指令表示一个段的结束
段定义指令后的 4个关键字用于确定段的各种属性,
堆栈段要采用 stack组合类型,代码段应具有 ‘ code’
类别,其他为可选属性参数
如果不指定,则采用默认参数;但如果指定,注意要按照上列次序段定位 ( align) 属性
指定逻辑段在主存储器中的边界,可为:
BYTE 段开始为下一个可用的字节地址 ( xxxx xxxxb)
WORD 段开始为下一个可用的偶数地址 ( xxxx xxx0b)
DWORD 段开始为下一个可用的 4倍数地址 ( xxxxxx00b)
PARA 段开始为下一个可用的节地址 ( xxxx 0000b)
PAGE 段开始为下一个可用的页地址 ( 0000 0000b)
简化段定义伪指令的代码和数据段默认采用
WORD定位,堆栈段默认采用 PARA定位
完整段定义伪指令的默认定位属性是 PARA,其低 4位已经是 0,所以默认情况下数据段的偏移地址从 0开始段组合 ( combine) 属性
指定多个逻辑段之间的关系,可为:
PRIVATE 本段与其他段没有逻辑关系,不与其他段合并,每段都有自己的段地址 。 这是完整段定义伪指令默认的段组合方式
PUBLIC 连接程序把本段与所有同名同类型的其他段 相邻地连接在一起,然后为所有这些段指定一个共同的段地址,也就是 合成一个物理段 。 这是 简化段定义伪指令默认的段组合
STACK 本段是堆栈的一部分,连接程序将所有 STACK段按照与 PUBLIC段的同样方式进行合并 。 这是 堆栈段必须具有的段组合段字 ( use) 属性
为支持 32位段而设置的属性
对于 16位 x86 CPU来说,它默认是 16
位段,即 USE16
而对于汇编 32位 x86 CPU指令时,它默认采用 32位段,即 USE32;但可以使用 USE16指定标准的 16位段
编写运行于实地址方式 ( 8086工作方式 ) 的汇编语言程序,必须采用 16位段段类别 ( class) 属性
当连接程序组织段时,将所有的同类别段相邻分配
段类别可以是任意名称,但必须位于单引号中
大多数 MASM程序使用 'code','data'
和 'stack’来分别指名代码段,数据段和堆栈段,以保持所有代码和数据的连续指定段寄存器伪指令
ASSUME 段寄存器:段名 [,段寄存器名:段名,...]
通知 MASM用指定的段寄存器来寻址对应的逻辑段,即建立段寄存器与段的缺省关系
在明确了程序中各段与段寄存器之间的关系后,
汇编程序会根据数据所在的逻辑段,在需要时自动插入段超越前缀 。 这是 ASSUME伪指令的主要功能
ASSUME伪指令并不为段寄存器设定初值,连接程序 LINK将正确设置 CS,IP和 SS,SP
由于数据段通常都需要,所以在样板源程序中,
首先为 DS赋值;如果使用附加段,还要赋值 ES
段组伪指令组名 GROUP 段名 [,段名,...]
把多个同类段合并为一个 64KB物理段,并用一个组名统一存取它
定义段组后,段组内各段就统一为一个段地址,
各段定义的变量和标号的偏移地址就相对于段组基地址计算
offset操作符取变量和标号相对于段组的偏移地址,如果没有段组则取得相对于段的偏移地址
offset后可以跟段组中的某个段名,表示该段最后一个字节后面字节相对于段组的偏移地址
stackseg segment stack
db 256 dup(?)
stackseg ends
data1 segment word public 'const'
const1 dw 100
data1 ends
data2 segment word public 'vars'
var1 dw?
data2 ends
datagroup group data1,data2 ;进行段组合
codeseg segment para public 'code'
assume cs:codeseg,ds:datagroup,ss:stackseg
例题 3.5- 1/3
start,mov ax,datagroup
mov ds,ax ;对段组寻址
mov ax,const1 ;ax=100
mov var1,ax ;[var1]=100
mov ax,offset var1 ;ax=2
mov ax,offset data1 ;ax=2
mov ax,offset data2 ;ax=4
例题 3.5- 2/3
assume ds:data2
mov ax,data2
mov ds,ax
mov ax,var1 ;ax=100
mov ax,offset var1 ;ax=2
mov ax,4c00h
int 21h
codeseg ends
end start
例题 3.5- 3/3
段顺序伪指令
.SEG ;按照源程序的各段顺序
.DOSSEG ;按照微软使用的标准 DOS规定
.ALPHA ;按照段名的字母顺序
段顺序伪指令确定各逻辑段在主存的前后位置
完整段定义格式中,默认按照源程序各段的书写顺序安排 ( 即,seg)
采用,model伪指令的简化段定义格式,则是规定的标准 DOS程序顺序 ( 即,dosseg ),
代码段 → 数据段 → 堆栈段主存地址低端 高端
dseg segment word public 'data'
org 100h;设定堆栈段起始段内偏移地址
dw 200 dup(?)
topsp equ this word ;定义栈顶指针
array dw 100 dup(5868h)
dseg ends
cseg segment 'code'
assume cs:cseg,ds:dseg,ss:dseg;dseg既是数据段又是堆栈段例题 3.6- 1/2
start,mov ax,dseg
mov ds,ax
mov ss,ax;数据段与堆栈段具有相同的段地址
mov sp,offset topsp
mov cx,100
xor si,si
again,push array[si]
inc si
inc si
loop again
mov ah,4ch
int 21h
cseg ends
end start
例题 3.6- 2/2
第 3章 简化段定义格式的段属性
采用简化段定义格式的源程序,同样具有段定位,组合,类别以及段组等属性 ( 表 3.4),具有默认的属性
.MODEL伪指令除了设置程序采用的存储模式外,还具有如下语句的作用:
dgroup GROUP _data,_bss,stack
assume cs:_TEXT,ds:dgroup,ss:dgroup
第 3章 教学要求 ( 1)
1,掌握汇编语言语句格式
2,掌握简化段定义 ( 或完整段定义 ) 源程序格式
3,掌握常量表达,变量定义及应用,变量,标号和逻辑段的属性
4,了解数值表达式和 DOS的程序结构
5,掌握汇编语言源程序的编辑,汇编,连接和调试的开发方法第 3章 教学要求 ( 2)
6,掌握基本伪指令和操作符:
EQU/=,+- */,DB/ DW/ DD,? / DUP
ORG/ $,OFFSET/ SEG/ PTR
.MODEL/,STACK/,DATA/,CODE/ END
SEGMENT/ENDS
第 3章 教学要求 ( 3)
7,了解不常使用伪指令和操作符:
.RADIX;逻辑,移位和关系运算符
DF/ DQ/ DT; EVEN/ ALIGN
THIS/ SHORT/ TYPE/ SIZEOF/ LENGTHOF
ASSUME/ GROUP,.SEG/,DOSSEG/,ALPHA;
8,习题 6( p111)
3.22 3.25 3.26
Take a Break
第 3章介绍 MASM基本的伪指令 。 第 3章重点掌握:
程序的格式,开发方法
参数的表达,变量的定义
变量和标号的属性第 3章 硬指令和伪指令
硬指令 —— 使 CPU产生动作,并在程序执行时才处理的语句,就是第 2章学习的处理器指令
伪指令 ( Directive) —— 不产生 CPU
动作,在程序执行前由汇编程序处理的说明性语句,例如,数据说明,变量定义等等
伪指令与具体的处理器类型无关,但与汇编程序的版本有关本课程采用微软宏汇编程序 MASM 6.11
第 3章 3.1 汇编语言程序的开发
本节从汇编语言程序的 语句格式出发,给出第一个示范性的汇编语言 源程序,并演示汇编语言程序的过程:
编辑 汇编 连接 调试
即汇编语言程序的开发方法语句格式
⑴ 执行性语句 —— 由硬指令构成的语句,
它通常对应一条机器指令,出现在程序的代码段中:
标号,硬指令助记符 操作数,操作数 ;注释
⑵ 说明性语句 —— 由伪指令构成的语句,
它通常指示汇编程序如何汇编源程序:
名字 伪指令助记符 参数,参数,… ;注释第 3章
MOV CX,0 ;传送指令,具有 2个操作数
DELAY:NOP;空操作指令,没有操作数,带有标号
LOOP DELAY;循环指令,标号 DELAY说明转移位置
BUFFERDB 1,2,3,4,5,6,7;数据定义伪指令,在主存中开辟 7个连续的字节单元,初值依次为 1~ 7,BUFFER表示首地址标号,名字与标识符
标号 是反映硬指令位置 ( 逻辑地址 ) 的标识符,
后跟一个冒号分隔
名字 是反映伪指令位置 ( 逻辑地址 ) 和属性的标识符,后跟空格或制表符分隔,没有一个冒号
标识符 ( Identifier) 一般最多由 31个字母,数字及规定的特殊符号 ( 如 _,$,?,@) 组成,
不能以数字开头 。 默认情况下,汇编程序不区别标识符中的字母大小写
一个程序中,每个标识符的定义是唯一的,还不能是汇编语言采用的保留字第 3章保留字
保留字 ( Reserved Word) 是汇编程序已经利用的标识符,主要有:
o 硬指令助记符 —— 例如,MOV,ADD
o 伪指令助记符 —— 例如,DB,EQU
o 操作符 —— 例如,OFFSET,PTR
o 寄存器名 —— 例如,AX,CS
o 预定义符号 —— 例如,@data
第 3章汇编语言大小写不敏感第 3章 助记符
硬指令助记符 可以是任何一条处理器指令,也可以是一条宏指令
伪指令助记符 将在本章和下章学习
前一章引入的定义字节数据和字符串的
DB就是伪指令第 3章 操作数与参数
处理器指令的 操作数 可以是立即数,寄存器和存储单元
伪指令的 参数 可以是常数,变量名,表达式等,可以有多个,
参数之间用逗号分隔第 3章 注释
语句中由分号,;,开始的部分为注释内容,用以增加源程序的可读性
必要时,一个语句行也可以由分号开始作为阶段性注释
汇编程序在翻译源程序时将跳过该部分,不对它们做任何处理第 3章 分隔符
语句的 4个组成部分要用分隔符分开
标号后用冒号,注释前用分号
操作数之间和参数之间使用逗号分隔
其他部分通常采用空格或制表符
多个空格和制表符的作用与一个相同
MASM支持续行符,\”
第 3章 汇编语言源程序的组成原则
完整的汇编语言源程序由段组成
一个汇编语言源程序可以包含若干个代码段,
数据段,附加段或堆栈段,段与段之间的顺序可随意排列
需独立运行的程序必须包含一个代码段,并指示程序执行的起始点,一个程序只有一个起始点
所有的可执行性语句必须位于某一个代码段内,说明性语句可根据需要位于任一段内
通常,程序还需要一个堆栈段第 3章 汇编语言源程序
源程序分别用两种格式书写
第一种格式从 MASM 5.0开始支持
简化段定义格式
第二种格式 MASM 5.0以前就具有
完整段定义格式
Hello,Everybody !
程序功能;lt301a.asm( 文件名 )
.model small ;定义程序的存储模式
.stack ;定义堆栈段
.data ;定义数据段
string db ’Hello,Everybody !’,0dh,0ah,’$’;在数据段定义要显示的字符串
.code ;定义代码段
.startup ;程序起始点,建立 DS,SS
mov dx,offset string ;指定字符串
mov ah,9
int 21h ;利用功能调用显示信息
.exit 0 ;程序结束点,返回 DOS
end ;汇编结束;SampleA.ASM
.model small
.stack
.data
..,;在数据段定义数据
.code
.startup ;( 注 1)
..,;在代码段填入指令序列
.exit 0 ;( 注 2)
..,;子程序代码
end ;( 注 3)
简化段定义格式
MASM 6.x支持;SampleC.ASM
.model small
.stack
.data
..,;在数据段定义数据
.code
start,mov ax,@data
mov ds,ax
..,;在代码段填入指令序列
mov ax,4c00h
int 21h
..,;子程序代码
end start
简化段定义格式
MASM 5.x支持;lt301b.asm( 文件名 )
stack segment stack ;定义堆栈段
dw 512 dup(?);堆栈段有 512字 ( 1024字节 ) 空间
stack ends ;堆栈段结束
data segment ;定义数据段
string db ’Hello,Everybody !’,0dh,0ah,’$’
data ends
code segment ’code’;定义代码段
assume cs:code,ds:data,ss:stack
start,mov ax,data ;建立 DS段地址
mov ds,ax
mov dx,offset string
mov ah,9
int 21h
mov ax,4c00h
int 21h ;利用功能调用返回 DOS
code ends ;代码段结束
end start;汇编结束,同时指明程序起始点;SampleB.ASM
stack segment stack
dw 512 dup(?)
stack ends
data segment
..,;在数据段定义数据
data ends
code segment ’code’
assume cs:code,ds:data,ss:stack
start,mov ax,data
mov ds,ax
..,;在代码段填入指令序列
mov ax,4c00h
int 21h
..,;子程序代码
code ends
end start
完整段定义格式
MASM 5.x支持汇编语言程序的开发过程编辑文本编辑器,如 EDIT.COM
源程序:文件名,asm
汇编汇编程序,如 ML.EXE
目标模块:文件名,obj
连接连接程序,如 LINK.EXE
可执行文件:文件名,exe
调试调试程序,如 DEBUG.EXE
应用程序 错误错误错误错误开发过程 1:源程序的编辑源程序文件要以 ASM为扩展名源程序文件的形成 ( 编辑 ) 可以通过任何一个文本编辑器实现,
DOS中的全屏幕文本编辑器 EDIT
其他程序开发工具中的编辑环境
MASM程序员工作平台 PWB中的编辑环境
EDIT lt301a.asm
开发过程 2:源程序的汇编汇编是将源程序翻译成由机器代码组成的目标模块文件的过程
MASM 6.x提供的汇编程序是 ML.EXE:
ML /c lt301a.asm
如果源程序中没有语法错误,MASM将自动生成一个目标模块文件 ( lt301a.obj) ;
否则 MASM将给出相应的错误信息这时应根据错误信息,重新编辑修改源程序后,再进行汇编开发过程 3:目标模块的连接连接程序能把一个或多个目标文件和库文件合成一个可执行程序 (,EXE,.COM文件 ),
LINK lt301a.obj
如果没有严重错误,LINK将生成一个可执行文件 ( lt301a.exe) ;否则将提示相应的错误信息这时需要根据错误信息重新修改源程序后再汇编,链接,直到生成可执行文件汇编和连接过程可以依次自动完成汇编和连接的依次自动实现
ML汇编程序可自动调用 LINK连接程序,
实现汇编和连接的依次进行
ML lt301a.asm
汇编程序 ML.EXE可带其他参数,常用
ML /Fl /Sg lt301a.asm
该命令除产生模块文件 lt301a.obj和可执行文件 lt301a.exe外,还将生成列表文件 lt301a.lst
列表文件是一种文本文件,含有源程序和目标代码,对我们学习汇编语言程序设计和发现错误很有用 。 采用 /Sg选项,将在列表文件中得到有些伪指令相应的硬指令开发过程 4:可执行程序的调试经汇编,连接生成的可执行程序在操作系统下只要输入文件名就可以运行:
lt301a
操作系统装载该文件进入主存,并开始运行如果出现运行错误,可以从源程序开始排错,也可以利用调试程序帮助发现错误采用 DEBUG.EXE调试程序:
DEBUG lt301a.exe
第 3章 3.2 参数,变量和标号
本节详细讨论汇编语言程序语句的主要部分:
参数 变量名 标号
并引出相关的伪指令和操作符
本节重点掌握:
常数的表达,
变量定义伪指令 DB/DW/DD、
地址操作符和类型操作符第 3章 3.2.1 数值型参数
在源程序语句格式的 4个组成部分中,
参数是指令的操作对象 ( 在学习硬指令时被称为操作数 ),参数之间用逗号分隔
参数根据指令不同可以没有,可以有 1
个,2个或多个
汇编语言程序中,指令参数有数值型,
它的主要形式是 常数 和 数值表达式 ;
硬指令的操作数有立即数;立即数就要用数值型参数表达第 3章 常数
常数 ( 常量 ) 表示一个固定的数值
它又分成多种形式:
( 1) 十进制常数
( 2) 十六进制常数
( 3) 二进制常数
( 4) 八进制常数
( 5) 字符串常数
( 6) 符号常数第 3章 数值表达式
数值表达式一般是指由运算符连接的各种常数所构成的表达式
汇编程序在汇编过程中计算表达式,
最终得到一个数值
程序运行之前,就已经计算出了表达式;所以,程序运行速度没有变慢,
但增强程序的可读性
MASM对除伪指令外各种汇编时处理的指令统称为操作符 ( Operator)
第 3章 运算符
算术运算符
+ - * / MOD
逻辑运算符
AND OR XOR NOT
移位运算符
SHL SHR
关系运算符
EQ NE GT LT GE LE
高低分离符
HIGH LOW HIGHWORD LOWWORD
第 3章 操作符的优先级
1 () <> [] ·LENGTH SIZE WIDTH MASK
2 PTR OFFSET SEG TPYE THIS,
3 HIGE LOW
4 * / MOD SHL SHR
5 + -
6 EQ NE GT LT GE LE
7 NOT
8 AND
9 OR XOR
10 SHORT
建议采用圆括号,( ),显式表达,它可以极大地提高程序的可阅读性第 3章 地址型参数
汇编语言程序中,指令参数还有地址型,它的主要形式是标号和名字 ( 变量名,段名,过程名等 )
硬指令的操作数有存储单元;存储单元就应该用地址型参数 ( 存储器操作数 ) 表达第 3章 3.2.2 变量定义伪指令
变量定义 ( Define) 伪指令为变量申请固定长度的存储空间,并可同时将相应的存储单元初始化变量名 伪指令助记符 初值表变量定义伪指令最常使用第 3章 变量名
变量名为用户自定义标识符,表示初值表首元素的逻辑地址 ;用这个符号表示地址,常称为符号地址
变量名可以没有 。 这种情况,汇编程序将直接为初值表分配空间,无符号地址
设置变量名是为了方便存取它指示的存储单元第 3章 初值表
初值表是用逗号分隔的参数
主要由数值常数,表达式或?,
DUP组成
? —— 表示初值不确定,即未赋初值;
DUP—— 表示重复初值
DUP的格式为:
重复次数 DUP(重复参数 )
第 3章 变量定义伪指令助记符
变量定义伪指令根据申请的主存空间单位分类
DB—— 定义字节伪指令
DW—— 定义字伪指令
DD—— 定义双字伪指令
DF—— 定义 3字伪指令
DQ—— 定义 4字伪指令
DT—— 定义 10字节伪指令
还有定位伪指令定义字节单元伪指令 DB
DB伪指令用于分配一个或多个字节单元,
并可以将它们初始化为指定值初 值 表 中 每 个 数 据 一 定 是 字 节 量
( Byte),存放一个 8位数据:
可以是 0~255的无符号数或是- 128~+ 127带符号数也可以是字符串常数
data segment ;数据段
X db 'a',-5
db 2 dup(100),?
Y db 'ABC'
data ends
定义字单元伪指令 DW
DW伪指令用于分配一个或多个字单元,并可以将它们初始化为指定值初 值 表 中 每 个 数 据 一 定 是 字 量
( Word),一个字单元可用于存放任何 16位数据:
一个段地址一个偏移地址两个字符
0~ 65535之间的无符号数
- 32768~+ 32767之间的带符号数
data segment ;数据段
count dw 8000h,?,'AB'
maxintequ 64h
numberdw maxint
array dw maxint dup(0)
data ends
字变量和字常量的定义:
WNUM EQU 5678H ;定义 WNUM为常量
COUNTDW 20H;定义 COUNT变量,假设在数据段的偏移地址为 10H
字变量和字常量的应用:
MOV AX,[BX+SI+WNUM] ; MOV AX,[BX+SI+5678H]
MOV AX,COUNT ; MOV AX,[0010H]
MOV AX,[SI+COUNT] ; MOV AX,COUNT[SI]; MOV AX,[SI+10H]
LEA BX,COUNT ; LEA BX,[0010H]
MOV BX,OFFSET COUNT ; MOV BX,0010H
定义双字单元伪指令 DD
DD伪指令 用于分配一个或多个双字单元,
并可以将它们初始化为指定值初值表中每个数据是一个 32位的双字量
( Double Word),
可以是有符号或无符号的 32位整数也可以用来表达 16位段地址 ( 高位字 ) 和
16位的偏移地址 ( 低位字 ) 的远指针
vardd DD 0,?,12345678h
farpoint DD 00400078h
其他数据单元定义伪指令
定义 3字伪指令 DF——用于为一个或多个 6
字节变量分配空间及初始化
6字节常用在 32位 CPU中表示一个 48位远指针
( 16位段选择器,32位偏移地址 )
定义 4字伪指令 DQ——用于为一个或多个 8
字节变量分配空间及初始化
8字节变量可以表达一个 64位整数
定义 10字节伪指令 DT—— 用于为一个或多个 10字节变量分配空间及初始化
10字节变量可以表达扩展精度浮点数例 3.2,数据定义综合应用- 1/2
.model small
.stack
.data
bvar DB 16
wvar DW 4*3
dvar DD 4294967295 ;= 232- 1
qvar DQ?
DB 1,2,3,4,5
tvar DT 2345 ;定义了 BCD码 2345H
abc DB 'a','b','c'
msg DB 'Hello',13,10,'$'
bbuf DB 12 DUP('month')
dbuf DD 25 DUP(?)
CALLDOS EQU <int 21h>
例 3.2,数据定义综合应用- 2/2
.code
.startup
mov bl,bvar
mov ax,word ptr dvar[0]
mov dx,word ptr dvar[2] ;取双字到 DX.AX
mov dx,offset msg
mov ah,09h
CALLDOS
.exit 0
end
例 3.3,数据复制和显示- 1/2
.model small
.stack
.data
source db 33h,34h,35h,36h ;定义 4个字符数据
target db 80 dup(?) ;分配数据空间 4× 20=80
.code
.startup
mov ax,ds
mov es,ax ;data也作为附加段
cld
mov si,offset source
mov di,offset target
mov cx,80
例 3.3,数据复制和显示- 2/2
rep movsb ;串传送
mov si,0 ;显示
mov bx,offset target
again,mov dl,[bx+si]
mov ah,2
int 21h
inc si
cmp si,80
jb again
.exit 0
end
定位伪指令定位伪指令控制数据的偏移地址
ORG 参数
ORG伪指令是将当前偏移地址指针指向参数表达的偏移地址:
ORG 100h ;从 100h处安排数据或程序
ORG $+10;使偏移地址加 10,即跳过 10个字节空间
MASM中,符号,$”表示当前偏移地址值
EVEN ;从偶地址开始
ALIGN n ;从 n的整数倍地址开始第 3章 3.2.3 变量和标号的属性
标号和名字一经定义便具有以下两类三种属性:
① 段值
标号和名字对应存储单元的段地址
② 偏移值
标号和名字对应存储单元的偏移地址
③ 类型
标号,子程序名的类型可以是 NEAR( 近 )
和 FAR( 远 ),分别表示段内或段间
变量名的类型可以是 BYTE( 字节 ),
WORD( 字 ) 和 DWORD( 双字 ) 等地址属性类型属性地址操作符
取得名字或标号的段地址和偏移地址两个属性
[ ] 将括起的表达式作为存储器地址
$ 当前偏移地址
,采用指定的段地址寄存器
OFFSET 名字 /标号返回名字或标号的偏移地址
SEG 名字 /标号返回名字或标号的段地址
org $+10
array db 45,45h
.code
mov ax,seg array
mov ds,ax
mov bx,offset array;等价于 lea bx,array
mov cl,array+4;等效于 mov cl,array[4]
mov ax,es:[2000h]
加 4个字节单元类型操作符
类型操作符对名字或标号的类型属性进行有关设置类型名 PTR 名字 /标号
THIS 类型名
SHORT 标号
TYPE 名字 /标号
SIZEOF 变量名
LENGTHOF 变量名
PTR操作符类型名 PTR 名字 /标号
PTR操作符使名字或标号具有指定的类型
类型名可以是
BYTE/WORD/DWORD/FWORD/QWORD/TBYTE
或者是 NEAR/FAR,还可以是由 STRUCT,RECORD、
UNION以及 TYPEDEF定义的类型
mov al,byte ptr w_var ;w_var是一个字变量
jmp far ptr n_label ;n_label是一个标号
使用 PTR操作符,可以临时改变名字或标号的类型
THIS操作符THIS 类型名
利用 THIS说明的操作数具有汇编时的当前逻辑地址,
但具有指定的类型
b_var equ THIS byte;按字节访问变量 b_var,但与 w_var的地址相同
w_var dw 10 dup(0) ;按字访问变量 w_var
f_jump equ THIS far;用 f_jump为段间转移 ( f_jump label far)
n_jump,mov ax,w_var;用 n_jump为段内近转移,但两者指向同一条指令
LABEL伪指令的功能等同于,EQU THIS”
SHORT操作符
SHORT 标名
指定标号作为 -128~ +127字节范围内的短转移
jmp short n_jump
当然,如果标号实际上超出了这个范围,则出错 。
对高版本 MASM已无意义
TYPE操作符TYPE 名字 /标名
返回表明名字或标号类型的一个字量数值
对字节,字和双字变量依次返回 1,2和 4;
对短,近和远转移依次返回 ff01h,ff02h和 ff05h
mov ax,TYPE w_var ;汇编结果为 mov ax,2
mov ax,TYPE n_jump;汇编结果为 mov ax,0ff02h( near标号 )
操作符 SIZEOF返回整个变量占用的字节数
LENGTHOF返回整个变量的数据项数 ( 即元素数 )
SIZEOF = LENGTHOF × TYPE
例题:属性及其 应用- 1/5
.model small
.stack
.data
v_byte equ this byte;v_byte是字节类型,与变量 v_word的地址相同
v_word dw 3332h,3735h;v_word是字类型的变量
target dw 5 dup(20h);分配数据空间 2× 5= 10字节
crlf db 0dh,0ah,'$'
flag db 0
n_point dw offset s_label;取得标号 s_label的偏移地址例题:属性及其 应用- 2/5
.code
.startup
mov al,byte ptr v_word;用 PTR改变 v_word的类型,否则类型不匹配
dec al
mov v_byte,al;对 v_word的头一个字节操作,原为 32H,现为 31H
n_label,cmp flag,1
jz s_label ;flag单元为 1转移
inc flag
jmp short n_label ;进行短转移例题:属性及其 应用- 3/5
s_label,cmp flag,2
jz next ;flag单元为 2转移
inc flag
jmp n_point;段内的存储器间接寻址,转移到 s_label标号处
next,mov ax,type v_word;汇编结果为 mov ax,2
mov cx,lengthof target;汇编结果为 mov cx,5
例题:属性及其 应用- 4/5
mov si,offset target
w_again,mov [si],ax ;对字单元操作
inc si ;SI指针加 2
inc si
loop w_again ;循环
mov cx,sizeof target;汇编结果为 mov cx,0ah
mov al,'?'
mov di,offset target
b_again,mov [di],al ;对字节单元操作
inc di ;DI指针加 1
loop b_again ;循环例题:属性及其 应用- 5/5
mov dx,offset v_word;显示结果,1357
mov ah,9
int 21h
.exit 0
end 习题 5( p109)
3.5 3.9 3.14 3.15
第 3章 3.3 程序段的定义和属性
详述汇编语言程序格式的组成部分首先,简单了解 DOS支持的 exe程序和
com程序其次,重点掌握简化段定义格式的各条伪指令最后,理解完整段定义格式所包含的各种段属性
exe程序
利用程序开发工具,通常将生成 EXE结构的可执行程序 ( 扩展名为,EXE的文件 )
它可以有独立的代码,数据和堆栈段,还可以有多个代码段或多个数据段,程序长度可以超过
64KB,执行起始处可以任意指定
当 DOS装入或执行一个程序时,DOS确定当时主存最低的可用地址作为该程序的装入起始点 。 此点以下的区域称为程序段 。 在程序段内偏移 0处,
DOS为该程序建立一个程序段前缀控制块 PSP
( Program Segment Prefix),它占 256( =100h)
个字节;而在偏移 100h处才装入程序本身
com程序
COM程序是一种将代码,数据和堆栈段合一的结构紧凑的程序,所有代码,数据都在一个逻辑段内,不超过 64KB
在程序开发时,需要满足一定要求并采用相应参数才能正确生成 COM结构的程序
COM文件存储在磁盘上是主存的完全影象,不包含重新定位的加载信息,与 EXE文件相比其加载速度更快,占用的磁盘空间也少
尽管 DOS也为 COM程序建立程序段前缀 PSP,但由于两种文件结构不同,所以加载到主存后各段设置并不完全一样;SampleA.ASM
.model small
.stack
.data
..,;在数据段定义数据
.code
.startup
..,;在代码段填入指令序列
.exit 0
..,;子程序代码
end
简化段定义格式
MASM 6.x支持存储模式伪指令
.MODEL 存储模式
使用简化段定义,必须有存储模式伪指令
,model语句必须位于所有段定义语句之前
存储模式决定一个程序的规模,确定进行子程序调用,指令转移和数据访问的缺省属性
MASM有 7种不同的存储模式:
① TINY ② SMALL
③ COMPACT ④ MEDIUM
⑤ LARGE ⑥ HUGE
⑦ FLAT
TINY微型模式
微型模式是 MASM 6.0才引入的用于创建 COM类型程序
用微型模式编写汇编语言程序时,所有的段地址寄存器都被设置为同一值这意味着代码段,数据段,堆栈段都在同 一个段 内,不大于 64KB;访问操作数或指令都只需要使用 16位偏移地址
SMALL小型模式
一般的程序 ( 例如本书的绝大多数程序示例和习题 ) 都 可用这种模式
在小型模式下,一个程序至多 只能有一个代码段和一个数据段,每段不大于 64KB
这里的数据段是指数据段,堆栈段和附加段的总和,它们共用同一个段基址,总长度不可超过
64KB;因此小模式下程序的最大长度为 128KB
访问操作数或指令都只需要使用 16位偏移地址;
这意味着诸如指令转移,程序调用以及数据访问等都是 近属性 ( NEAR),即小型模式下的调用类型和数据指针缺省分别为近调用和近指针
COMPACT紧凑模式
适合于数据量大但代码量小的程序
紧凑模式下,代码段 被限制在 一个 不大于 64KB的段内;而 数据段则可以有多个,超过 64KB
这种模式下的调用类型缺省仍为近调用;而数据指针缺省为远 ( FAR) 指针,
因为必须用段地址来区别多个数据段
MEDIUM中型模式
中型模式是与紧凑模式互补的模式适合于数据量小但代码量大的程序
中型模式的 代码段可以 超过 64KB,有多个 ;但 数据段只能有一个 不大于 64KB
的段这种模式下的数据指针缺省为近指针;
但调用类型缺省是远 ( FAR) 调用,因为要利用段地址区别多个代码段
LARGE大型模式
较大型程序通常采用的存储模式
大型模式 允许的代码段和数据段都有多个,
都可以超过 64KB;但全部的静态数据 ( 不能改变的数据 ) 仍限制在 64K字节内大型模式下的调用类型和数据指针缺省分别为远调用和远指针
HUGE( 巨型模式 ) 与大型模式基本相同,
只是静态数据不再被限制在 64K字节之内
FLAT平展模式
平展模式用于 创建一个 32位的程序,
它只能运行在 32位 x86 CPU上 。
DOS下不能使用 FLAT模式,
而编写 32位 Windows 9.x或 Windows-
NT的程序时,必须采用 FLAT模式 。
DOS下编程可选择前六种模式,一般可以选用 SMALL模式
TINY模式产生 COM程序,其他模式产生
EXE程序,FLAT模式只能用于 32位程序简化段定义伪指令
.STACK [大小 ] ;堆栈段开始
.DATA ;数据段开始
.CODE [段名 ] ;代码段开始
简化段定义伪指令指明一个逻辑段的开始,同时自动结束前面的一个段采用简化段定义伪指令前,需有,model语句
使用简化段定义,各段名称和其他用户所需的信息可以使用 MASM预定义符号,例如:
@data表示由,data等定义的数据段的段名堆栈段伪指令
.STACK [大小 ]
堆栈段伪指令,STACK创建一个堆栈段,
段名是,stack
它的参数指定堆栈段所占存储区的字节数,默认是 1KB( = 1024 = 400h字节 )
数据段伪指令
.DATA
数据段伪指令,data创建一个数据段,段名是,_DATA。 它用于定义具有初值的变量,当然也允许定义无初值的变量
无初值变量可以安排在另一个段中,它用,data?伪指令创建,数据段名是,_BSS
,const伪指令用于建立只读的常量数据段 ( 段名,CONST)
代码段伪指令
.CODE [段名 ]
代码段伪指令,code创建一个代码段,它的参数指定该代码段的段名
如果没有给出段名,则采用默认段名:
在 TINY,SMALL,COMPACT和 FLAT
模式下,默认的代码段名是,_TEXT
在 MEDIUM,LARGE和 HUGE模式下,
默认的代码段名是:模块名 _TEXT
程序开始伪指令.STARTUP
按照 CPU类型,存储模式,操作系统和堆栈类型,产生程序开始执行的代码;同时还指定程序开始执行的起始点
在 DOS下,还将设置
DS值,调整 SS和 SP值
mov dx,dgroup
mov ds,dx ;设置 DS
mov bx,ss
sub bx,dx
shl bx,1
shl bx,1
shl bx,1
shl bx,1
cli ;关中断
mov ss,dx ;调整 SS和 SP
add sp,bx
sti ;开中断
mov dx,@data
mov ds,dx
程序终止伪指令.EXIT [返回参数 ]
产生终止程序执行返回操作系统的指令代码
它的可选参数是一个返回的数码,通常用 0
表示没有错误 。 例如,exit 0对应的代码是:
mov ax,4c00h
int 21h
DOS功能调用的 4ch子功能 ( 返回 DOS),
入口参数,AH= 4ch,AL=返回数码汇编结束伪指令END [标号 ]
指示汇编程序 MASM到此结束汇编过程
源程序的最后必须有一条 END语句
可选的标号用于指定程序开始执行点,连接程序将据此设置 CS,IP值
采用了,startup伪指令就不需要再用,end
标号,指明开始执行点,但还要有 end伪指令
———— 不要糊涂 ————
程序终止和汇编结束是两码事第 3章 com程序的编写
利用 MASM 6.x的简化段定义格式,可以非常容易地创建一个 COM程序
遵循的规则:
采用 TINY模式
源程序只设置代码段,无数据,堆栈等段
程序必须从偏移地址 100h处开始执行
数据只能安排在代码段中,注意不能与可执行代码相冲突,通常在程序最后
.model tiny ;微型存储模式
.code ;只有代码段
.startup ;程序起始点,= ORG 100H
mov dx,offset string
mov ah,9 ;显示信息
int 21h
mov ah,01h ;等待按键
int 21h
mov ah,02h ;响铃
mov dl,07h
int 21h
.exit 0 ;程序结束点,返回 DOS
string db ‘Press any key to continue !$’;数据安排在此
end ;汇编结束;SampleD.ASM
.model tiny
.code ;只有代码段
.startup ;= org 100h
..,;填入指令序列
.exit 0
..,;子程序代码
..,;在此定义数据
end
COM程序格式
MASM 6.x支持;SampleB.ASM
stack segment stack
dw 512 dup(?)
stack ends
data segment
..,;在数据段定义数据
data ends
code segment ’code’
assume cs:code,ds:data,ss:stack
start,mov ax,data
mov ds,ax
..,;在代码段填入指令序列
mov ax,4c00h
int 21h
..,;子程序代码
code ends
end start
完整段定义格式
MASM 5.x支持完整段定义伪指令段名 segment 定位 组合 段字 '类别 '
..,;语句序列段名 ends
完整段定义由 SEGMENT和 ENDS这一对伪指令实现,
SEGMENT伪指令定义一个逻辑段的开始,ENDS伪指令表示一个段的结束
段定义指令后的 4个关键字用于确定段的各种属性,
堆栈段要采用 stack组合类型,代码段应具有 ‘ code’
类别,其他为可选属性参数
如果不指定,则采用默认参数;但如果指定,注意要按照上列次序段定位 ( align) 属性
指定逻辑段在主存储器中的边界,可为:
BYTE 段开始为下一个可用的字节地址 ( xxxx xxxxb)
WORD 段开始为下一个可用的偶数地址 ( xxxx xxx0b)
DWORD 段开始为下一个可用的 4倍数地址 ( xxxxxx00b)
PARA 段开始为下一个可用的节地址 ( xxxx 0000b)
PAGE 段开始为下一个可用的页地址 ( 0000 0000b)
简化段定义伪指令的代码和数据段默认采用
WORD定位,堆栈段默认采用 PARA定位
完整段定义伪指令的默认定位属性是 PARA,其低 4位已经是 0,所以默认情况下数据段的偏移地址从 0开始段组合 ( combine) 属性
指定多个逻辑段之间的关系,可为:
PRIVATE 本段与其他段没有逻辑关系,不与其他段合并,每段都有自己的段地址 。 这是完整段定义伪指令默认的段组合方式
PUBLIC 连接程序把本段与所有同名同类型的其他段 相邻地连接在一起,然后为所有这些段指定一个共同的段地址,也就是 合成一个物理段 。 这是 简化段定义伪指令默认的段组合
STACK 本段是堆栈的一部分,连接程序将所有 STACK段按照与 PUBLIC段的同样方式进行合并 。 这是 堆栈段必须具有的段组合段字 ( use) 属性
为支持 32位段而设置的属性
对于 16位 x86 CPU来说,它默认是 16
位段,即 USE16
而对于汇编 32位 x86 CPU指令时,它默认采用 32位段,即 USE32;但可以使用 USE16指定标准的 16位段
编写运行于实地址方式 ( 8086工作方式 ) 的汇编语言程序,必须采用 16位段段类别 ( class) 属性
当连接程序组织段时,将所有的同类别段相邻分配
段类别可以是任意名称,但必须位于单引号中
大多数 MASM程序使用 'code','data'
和 'stack’来分别指名代码段,数据段和堆栈段,以保持所有代码和数据的连续指定段寄存器伪指令
ASSUME 段寄存器:段名 [,段寄存器名:段名,...]
通知 MASM用指定的段寄存器来寻址对应的逻辑段,即建立段寄存器与段的缺省关系
在明确了程序中各段与段寄存器之间的关系后,
汇编程序会根据数据所在的逻辑段,在需要时自动插入段超越前缀 。 这是 ASSUME伪指令的主要功能
ASSUME伪指令并不为段寄存器设定初值,连接程序 LINK将正确设置 CS,IP和 SS,SP
由于数据段通常都需要,所以在样板源程序中,
首先为 DS赋值;如果使用附加段,还要赋值 ES
段组伪指令组名 GROUP 段名 [,段名,...]
把多个同类段合并为一个 64KB物理段,并用一个组名统一存取它
定义段组后,段组内各段就统一为一个段地址,
各段定义的变量和标号的偏移地址就相对于段组基地址计算
offset操作符取变量和标号相对于段组的偏移地址,如果没有段组则取得相对于段的偏移地址
offset后可以跟段组中的某个段名,表示该段最后一个字节后面字节相对于段组的偏移地址
stackseg segment stack
db 256 dup(?)
stackseg ends
data1 segment word public 'const'
const1 dw 100
data1 ends
data2 segment word public 'vars'
var1 dw?
data2 ends
datagroup group data1,data2 ;进行段组合
codeseg segment para public 'code'
assume cs:codeseg,ds:datagroup,ss:stackseg
例题 3.5- 1/3
start,mov ax,datagroup
mov ds,ax ;对段组寻址
mov ax,const1 ;ax=100
mov var1,ax ;[var1]=100
mov ax,offset var1 ;ax=2
mov ax,offset data1 ;ax=2
mov ax,offset data2 ;ax=4
例题 3.5- 2/3
assume ds:data2
mov ax,data2
mov ds,ax
mov ax,var1 ;ax=100
mov ax,offset var1 ;ax=2
mov ax,4c00h
int 21h
codeseg ends
end start
例题 3.5- 3/3
段顺序伪指令
.SEG ;按照源程序的各段顺序
.DOSSEG ;按照微软使用的标准 DOS规定
.ALPHA ;按照段名的字母顺序
段顺序伪指令确定各逻辑段在主存的前后位置
完整段定义格式中,默认按照源程序各段的书写顺序安排 ( 即,seg)
采用,model伪指令的简化段定义格式,则是规定的标准 DOS程序顺序 ( 即,dosseg ),
代码段 → 数据段 → 堆栈段主存地址低端 高端
dseg segment word public 'data'
org 100h;设定堆栈段起始段内偏移地址
dw 200 dup(?)
topsp equ this word ;定义栈顶指针
array dw 100 dup(5868h)
dseg ends
cseg segment 'code'
assume cs:cseg,ds:dseg,ss:dseg;dseg既是数据段又是堆栈段例题 3.6- 1/2
start,mov ax,dseg
mov ds,ax
mov ss,ax;数据段与堆栈段具有相同的段地址
mov sp,offset topsp
mov cx,100
xor si,si
again,push array[si]
inc si
inc si
loop again
mov ah,4ch
int 21h
cseg ends
end start
例题 3.6- 2/2
第 3章 简化段定义格式的段属性
采用简化段定义格式的源程序,同样具有段定位,组合,类别以及段组等属性 ( 表 3.4),具有默认的属性
.MODEL伪指令除了设置程序采用的存储模式外,还具有如下语句的作用:
dgroup GROUP _data,_bss,stack
assume cs:_TEXT,ds:dgroup,ss:dgroup
第 3章 教学要求 ( 1)
1,掌握汇编语言语句格式
2,掌握简化段定义 ( 或完整段定义 ) 源程序格式
3,掌握常量表达,变量定义及应用,变量,标号和逻辑段的属性
4,了解数值表达式和 DOS的程序结构
5,掌握汇编语言源程序的编辑,汇编,连接和调试的开发方法第 3章 教学要求 ( 2)
6,掌握基本伪指令和操作符:
EQU/=,+- */,DB/ DW/ DD,? / DUP
ORG/ $,OFFSET/ SEG/ PTR
.MODEL/,STACK/,DATA/,CODE/ END
SEGMENT/ENDS
第 3章 教学要求 ( 3)
7,了解不常使用伪指令和操作符:
.RADIX;逻辑,移位和关系运算符
DF/ DQ/ DT; EVEN/ ALIGN
THIS/ SHORT/ TYPE/ SIZEOF/ LENGTHOF
ASSUME/ GROUP,.SEG/,DOSSEG/,ALPHA;
8,习题 6( p111)
3.22 3.25 3.26
Take a Break