第 4章 伪指令及汇编语言源程序结构第 4章 伪指令及汇编语言源程序结构
4.1 汇编程序结构
4.2 汇编语言语句格式
4.3 伪指令语句
4.4 标号、变量和表达式
4.5 段的组织
4.6 程序段前缀第 4章 伪指令及汇编语言源程序结构
4.1 汇编程序结构
4.1.1 寄存器组和语法元素
1,80x86的可编程的寄存器组
1) 通用寄存器组
EAX,EBX,ECX,EDX,ESI,EDI,EBP和 ESP是 32位可编程的通用寄存器,即程序员编程可以使用的寄存器。其中低 16位用 AX,BX,CX,DX,SI,DI,BP或 SP表示。 AX,BX,CX,DX还可以分成两个 8位寄存器,即低 8位为 AL,BL,CL,DL;高 8位为
AH,BH,CH,DH。
第 4章 伪指令及汇编语言源程序结构
2) 段寄存器
8086有 4个 16位的段寄存器,CS,SS,DS,ES,而 80486有六个 16位的段寄存器,CS,SS,DS,ES,FS和 GS。在实地址方式下,段寄存器的内容左移 4位而得到段基地址。在保护方式下,
段寄存器存放的是描述符的选择符。
3) 指令计数器指令计数器保存下一条指令相对于 CS段基地址的偏移值,
它可作 16位用,也可作 32位用。指令计数器采用 16位段时用 IP,
采用 32位段时用 EIP。调试程序时,(E)IP的值显示的是下条要执行的指令在 CS段中的偏移地址。
第 4章 伪指令及汇编语言源程序结构
4) 标志寄存器
EFLAGS是一个 32位的标志寄存器,可用指令 PUSHFD压入堆栈,指令 POPFD从堆栈弹出。可对 EFLAGS的低 16位 FLAGS单独进行操作,通过 PUSHF将其压入堆栈,POPF从堆栈弹出。
5) 控制寄存器
4个 32位控制寄存器 CR0,CR1,CR2,CR3中的 3个,即 CR0、
CR2,CR3为程序员使用。 Intel公司保留了 CR1。使用 MOV指令传送控制寄存器 CR0,CR2,CR3中的内容。例如,指令 MOV CR0,
EBX实现的功能就是将 EBX的内容送到 CR0中。
第 4章 伪指令及汇编语言源程序结构
6) 调试寄存器
DR4和 DR5为 Intel公司保留,程序员编程时不能使用 DR4和
DR5,其余的调试寄存器的内容可通过 MOV指令传送。例如,指令 MOV EAX,DR6是将调试寄存器 DR6中的内容送到 EAX中。
7) 测试寄存器程序员编程时能使用的测试寄存器只有 TR6和 TR7,其他为
Intel公司保留,则不能使用。例如,指令 MOV ECX,TR7实现的功能就是将 TR7的内容送到 ECX中。
第 4章 伪指令及汇编语言源程序结构
8) 系统地址寄存器
80486用 4个寄存器把在保护模式中常用的数据结构基地址、
限制和其他属性保存起来,以确保其快速性。这 4个寄存器是:
全局描述符寄存器 GDTR、局部描述符寄存器 LDTR、中断描述符寄存器 IDTR和任务寄存器 TR。与这 4个寄存器有关的指令是 LGDT、
LIDT,LLDT,LTR,LGDT或 LIDT,实现的功能就是将内存中六个字节的内容装入 GDTR或 IDTR中。 LLDT或 LTR把寄存器或内存中两个字节的内容装入 LDTR或 TR中,与上述 4条指令传送方向相反的指令是 SGDT,SIDT,SGDT,STR。注意这里任务寄存器 TR与测试寄存器 TR6,TR7的区别。
第 4章 伪指令及汇编语言源程序结构
2.语法规则和语法要素
1) 字符集汇编语言字符集是 ASCII字符集的一个子集,源文件中的每一个字符都应该是下列字符之一,
(1) 字母 26个英文大小写字母;
(2) 数字 0~ 9;
(3) 特殊字符 + - × / ( ) [ ] < > ; ’ 。,
-,? @ $ &;
(4) 定界符 空格符、制表符、回车符 (CR)、换行符 (LF)。
第 4章 伪指令及汇编语言源程序结构程序中出现不在上列字符集中的字符,汇编系统把该字符当作一个逻辑空格符来处理。逻辑空格符就是把多个连续的空格符或制表符当作一个空格符来处理。
在程序中,字母的大小写是无关的,可以互换。但是字符串中的字母大小写是不能互换的,如 ‘ XYZ’与 ‘ xyz’,是不相等的字符串。
第 4章 伪指令及汇编语言源程序结构
2) 标识符一个标识符是程序员用来定义段、变量、标号或常量等项目的名字。一个有效的标识符应遵循以下规则,
(1) 标识符的首位字符必须是一个字母或下述 3个特殊字符之一,? (问号 ),@ (AT符号 ),_ (下划线符号 )
(2) 其余的字符可以是字母、数字或是上面 3个特殊字符,标识符中间不能有分隔符 (逻辑空格或定界符 );
(3) 一个标识符可有长达 255个字符,系统只识别前 31个字符;
(4) 一个程序模块内的每一个标识符只代表而且仅仅代表一个项,在模块的任何地方都可以通过标识符访问它所表示的项。
第 4章 伪指令及汇编语言源程序结构
3) 关键字和保留字汇编语言的关键字和保留字都是系统自己预定义的标识符。
关键字指的是指令助记符,如加法指令 ADD、中断返回指令
IRET等。保留字指的是伪指令或其他功能符号,如 SEGMENT、
DWORD等。
第 4章 伪指令及汇编语言源程序结构
4) 语言符号和分隔符语言符号是源程序中最小的有意义的单元,非常类似英语语句中的单词。汇编语言的语言符号有以下几种:
(1) 一条语句的结束,如换行符 (LF)或回车 /换行符
(CR/LF),用来分开两条汇编语句;
(2) 一个定界符,如逗号,,,和分号,;,;
(3) 一个标识符,如用户定义的 PROGRAM_DATA,FTT等;
第 4章 伪指令及汇编语言源程序结构
(4) 一个常量,如 56DEH,3.1415等;
(5) 一个关键字或保留字,如 SUB,ASSUME等。 ASSUME是一条伪指令语句,其格式、功能和使用方法将在 4.3.2节的
,逻辑段定义伪指令,中讲述。
一个分隔符是一个逻辑空格或一个定界符,在相邻的标识符、常量、关键字、保留字之间,必须用分隔符把它们隔开。
最常用的分隔符是空格。
第 4章 伪指令及汇编语言源程序结构
4.1.2 源程序框架结构
1.源程序结构一个以 MASM为基础的汇编语言源程序的结构形式如例 4-1所示。
例 4-1
NAME MAIN_PROGMODULE
DATA SEGMENT ;定义数据段
(数据定义伪指令序列 )
DATA ENDS
STACK SEGMENT ;定义堆栈段
(数据定义伪指令序列 )
…
…
第 4章 伪指令及汇编语言源程序结构
STACK ENDS
CODE SEGMENT ;定义代码段
ASSUME CS∶CODE,SS∶STACK,DS∶DATA,ES∶DATA
START,MOV AX,DATA ;建立数据段和附加数据段的可寻址性
MOV DS,AX ;置 DS和 ES初值
MOV ES,AX
(用户编写的程序段 )
MOV AH,4CH ;返回操作系统
INT 21H
CODE ENDS
END START
…
第 4章 伪指令及汇编语言源程序结构该源程序结构中的每行语句的用法及含义是:
1) NAME MAIN_PROGMODULE
NAME是保留字,用于定义程序模块的名称,MAIN_MODULE
是程序名称,用户可用任意一个标识符为程序命名。
第 4章 伪指令及汇编语言源程序结构
2) DATA SEGMENT
(数据定义伪指令序列 )
DATA ENDS
DATA是程序员命名的数据段名称。 SEGMENT和 ENDS是保留字,SEGMENT与 ENDS配对使用,ENDS前的 DATA应与 SEGMENT取的
DATA一致。其功能是使用伪指令语句定义数据段、代码段和变量,并可预置变量的初值。
…
第 4章 伪指令及汇编语言源程序结构
3) STACK SEGMENT
(数据定义伪指令序列 )
STACK ENDS
STACK是程序员命名的堆栈段名称。其功能是使用伪指令语句定义堆栈段。
4)CODE SEGMENT
ASSUME CS,CODE,SS,STACK,DS,DATA,ES,DATA
CODE ENDS
CODE是程序员命名的代码段名称,SEGMENT在这里定义一个代码段。
…
…
第 4章 伪指令及汇编语言源程序结构
5) ASSUME CS∶CODE,SS∶STACK,DS∶DATA,ES∶DATA
ASSUME是保留字,指示段寄存器对应前面定义的哪个段。
CS∶CODE,SS∶STACK,DS∶DATA,ES∶DATA 分别指出 CS,SS、
DS和 ES寄存器与 CODE,STACK,DATA段对应。
6) START
START是程序员定义的程序入口处的标号名。用冒号,,,
说明 START是一个标号。
第 4章 伪指令及汇编语言源程序结构
7) 程序部分
START,MOV AX,DATA
MOV DS,AX
MOV ES,AX
(用户编写的程序段 )
MOV AH,4CH
INT 21H
这里是程序员编写的程序。
…
第 4章 伪指令及汇编语言源程序结构
8) CODE ENDS
这条语句指出所定义的 CODE代码段到此结束。
9) END START
END是保留字,指示整个程序模块到此结束。
按上述格式写出的一个程序如例 4-2所示:
第 4章 伪指令及汇编语言源程序结构例 4-2
NAME SIMPLE_EXAMPLE
FIRST_DATA SEGMENT
STRING_DA DB 'This is My First Program $' ;要显示的字符串
FIRST_DATA ENDS
FIRST_STACK SEGMENT PARA STACK ' STACK'
DB 100 DUP(?)
FIRST_STACK END
FIRST_CODE SEGMENT
ASSUME DS∶FIRST_DATA,SS∶FIRST_STACK,CS∶FIRST_CODE
第 4章 伪指令及汇编语言源程序结构
START,MOV AX,FIRST_DATA
MOV DS,AX
MOV DX,STRING_DA
MOV AH,02H
INT 21H ; DOS功能调用
MOV AH,4CH
INT 21H
FIRST_CODE ENDS
END START
第 4章 伪指令及汇编语言源程序结构该程序运行的结果是在屏幕上显示一行字符:,This is
My First Program”。
80x86系列微处理器的存储器采用了分段管理的方法,其汇编语言是以逻辑段为基础,按段的概念来组织代码和数据的,
汇编语言源程序的结构特点有:
(1) 由若干逻辑段组成,各逻辑段由伪指令语句定义和说明。
(2) 整个源程序以 END伪指令结束。
第 4章 伪指令及汇编语言源程序结构
(3) 每个逻辑段由语句序列组成,各语句可以是:
指令语句 —— 完成一定操作功能,能够翻译成机器代码的语句,即为第 3章介绍的指令所形成的语句。指令语句对应于 CPU指令系统中的一条指令,因此为可执行语句。汇编时汇编成目标码。
第 4章 伪指令及汇编语言源程序结构伪指令语句 —— CPU不执行的语句,只是为汇编程序在翻译成汇编语言源程序时提供有关信息,并不翻译成机器代码的语句。因此,伪指令语句是协助汇编系统实现某种特定的操作,
决定程序的数据段、堆栈段和代码段的组织。伪指令语句本身并不完成任何机器指令的功能,但对汇编系统生成的所有操作码是要产生影响的。如:在某程序中:
BUFFERA DB 35H
BUFFERB DW 123AH
SUM DD?
第 4章 伪指令及汇编语言源程序结构就是伪指令语句,其功能是在内存中设置 3个存储单元,单元的名字分别是,BUFFERA,BUFFERB和 SUM。 BUFFERA,BUFFERB的初值是 35H和 123AH,而 SUM单元未定义初值。
宏指令语句 —— 由若干条指令语句形成的语句。一条宏指令语句的功能相当于若干条指令语句的功能。宏指令语句实际上是一个指令序列,汇编时产生对应的目标代码序列。
第 4章 伪指令及汇编语言源程序结构注释语句 —— 以分号,;,开始的说明性语句,汇编程序不予以处理,只起注释作用,使程序易于理解。
空行语句 —— 为保持程序书写清晰,仅包含回车换行符的语句行。
注意:有关逻辑段的定义和说明伪指令,以及其他伪指令 /
指令语句的格式与参数规定等,因汇编程序的类型和版本不同而有所不同。
第 4章 伪指令及汇编语言源程序结构
(4) 80x86汇编语言源程序一般具有数据段、附加数据段、
堆栈段和代码段。但是,根据程序的实际情况,堆栈段、数据段和附加段也可以没有;只有代码段是必不可少的,每个程序至少必须有一个。当然,对于复杂、庞大的源程序,这几种逻辑段也分别允许定义多个。不过允许同时使用的段则是有限定的,8086/8088只允许同时使用 4个段,即堆栈段 (SS)、数据段
(DS)、附加段 (ES)和代码段 (CS)各一个; 80486允许同时使用 6
个段,即除以上 4个段外,还可有 FS和 GS两个附加数据段。在
8086和实地址方式下,每个段的大小可以是 1~ 64 KB;而在保护方式下,80486允许 4 GB。
第 4章 伪指令及汇编语言源程序结构
(5) 由于段寄存器说明伪指令只说明了各段寄存器与逻辑段的关系,并没有设置段寄存器的初值,所以在源程序中,除代码段 CS(有时还有堆栈段 SS)外,其他所有定义的段寄存器的初值都要在程序代码段的起始处由用户自己设置,以建立这些逻辑段的可寻址性。
(6) 每个源程序在其代码段中都必须含有返回到 DOS操作系统的指令语句,以保证程序执行完后能自动返回 DOS状态,可继续向计算机键入命令或程序。终止当前程序,使其正确返回 DOS
状态的方法通常有以下四种:
第 4章 伪指令及汇编语言源程序结构
① 采用 DOS 4CH号功能调用。这种方法在代码段结束前加调用语句:
MOV AH,4CH ;功能号 4CH→AH
INT 21H ;中断调用这种方法在前面的源程序结构中我们已使用过。这是返回 DOS最有效且兼容性最好的一种方法。
第 4章 伪指令及汇编语言源程序结构
② 将主程序定义为远过程。这种方法在代码段开始处按例
4-3所述方式定义主程序:
例 4-3
CODE SEGMENT …
ASSUME …
主过程名 PROC FAR
PUSH DS
MOV AX,0
PUSH AX
RET
主过程名 ENDP
END 主过程名一般也将这种方法称为,标准序,方法。
…
…
…
第 4章 伪指令及汇编语言源程序结构
③ 利用 20号软中断调用。调用方式:
INT 20H
这种方法在产生扩展名为,EXE的可执行文件中是不能使用的,
但可用于小模式的扩展名为,COM的可执行文件中,作为返回 DOS
的一种方法。但是任一汇编语言源程序经汇编、连接之后产生的可执行文件都是扩展名为,EXE类型的,这时如果源程序是按小模式形式编写的,则在连接之后可用 DOS提供的,EXE 2BIN”
转换程序将,EXE文件转换成,COM文件。这样在程序中的 INT
20H指令就可使控制权返回到 DOS。
第 4章 伪指令及汇编语言源程序结构
④ 利用 DOS的 0号功能调用。调用方式:
MOV AH,0
INT 21H
该方式也是只有在,COM格式的可执行文件中才可使用。
第 4章 伪指令及汇编语言源程序结构
4.2 汇编语言语句格式
4.2.1 语句种类根据汇编语言的语法规则,编写汇编语言源程序除了需要用第 3章介绍的指令系统中的指令并满足一定的结构要求外,还要用到伪指令甚至宏指令。汇编语言使用的语句一般包括:指令语句,伪指令语句,宏指令语句。
第 4章 伪指令及汇编语言源程序结构
4.2.2 语句格式本节只介绍指令语句和伪指令语句的格式,有关宏指令语句格式及其使用在第 8章中讲述。
指令语句和伪指令语句的格式基本相同,均由 4部分 (又称 4个域 )组成。其格式分别是:
指令语句,[标号,]助记符 [操作数 ][;注释 ]
伪指令语句,[名字 ]定义符 [操作数 ][;注释 ]
其中,格式中方括号,[ ]”内的内容为可选项。
这两种语句在格式上的主要不同在于,指令语句中的标号后面要加冒号,,,,而在伪指令语句中的名字后面不能跟冒号。
现对格式中的四个部分作如下说明。
第 4章 伪指令及汇编语言源程序结构
1.标号和名字标号和名字分别是给指令单元和伪指令起的符号名称,统称为标识符。标号指出了指令的起始地址。程序员可通过标号来引用所标识的指令,如可作为 JMP和 CALL指令的转移目标,与具体的指令地址相联系。而伪指令语句中的名字一般用作定义变量名、过程名、记录名等,不作为指令的操作数使用。标号可以任选或省略,而名字有时可任选或省略,有时则是强制的,
具体取决于实际的定义符。标号和名字都可由不超过 31个的字符串组成。可选字符集为:
第 4章 伪指令及汇编语言源程序结构
1.标号和名字标号和名字分别是给指令单元和伪指令起的符号名称,统称为标识符。标号指出了指令的起始地址。程序员可通过标号来引用所标识的指令,如可作为 JMP和 CALL指令的转移目标,与具体的指令地址相联系。而伪指令语句中的名字一般用作定义变量名、过程名、记录名等,不作为指令的操作数使用。标号可以任选或省略,而名字有时可任选或省略,有时则是强制的,
具体取决于实际的定义符。标号和名字都可由不超过 31个的字符串组成。可选字符集为:
第 4章 伪指令及汇编语言源程序结构
(1) 字母 A~ Z或 a~ z;
(2) 数字 0~ 9;
(3) 特殊符号 @$- ·:? [] () ; / + - * % &等。
必须注意,标号不允许用数字开头,也不允许用特殊符号单独作为标识符,更不允许用汇编语言中有特定意义的保留字,
如指令助记符、伪指令、寄存器名和运算符等。
第 4章 伪指令及汇编语言源程序结构
2.助记符和定义符助记符和定义符分别用于规定指令语句的操作性质和伪指令语句的伪操作功能,所以统称为操作符。要注意的是,在指令语句的助记符前面,还可根据需要加,前缀,。
第 4章 伪指令及汇编语言源程序结构
3.操作数操作数也叫参数。助记符和定义符都可后跟一个或多个操作数,作为操作处理的对象,当然也可不跟。各操作数之间要用逗号,,,分隔开。
根据寻址方式等因素的不同,操作数可以有 4类:常量、寄存器、存储器和表达式。对常量、存储器和表达式 3种操作数作如下说明。
第 4章 伪指令及汇编语言源程序结构
1) 常量操作数常量操作数可以是二、八、十或十六进制的整型常数,十六进制实数,字符串和已赋值的常数标识符,也可以是寄存器名和 I/O端口地址,如 EAX,SI和 5FH等。
第 4章 伪指令及汇编语言源程序结构
2) 存储器操作数存储器操作数分为标号和变量两种。标号是某条指令所存放单元的符号化地址,这个地址一定在代码段中,它是转移 /调用指令的目标操作数。变量则是数据所存放单元的符号化地址,
它一般位于数据段或堆栈段中,不可能在代码段中。可用各种寻址方式对变量进行存取。
第 4章 伪指令及汇编语言源程序结构作为存储器操作数的标号和变量有三种共同属性:
段值 —— 段基址,可用 SEG运算符求得。
偏移值 —— 段内偏移地址,可用 OFFSET运算符求得。
类型 —— 对变量有字节、字、双字、四字、十字等 5种类型;
对标号有 NEAR和 FAR两种类型。可用 TYPE运算符求得。
除此之外,变量操作数还有另外两个属性:长度和字节数,
可分别用 LENGTH和 SIZE运算符求得。
第 4章 伪指令及汇编语言源程序结构
3) 表达式操作数它由各种操作数、界限符 (如圆括号,( )”、方括号,[ ]”
等 )和运算符组成。汇编时,每个表达式都能产生一个确定的值。
运算符包括:算术运算符、逻辑运算符和关系运算符。操作符有分析操作符和合成操作符两种。
(1) 算术运算符有:加 (+)、减 (-)、乘 (*)、除( /)和求模( MOD)。算术运算符总可以应用于数字操作数,结果也是数字的。应用于存储器地址操作数时,有意义的运算符是加和减。
第 4章 伪指令及汇编语言源程序结构
(2) 逻辑运算符是按位操作的与 (AND)、或 (OR)、异或 (XOR)
和非 (NOT)。逻辑运算符的操作数只能是数字的,且结果也是数字的。存储器地址操作数不能进行逻辑运算。
注意:有些运算符尽管与指令的名字相同,但它们与指令有着本质区别:指令是在程序运行时执行的语句,而运算符是在汇编时由汇编程序完成其功能的。如,AND,OR,XOR和 NOT也是指令助记符。作为运算符使用时,它们是在程序汇编时计算的。而作为指令助记符时,则是在程序执行时计算的。例如第 4章 伪指令及汇编语言源程序结构
AND DX,PORT AND 0FEH
其中第二个 AND是逻辑运算符,在汇编时,计算 PORT AND 0FEH
后,产生一个立即数作为指令的操作数。而第一个 AND是指令助记符,在汇编以后,执行 AND指令时,DX的内容与上述立即数相
,与,,结果放在 DX中。
第 4章 伪指令及汇编语言源程序结构
(3) 关系运算符有相等 (EQ)、不等 (NE)、小于 (LT)、大于
(GT)、小于或等于 (LE)、大于或等于 (GE)。关系运算符连接两个操作数,必须都是数字的或是在同一段内的存储器地址。运算结果始终是一个数字值。若关系是假 (关系不成立 ),则结果为 0;若关系为真,则结果为 0FFFFH。
第 4章 伪指令及汇编语言源程序结构例 4-4
MOV BX,PORT LT 5
若 PORT的值小于 5,则汇编程序将把这条指令汇编为
MOV BX,0FFFFH
否则,若 PORT的值不小于 5,则汇编为
MOV BX,0
第 4章 伪指令及汇编语言源程序结构一般不单独使用关系运算符。因为运算的结果不是 0就是
0FFFFH,没有别的选择,所以,常与其他运算符组合起来使用。
例如:
MOV BX,((PORT LT 5) AND 20) OR ((PORT GE 5)
AND 30)
当 PORT的值小于 5时,上述指令将汇编为
MOV BX,20
否则为 MOV BX,30
第 4章 伪指令及汇编语言源程序结构
(4) 分析操作符和合成操作符。分析操作符也叫分解操作符,可从变量或标号中分解出某些属性值,把存储器操作数分解为它的组成部分;合成操作符也叫属性操作符,可用来改变原有变量或标号的类型,把组成部分综合为存储器操作数。分析操作符有,SEG(返回段基址),OFFSET(返回偏移地址)、
LENGTH(返回变量单元数),TYPE(返回元素字节数),SIZE
(返回变量总字节数),返回的运算结果分别是:段基址、偏移地址、单元数、字节数和总字节数。
分析操作符和合成操作符将在 4.3.1节中作详细介绍。
第 4章 伪指令及汇编语言源程序结构
4.注释注释部分以分号开始,其作用与注释语句相同。注释语句是对后跟程序段的功能加以说明,而以分号开始的注释是对语句的功能加以说明,目的在于增加程序的可读性。注释部分不被汇编程序汇编,也不被执行,只对源程序起说明作用。
第 4章 伪指令及汇编语言源程序结构
4.3 伪 指 令 语 句
4.3.1 符号 /数据 /标号定义伪指令语句
1.符号定义伪指令符号定义伪指令可用来为表达式赋予一个符号名,表达式可以是常数、变量、标号、指令语句和字符等。在程序中,任何需要这种表达式的地方都可使用被赋予的符号名来代替它。
符号定义伪指令语句有两种,即等值语句和等号语句。
第 4章 伪指令及汇编语言源程序结构
1) 等值语句 (EQU)
格式:符号名 EQU 表达式功能:用符号名代替表达式的值,供以后引用。
说明,EQU语句不能重新定义,即在同一源程序中,用它定义的符号名不能再赋予不同的值。使用 EQU语句时,必须先赋值后使用。
例 4-5 下面是等值语句的例子。
X EQU 50
Y EQU X+10
COUNT EQU CX
第 4章 伪指令及汇编语言源程序结构
2) 等号语句 (=)
格式:符号名=表达式功能:等号语句的功能与 EQU语句的功能相同,只是其符号名可以再定义。
例 4-6 下面是等号语句的 3个例子。
PORT1= 30H
PORT1= PORT1+ 20H
PORT1= 325 * 8
第 4章 伪指令及汇编语言源程序结构
2) 数据定义伪指令格式,[符号名 ] DB/DW/DD/DF/DQ/DT 初值序列功能:为数据项分配一个或多个字节 /字 /双字 /长字 /四字
/十字节的存储空间,给它们赋初值,并用一个符号名与之相联系。
第 4章 伪指令及汇编语言源程序结构说明:
(1) 数据定义伪指令按数据长度可分为 DB,DW,DD,DF、
DQ,DT 6种类型,分别定义 8位,16位,32位,48位,64位、
80位数据。具体地讲就是:
● DB指一个操作数占用一个字节单元,定义的变量为字节变量;
● DW指一个操作数占用一个字单元 (2个字节单元 ),定义的变量为字变量;
● DD指一个操作数占用一个双字单元 (4个字节单元 ),
定义的变量为双字变量;
第 4章 伪指令及汇编语言源程序结构
● DF指一个操作数占用一个三字单元 (6个字节单元 ),定义的变量为三字变量,该助记符仅用于 386以上的 CPU,定义的变量作为指针使用,其低 4字节存放偏移地址,高 2字节存放段地址;
● DQ指一个操作数占用一个四字单元 (8个字节单元 ),定义的变量为四字变量;
● DT指一个操作数占用 10个字节单元,定义的变量为十字节变量,使用该助记符时,对于十进制操作数,必须给出后缀 D,没有后缀的默认为压缩 BCD码。
第 4章 伪指令及汇编语言源程序结构
(2) 与数据项相联系的符号名称为变量,经过定义的变量名有 3个属性:数据类型 (字节、字、双字、长字、四字、十字 )、
偏移量 (可用 OFFSET运算符获得 )和段基址 (可用 SEG运算符求得 ),
符号名为可选项。
第 4章 伪指令及汇编语言源程序结构
(3) 给变量赋初值:
① 可以是赋确定的值,也可以是赋用,?,表示不确定的值。赋不确定值,实质是不赋值,而只预留规定长度的存储空间。
② 初值序列可以是一个元素,也可以是用逗号分隔的多个元素。
③ 用 DUP运算符建立单个值的多次拷贝,确定值可以是整数、浮点数 (只允许 DD,DQ和 DT伪指令,并只用于 80486和
80387/80287协处理器上 )、字符、字符串或表达式。
第 4章 伪指令及汇编语言源程序结构例 4-7
VAR1 DB? ;给变量 VAR1分配一个字节,但不赋初值
VAR2 DD? ;给变量 VAR2分配 4个字节,但不赋初值
XY DT 3456H ;给变量 XY分配 10个字节,初值为 3456H
STR1 DB 'ABCDE' ;给字符串分配 5个字节,并赋初值 (ASCII码 )
ARRAY DW 20 DUP(1) ;给数组变 ARRAY分配 20个字,初值均为 1
BUFF DB 6 DUP(? ) ;相当于 DB?,?,?,?,?,?
COUNT DB 25,35,45 ;给变量 COUNT分配 3个字节,并赋初值。
第 4章 伪指令及汇编语言源程序结构
(4) 对操作数的说明。
① 操作数是常数或表达式 (代表的是数据或内存单元地址 )。
例 4-8 操作数是数据的定义形式。
DATAB DB 18H,-1,30 ;每个数占用一个字节单元
DATAW DW 18H,2A45H ;每个数占用一个字单元
DATAD DD 18H,2F3A124BH ;每个数占用一个双字单元第 4章 伪指令及汇编语言源程序结构在内存中的存储情况如图 4-1所示。
说明:操作数可用各种进制形式书写,汇编程序将其转换成相应的补码存入内存单元中。同样一个数 (如 18H),由于数据定义助记符的不同,所占用的内存空间是不一样的。数据的高字节存放在高地址单元,低字节存放在低地址单元。
第 4章 伪指令及汇编语言源程序结构图 4-1 内存中的存储情况
18
FF
1E
18
00
45
2A
18
00
00
00
4B
12
3A
2F
D A T A D
D A T A W
D A T A B
第 4章 伪指令及汇编语言源程序结构例 4-9 操作数是地址的定义形式。
ADDR1 DW NEXT ;存放偏移地址
ADDR2 DD NEXT ;存放偏移地址和段地址
NEXT,MOV AL,34H
NEXT是一条指令的标号,表示这条指令所在单元的地址,
ADDRW是一个字单元,只存放偏移地址,ADDRD是一个双字单元,
存放的是偏移地址和段地址,存储情况如图 4-2所示。
第 4章 伪指令及汇编语言源程序结构图 4-2 偏移地址和段地址偏移地址低字址偏移地址高字址偏移地址低字址偏移地址高字址段地址低字址段地址高字址
A D D RW
A D D RD
第 4章 伪指令及汇编语言源程序结构
② 操作数是字符串时,内存中存放的是每个字符的 ASCII码。
例 4-10 下面 3个定义语句是等价的。
STR1 DB 'ABCD'
STR1 DB 'A','B','C','D'
STR1 DB 41H,42H,43H,44H
第 4章 伪指令及汇编语言源程序结构例 4-11 下面两个定义语句是等价的。
STR2 DB,'AB'
STR2 DW,'BA'
当定义的字符串中字符多于两个时,只能使用 DB定义,不能使用 DW。例如,定义 STR3 DW,'ABCD'是错误的。
第 4章 伪指令及汇编语言源程序结构
③ 操作数是,?”,此时只分配单元,不定义初值。例如:
BUF1 DB 5,6,7,?
BUF2 DW 56H,78H,?,345FH
第 4章 伪指令及汇编语言源程序结构
④ 复制操作符 DUP。操作数用复制操作符 DUP,表示操作数重复若干次。例如:
BUFFER1 DB 2 DUP(2,3,4)
等价于 BUFFER1 DB 2,3,4,2,3,4
BUFFER2 DW 1,2,3 DUP(6)
等价于 BUFFER2 DW 1,2,6,6,6
BUFFER3 DB 2 DUP(5,6,3 DUP(7))
等价于 BUFFER3 DB 5,6,7,7,7,5,6,7,7,7
第 4章 伪指令及汇编语言源程序结构
(5) 指令单元 NEAR和 FAR。一个指令单元能出现在一个
JMP或 CALL指令语句中。若这个单元的类型是 NEAR,汇编程序将产生一个段内 JMP或 CALL指令;若单元的类型是 FAR,则产生一个段间 JMP或 CALL指令。 — 个 NEAR指令单元规定了 — 个长度为两个字节的指针,即此指令单元在段内的地址偏移量。获取了此地址偏移量,就可以实现段内的转移和调用。一个 FAR指令单元规定了一个长度为四个字节的指针,即此指令单元所在段的段地址和段内的地址偏移量。只有获取了这四个字节,才能得到一个 FAR指令单元的全地址,才能实现段间的调用和转移。
第 4章 伪指令及汇编语言源程序结构例 4-12
CYCLE,CMP SUM,100
若存储单元 CYCLE的类型是 NEAR,当汇编程序遇到指令
JMP CYCLE
时,就产生一个段内 JMP指令。
从一个存储单元加或减一个数字值形成的新的存储器地址与原存储单元有相同的类型。若 SUM,BIG,CYCLE分别是字节型、
字型,NEAR型指令单元,则 SUM+2,BIG-3,CYCLE+1也分别是字节型、字型,NEAR型指令单元。
第 4章 伪指令及汇编语言源程序结构
3.除定义伪指令 PURGE
格式,PURGE 符号 1,符号 2,…,符号 n
功能:解除指定符号的定义,解除符号定义后,可用 EQU重新定义。
例 4-13 执行指令
DATA EQU 7
PURGE DATA
后,DATA可重新用 EQU进行定义。
DATA EQU 28
第 4章 伪指令及汇编语言源程序结构
4.标号定义伪指令 (LABEL)
格式:符号名 LABEL 类型功能:将紧跟在本伪指令语句后的标号、操作码、过程或变量建立新的符号名,并刷新其类型属性。对标号、操作码或过程,其类型为 NEAR,FAR;对变量,其类型为 TYTE,WORD、
DWORD,FWORD,QWORD或 TBYTE。
第 4章 伪指令及汇编语言源程序结构说明,LABEL伪指令提供了另一种定义标号或变量名的方法,
但它并不为符号名分配存储空间。如:
SUBRF LABEL FAR ;远调用入口
SUBRN,… ;近调用入口两个标号 SUBRF与 SUBRN均指向同一条指令,但由于它们的类型不同 (SUBRF是 FAR,而 SUBRN后有冒号,其类型隐含为 NEAR),
所以可用不同的调用方法 (远或近 )来访问标号所指的程序段,
即其他代码段可通过远标号 SUBRF来访问该程序段,而当前代码段可通过近标号 SUBRN来访问该程序段。
…
第 4章 伪指令及汇编语言源程序结构再如:
BAARAY LABEL BYTE
ARRAY DW 200 DUP(? )
MOV AL,[99] ;取数组的第 100个字节值 → AL
MOV AX,[98] ;取数组的第 99个字值 → AX
…
…
第 4章 伪指令及汇编语言源程序结构这里用两种方法定义了数组。由于 LABEL伪指令不为变量分配存储空间,因此 BARRAY与 ARRAY的地址实际上是相同的,即它们指向同一个数组,只是 BARRAY被定义为字节型,而 ARRAY被定义为字型。这样,可根据需要按不同类型去存取数组中的数据。
第 4章 伪指令及汇编语言源程序结构
5.分析和合成操作符
(1) 分析操作符把存储器地址操作数分解成它们的组成部分。这些操作符是 SEG,OFFSET,TYPE,SIZE,LENGTH。
① SEG操作符。
格式,SEG <变量或标号 >
功能:计算变量或标号的段地址,即返回存储器地址操作数所在段的段地址部分。
第 4章 伪指令及汇编语言源程序结构
② OFFSET操作符。
格式,OFFSET <变量或标号 >
功能:计算变量或标号的段内偏移地址,即返回地址的段内偏移量部分。
例 4-14 说明指令 MOV AX,SEG DATA和 MOV SI,OFFSET
DATA的功能。
指令 MOV AX,SEG DATA的功能是把 DATA的段地址存入 AX寄存器中,指令 MOV SI,OFFSET DATA的功能是把 DATA的偏移地址存入 SI寄存器中,等价于指令 LEA SI,DATA。
第 4章 伪指令及汇编语言源程序结构
③ TYPE操作符。
格式,TYPE <变量或标号 >
功能:计算变量的类型值或标号的类型值,即返回一个数字值,它表示存储器操作数的类型部分。
各种存储器地址操作数类型部分的值如下:
第 4章 伪指令及汇编语言源程序结构存储器操作数 类型部分字节数据 1
字数据 2
双字数据 4
长字数据 6
四字数据 8
十字数据 10
NEAR指令单元 - -1
FAR指令单元 -2
第 4章 伪指令及汇编语言源程序结构从此表可看出,用 DB,DW,DD,DF,DQ,DT定义的变量对应的类型值分别为 1,2,4,6,8,10; NEAR,FAR型标号对应的类型值分别为 -1,-2。注意:字节、字、双字、长字、四字和十字的类型部分,分别是它们所占有的字节数,而指令单元的类型部分的值没有实际的物理意义。若 TYPE放在一个结构名前,则返回此结构所占用的字节数。
第 4章 伪指令及汇编语言源程序结构
④ LENGTH和 SIZE操作符只应用于数据存储器地址操作数。
格式,LENGTH <变量 >
功能:返回一个与存储器地址操作数相联系的单元数,对于使用 DUP定义的变量,计算分配给该变量的单元数,其他变量的 LENGTH值为 1。
格式,SIZE <变量 >
功能:返回一个为存储器地址操作数分配的字节数,即计算分配给该变量的字节数,其值为 TYPE和 LENGTH的乘积。
第 4章 伪指令及汇编语言源程序结构例 4-15 若 MULT_WORDS定义为
MULT_WORDS DW 50 DUP(0)
则 LENGTH MULT_WORDS是 50,而 SIZE MULT_WORDS是 100,即
SIZE X= (LENGTH X)× (TYPE X)
(2) 合成操作符由地址部分建立存储器地址操作数,这些操作符是,PTR和 THIS。
第 4章 伪指令及汇编语言源程序结构
① PTR操作符。
格式:类型 PTR 表达式类型可以是 BYTE,WORD,DWORD,NEAR,FAR。
功能:给表达式 (一般是变量或标号 )指定类型,不管它原来有无类型或是什么类型,均以 PTR前的类型为准。对于变量,可以指定的类型是 BYTE(字节 ),WORD(字 ),DWORD(双字 );对于标号,可以指定的类型是 NEAR(段内引用型 ),FAR(段间引用型 )。
PTR操作符建立一个存储器地址操作数,它与其后的存储器地址操作数有相同的段地址偏移量,但有不同的类型。不像一个数据定义语句,PTR操作符并不分配存储器,它可以给已分配的存储器一个另外的意义。
第 4章 伪指令及汇编语言源程序结构例 4-16 若 TWO_BYTE定义为
TWO_BYTE DW?
于是能给 TWO_BYTE的第一个字节定义为
ONE_BYTE EQU BYTE PTR TWO_BYTE
这里,PTR操作符建立了一个与 TWO_BYTE有相同的段和偏移量的新的存储器地址操作数,但它的类型部分是字节。可以给第二个字节定名为
OTHER_BYTE EQU BYTE PTR TWO_BYTE+1
或简单地定义为
OTHER_BYTE EQU ONE_BYTE+1
第 4章 伪指令及汇编语言源程序结构例 4-17 用 PTR操作符建立字和双字。
MANY_BYTES DB 100 DUP(?) ;一个 100个字节的矩阵
FIRST_WORD EQU WORD PTR MANY_BYTES ; 50个字
SECOND_DOUBLE EQU DWORD PTR MANY_BYTES ; 25个双字第 4章 伪指令及汇编语言源程序结构例 4-18 设 INCHES的类型是 NEAR,使用 PTR运算符为 MILES
建立 FAR型的指令单元。
INCHES,CMP SUM,100
JMP INCHES ;段内转移
MILES EQU FAR PTR INCHES ; MILES类型是 FAR
JMP HILES ;段间转移第 4章 伪指令及汇编语言源程序结构
② THIS操作符。像 PTR一样,合成操作符 THIS可用来建立一个特殊类型的存储器地址操作数,而没有为它分配存储器。
新的存储器地址操作数的段和偏移量部分,就是下一个能分配的存储单元的段和偏移量。
格式,THIS <属性或类型 >
功能:将变量或标号定义成指定的类型,但并不分配新的存储单元,其寻址空间与跟在后面的变量的寻址空间相同。对于变量,类型可以是 BYTE,WORD,DWORD,对于标号,类型可以是 NEAR,FAR。
第 4章 伪指令及汇编语言源程序结构例 4-19 定义:
HY_BYTE EQU THIS BYTE
HY_WORD DW?
后,将建立 HY_BYTE具有字节类型,且与 HY_WORD具有相同的段和偏移量部分。在这个例子中,HY_BYTE也可用 PTR操作符建立:
HY_BYTE EQU BYTE PTR HY_WORD
第 4章 伪指令及汇编语言源程序结构也可使用 THIS操作符建立 FAR指令单元:
MILES EQU THIS FAR
CMP SUM,100
JMP MILES
…
第 4章 伪指令及汇编语言源程序结构注意:上例中使用 THIS操作符,并不需要有一个与 MILES
具有相同的段和偏移量的 NEAR指令单元。但若用 PTR操作符代替 THIS这样的 NEAR指令是需要的。
说明:用数据定义伪指令,定义的变量是有类型的。在指令中使用变量作操作数时,要注意其类型与其他操作数的匹配。
第 4章 伪指令及汇编语言源程序结构例 4-20 如果有数据定义伪指令
OPDATA1 DB 23H,4AH
OPDATA2 DW 127FH,25A6H
则如下两条指令是错误的,
MOV BX,OPDATA1 ; BX为字寄存器,OPDATA1为字节变量
MOV AL,OPDATA2 ; AL为字节寄存器,OPDATA2为字变量第 4章 伪指令及汇编语言源程序结构使用合成操作符 PTR,书写成如下形式才是正确的:
MOV BX,WORD PTR OPDATA1 ; BX为字寄存器,OPDATA1为字变量
MOV AL,BYTE PTR OPDATA2 ; AL为字节寄存器,OPDATA2为字节变量指令执行后,BX=4A23H,AL=7FH。
第 4章 伪指令及汇编语言源程序结构
6.操作符及运算符的优先权级的规定操作符及运算符的优先权级按如下顺序,从高到低排列为:
① 圆括号,(记录中使用的 )尖括号、方括号,(结构中使用的 )圆点符,LENGTH,SIZE,WIDTH,MASK。
② PTR,OFFSET,SEG,TYPE,THIS、段寄存器名,(加段前缀 )。
③ *,/,MOD(求模 ),SHL,SHR。
④ HIGH,LOW(操作数高、低字节 )。
第 4章 伪指令及汇编语言源程序结构
⑤ +、-。
⑥ EQ,NE,LT,LE,GT,GE。
⑦ NOT。
⑧ AND。
⑨ OR,XOR。
⑩ SHORT。
当各种运算符同时出现于同一表达式中时,具有不同的优先级。优先级相同的运算符操作顺序为先左后右。
第 4章 伪指令及汇编语言源程序结构
4.3.2 程序结构伪指令语句
1.方式选择伪指令方式选择伪指令又称指令集选择伪指令。这是汇编程序为区分使用的是哪种 CPU执行程序而提供的选择处理器的伪指令。
每种处理器的指令系统都有一个汇编执行语句集合,也就是通常所称的指令集,处理器方式选择伪指令本质上就是指令集选择伪指令。这些指令的一个共同特点是,使用时用一点,,”为引导,程序中放在段外,一般放在程序的开始处,对整个源程序起作用。,586和,586P用于 MASM6.11以上的汇编语言版本,其他的可用于 MASM5.0以上的汇编语言版本。
第 4章 伪指令及汇编语言源程序结构
(1),8086:默认方式,此伪指令可以省略,选择
8086/8088指令集,即汇编程序只接受 8086/8088指令。
(2),286/.286C:选择 80286指令集。,286不包括特权指令,
汇编程序只接受 8086/8088及 80286非保护方式 (即实地址方式 )下的指令,用,8086可删除该伪指令。
(3),286P:选择 80286指令集。,286P包括特权指令,允许汇编程序接受 8086/8088及 80286的所有指令 (包括保护方式和非保护方式下的指令 )。该伪指令一般只有系统程序员使用,并可用,8086伪指令删除。
第 4章 伪指令及汇编语言源程序结构
(4),386/.386C:选择 80386指令集。,386不包括特权指令。允许汇编 8086/8088及非保护方式下的 80286/80386指令。
与,286/.286C类似,在此方式下将禁止所有保护方式下的指令出现,否则将出错。可用,8086删除。
(5),386P:选择 80386指令集。,386P包括特权指令,除具有,386/.386C功能外,还允许汇编保护方式下的 80286/80386
指令。一般只有系统程序员使用,并可用,8086伪指令删除。
(6),8087/.287/.387:分别选择 8087,80287和 80387数字协处理器指令集,并指定实数的二进制码为 IEEE格式。
第 4章 伪指令及汇编语言源程序结构
(7),486/.486P:选择 80486指令集,.486不包括特权指令。与,386/.386C类似,允许汇编 80486非保护方式下的指令。
(8),486P:选择 80486指令集,.486包括特权指令。
与,386P类似,允许汇编 80486的全部指令。
(9),586/.586P:选择 Pentium指令集,不包括特权指令,.586P包括特权指令。
第 4章 伪指令及汇编语言源程序结构
2.逻辑段定义伪指令逻辑段定义的方法有两种:完整段定义和简化段定义。使用 MASM5.0以上的汇编语言版本中,既可定义完整段,也可定义简化段;在低于 MASM5.0的版本中,只能定义完整段。
1) 完整段定义伪指令采用完整段定义伪指令可具体控制汇编程序 (MASM)和连接程序 (LINK)在内存中组织代码和数据的方式。它包括 3种伪指令语句:
第 4章 伪指令及汇编语言源程序结构
(1) 段定义语句 (SEGMENT/END)。
格式:段名 SEGMENT [定位类型 ][组合类型 ] [‘类别 ’ ]
[属性类型 ]
(段体 )
段名 ENDS
功能:指出段名及段的各种属性,并表示段的开始和结束位置 (地址 )。
说明:段名是用户定义的段的标识符,用于指明段的基址。
SEGMENT后面有 4个可选参数,分别代表段的 4种属性。
…
…
第 4章 伪指令及汇编语言源程序结构
① 定位类型用于规定段的起始地址要求,即指定该段起点的边界类型,有 5种可选类型,默认方式为 PARA。
PARA(节 ):段起始地址从段边界开始 (必为 16的倍数 ),段起始单元 20位地址的最低 4位二进制位必为 0。
BYTE(字节 ):段起始地址从字节边界开始,即该段可以从任何单元开始。
WORD(字 ):段起始地址从字边界开始 (必为偶数 ),段起始单元 20位地址的最低 1位二进制位必为 0。
第 4章 伪指令及汇编语言源程序结构
DWORD(双节 ):段起始地址从双字边界开始 (必为 4的倍数 ),
段起始单元 20位地址的最低 2位二进制位必为 0,一般用于
80386的 32位段中。
PAGE(页 ):段起始地址从页边界开始 (必为 256的倍数 ),
段起始单元 20位地址的最低 8位二进制位必为 0。
第 4章 伪指令及汇编语言源程序结构
② 组合类型用于告诉 LINK程序本段与其他模块中同名段的组合连接关系,有五种可选组合类型:
PUBLIC,LINK程序将不同模块中具有该类型且段名相同的段连接到同一个物理段中,使它们公用一个段地址。
STACK:与 PUBLIC同样处理,只是连接后的段为堆栈段。
LINK程序在连接过程中自动将新段的段地址送到 SS段寄存器,
新段的长度送到 SP寄存器中。如果在定义堆栈段时没有将其说明为 STACK类型,那么就需要在程序中用指令设置 SS和 SP寄存器的值,此时 LINK程序将会给出一个警告信息。
第 4章 伪指令及汇编语言源程序结构
COMMON:产生一个覆盖段。 LINK程序为该类型的同名段指定相同的段地址。段的长度取决于最长的 COMMON段的长度。段的内容为所连接的最后一个模块中的内容及其没有覆盖到的前面 COMMON段的部分内容。
MEMORY,LINK程序不单独区分 MEMORY类型,它把 MEMORY与
PUBLIC类型同等对待。 MASM程序允许使用它主要是为了与其他支持 Intel MEMORY类型的连接程序兼容。
第 4章 伪指令及汇编语言源程序结构
AT表达式,LINK程序将具有 AT类型的段装在表达式值所指定的段地址边界上。这个类型可以为标号或变量赋予绝对地址,
以便程序以标号或变量的形式存取这些存储单元的内容。一般在 AT类型的段中不定义指令或数据,只说明一个地址结构。
第 4章 伪指令及汇编语言源程序结构例 4-21
STUEF SEGMENT AT 0 ;段地址为 0
ORG,410H ;偏移地址为 410H
EQUIPMENT LABEL WORD ;标号 EQUIPMENT的绝对地址为 0000,0410
STUEF ENDS
在保护方式中,AT类型无意义。
若此属性缺省,表示段是独立的,不与其他同名段发生联系,并有自己的段起始地址。
第 4章 伪指令及汇编语言源程序结构
③ 属性类型选择用于定义段中使用的偏移地址和寄存器的字长。该选择只用于设置含有,386和,486语句的段。有两种属性类型可供选择:
USE16—— 选择 16位段,按 16位方式寻址,最大段长为 64 KB。
USE32—— 选择 32位段,按 32位方式寻址,最大段长可达 4 GB。
如果属性类型选择缺省,则在使用,386/.486伪指令时默认为 USE32。
第 4章 伪指令及汇编语言源程序结构
④ ‘类别 ’ 用于控制段的存放次序。它可以是任何合法的名称,但必须用单引号括起来。 LINK程序只使同类别段发生关系,并将它们存放在连续的存储空间中。若 ‘ 类别 ’ 选择项缺省,则表明该段类别为空。
第 4章 伪指令及汇编语言源程序结构
(2) 段寄存器说明语句 (ASSUME)。
格式,ASSUME 段寄存器:段名 /组名 [,段寄存器:段名 /
组名,… ]
功能:说明源程序中定义的段或组由哪个段寄存器去寻址,
它指出了段与段寄存器的关系,并确定某个段分配给哪个段寄存器,以便汇编程序知道段的结构和在执行各种指令时知道应访问哪一个段。段寄存器可以是 CS,SS,DS,ES,FS或 GS。
第 4章 伪指令及汇编语言源程序结构说明:段寄存器 CS只能用于包含有程序的段,反之,含有程序的段也只能以 CS作段寄存器。 SS只能与堆栈段对应。 CS所对应的段名必须在该语句之前有定义,因此,ASSUME语句一般都设置于代码段内,放在段定义语句之后,是说明性语句。
除主程序的代码段及最后一个堆栈段之外,其余段寄存器的初值均由用户在程序中设置的参数,NOTHING”表示取消以前指定的段寄存器。如果各段寄存器的指定都取消,则可写成如下形式:
ASSUME NOTHING
第 4章 伪指令及汇编语言源程序结构例 4-22 3个数相加并把结果存放在 SUM单元中,用完整段定义结构的程序。
DATA SEGMENT ;段定义开始
BUF DB 35H,78H,0A5H ;定义数据
SUM DB? ;定义存放累加和的单元
DATA ENDS ;段定义结束
CODE SEGMENT ;段定义开始
ASSUME CS∶CODE,DS∶DATA ;规定段的性质
START,MOV AX,DATA
MOV DS,AX ;设置 DS的值第 4章 伪指令及汇编语言源程序结构
MOV AL,0 ;累加器清 0
MOV SI,OFFSET BUF ; BUF首地址送 SI
ADD AL,[SI] ;累加第 1个数
INC SI ;地址指针增 1
ADD AL,[SI] ;累加第 2个数
INC SI ;地址指针增 1
ADD AL,[SI] ;累加第 3个数
MOV SUM,AL ;存储累加和
MOV AH,4CH
INT 21H ;返回 DOS
CODE ENDS ;段定义结束
END START ;源程序结束第 4章 伪指令及汇编语言源程序结构
(3) 组定义语句 (GROUP)
格式:组名 GROUP段名 [,段名,… ]
功能:将 GROUP定义符后指定的所有段分配在一个 64 KB的物理段中,并赋予该段一个名字 —— 组名。
说明:组名是用户定义的名字,是指出组的始地址的一种符号,必须是惟一的,不能与任何标号、段名及变量等同名。
段名可以是用 SEGMENT语句定义的或者由 SEG运算符得到的。
第 4章 伪指令及汇编语言源程序结构组定义语句不影响各段的次序,因此组内各段不一定连续存放,但它们都必须包含在 64 KB中。如果组名在语句中已说明,
且相应段寄存器 (DS,ES,FS或 GS)有初始化语句,则系统把所有组内各段中的变量或标号的偏移地址调整为相对于组的起始地址。但是属性常数,变量,没有调整,它还是相对于段始址的偏移值。需要相对于组名地址的偏移值时,可用:
OFFSET组名:变量 ;组名在这里相当于段前缀该语句可使定义在源程序中不同类型的段运行时共用同一个段寄存器,但这些段仍为独立的段。这与 SET语句中的 PUBLIC
组合类型不同,PUBLIC组合类型是将同名段组合成为一个段。
第 4章 伪指令及汇编语言源程序结构
2) 简化段定义伪指令简化段有利于实现汇编语言程序模块与 Microsoft高级语言程序模块的连接,它可以由操作系统自动安排段序,自动保证名字定义的一致性。但是命令文件 (.COM)的编程不可使用简化段定义。
(1) 段次序语句 (DOSSEG)。
格式,DOSSEG
功能:各段在内存的顺序按 DOS段次序约定排列。
说明:各段在内存的次序决定于很多因素,多数程序对段次序无明确要求,可由操作系统安排。本语句用于主模块前面,
其他模块不必使用。
第 4章 伪指令及汇编语言源程序结构
(2) 内存模式语句 (.MODEL)。
格式,.MODEL 模式类型 [,高级语言 ]
功能:指定数据和代码允许使用的长度。
说明,[高级语言 ]是可选项,可使用 C,BASIC,FORTRAN、
PASCAL,SYSCALL,STDCALL等关键字来指定和哪种高级程序设计语言接口,还可用关键字 OS_OS2或 OS_DOS告诉使用的是哪种操作系统。程序中凡数据或代码的长度不大于 64 KB时为近程,
否则为远程。近程的数据通常定义在一个段中,对应一个物理段,只要程序一开始设置其段值于 DS中,以后数据的访问只改变偏移值,不改变段值。
第 4章 伪指令及汇编语言源程序结构本语句一般放在用户程序中其他简化段定义语句前。可选内存模式有 5类:
SMALL:小模式。数据、代码各放入一个物理段中,均为近程。
MEDIUM:中模式。数据为近程,代码允许为远程。
COMPACT:压缩模式。代码为近程,数据允许为远程,但任一个数据段所占内存不可超过 64 KB。
第 4章 伪指令及汇编语言源程序结构
LARGE:大模式。数据与代码均允许为远程。但任一个数据段不可超过 64 KB。
HUGE:巨型模式。数据与代码均允许为远程,且数据语句所占内存也可大于 64 KB。
当独立的汇编语言源程序不与高级语言程序连接时,多数情况下只用小模式即可,而且小模式的效率也最高。
第 4章 伪指令及汇编语言源程序结构
(3) 段语句。简化段定义的段语句有以下几种:
① 代码段语句。
格式,.CODE [名字 ]
功能:定义一个代码段。如有多个代码段,要用名字区别。
② 堆栈段语句。
格式,.STACK[长度 ]
功能:定义一个堆栈段,并形成 SS及 SP初值。 (SP)=长度,
如省略长度,则 (SP)= 1024。
第 4章 伪指令及汇编语言源程序结构
③ 初始化近程数据段语句。
格式,.DATA
功能:定义一个近程数据段。当用于与高级语言程序连接时,其数据空间要赋初值。
④ 非初始化近程数据段语句。
格式,.DATA?
功能:定义一个近程数据段。当用于与高级语言程序连接时,其数据空间只能用,?”定义,表示不赋初值。
第 4章 伪指令及汇编语言源程序结构
⑤ 常数段语句。
格式,.CONST
功能:定义一个常数段。该段是近程的,用于与高级语言程序连接。段中数据不能改变。
⑥ 初始化远程数据段语句。
格式,.FARDATA [名字 ]
功能:定义一个远程数据段,且其数据语句的数值应赋初值。用于与高级语言程序连用。
第 4章 伪指令及汇编语言源程序结构
⑦ 非初始化远程数据段语句。
格式,.FARDATA? [名字 ]
功能:定义一个远程数据段,但其数据空间不赋初值,只能用,?”定义数值。用于高级语言程序连用。
第 4章 伪指令及汇编语言源程序结构例 4-23 三个数相加并把结果存放在 SUM单元中,用简化段定义结构程序。
.MODEL SMALL ;选用小模式
.DATA ;数据段定义
BUF DB 35H,78H,0A5H ;定义数据
SUM DB? ;定义存放累加和的单元
.CODE ;代码段定义
MOV AX,@DATA ;数据段段名为 @DATA
MOV DS,AX ;设置 DS值第 4章 伪指令及汇编语言源程序结构
MOV AL,0 ;累加器清 0
MOV SI,OFFSET BUF ; BUF首地址送 SI
ADD AL,[SI] ;累加第 1个数
INC SI ;地址指针增 1
ADD AL,[SI] ;累加第 2个数
INC SI ;地址指针增 1
ADD AL,[SI] ;累加第 3个数
MOV SUM,AL ;存储累加和
MOV AH,4CH
INT 21H ;返回 DOS
END ;源程序结束第 4章 伪指令及汇编语言源程序结构对于简化段定义需要说明的是:
① 凡是与高级语言程序连接的数据,必须把常数与变量分开,变量中又要把赋初值的与不赋初值的分开,并分别定义在,CONST,.DATA/FARDATA和,DATA? /.FARDATA?中。远程数据段只能在压缩模式、大模式和巨型模式中使用,其他数据段和代码段可在任何模式下使用。
② 不与高级语言连接的源程序独立的汇编语言源程序只用前述的 DOSSEG,.MODEL,.CODE,.STACK和,DATA 5种简化语句,
并且不区分常数与变量以及赋初值与不赋初值。在,DATA语句定义的段中,所有数据语句均可使用。其一般格式如下:
第 4章 伪指令及汇编语言源程序结构
DOSSEG
.MODEL
.STACK [长度 ]
.DATA
数据语句
.CODE
启动标号:
MOV AX,DGROUP ;或 MOV AX,@DATA
MOV DS,AX
执行性语句
END启动标号
…
…
…
…
第 4章 伪指令及汇编语言源程序结构这种简化段的源程序结构中只有一个堆栈段、一个数据段和一个代码段。代码段长度可达 64 KB,数据段与堆栈段为一个组,其总长度可达 64 KB,组名为 DGROUP。组名 DGROUP与数据段名 @DATA都代表组对应物理段的段界地址。装入内存时,系统给
CS和 IP赋初值,使其指向代码段,同时系统还给 SS和 SP赋初值,
使 (SS)= DGROUP,(SP)=数据段长度+堆栈段长度,从而使堆栈段为对应的物理段。这样处理是使堆栈元素也能用 DS寄存器访问,以便同高级语言程序连接。在代码段开始运行处 (启动标号处 ),用户应设置 DS指向组的段界地址。
第 4章 伪指令及汇编语言源程序结构
3.指定地址伪指令 (ORG)
格式,ORG偏移地址
ORG $+偏移地址功能:以其指定的偏移地址或由 $给出的当前地址加上指定的偏移地址作为当前开始分配和使用的偏移地址。
说明:该伪指令语句不占内存,它指定下一个占内存语句的偏移地址。偏移地址可写成表达式形式,但其取值范围在
0~ 65 535之间,通常不必使用该语句,只在需要指定存储空间或保留一段存储空间时才使用它。该语句不能使用标号,否则语句无效。
第 4章 伪指令及汇编语言源程序结构
4.模块定义伪指令一个可执行的汇编源程序可由多个模块组成,每个模块是一个独立的汇编单位。在操作系统中,汇编源程序是一个 *.ASM
源文件。汇编源程序的模块与汇编源文件是一一对应的。
1) 模块开始语句 (NAME)
格式,NAME[模块名 ]
功能:表示源程序开始并指出模块名。
说明:该语句一般可省略。省略时,模块名取源程序中
TITLE语句之页标题的前 6个字符。若没有 TITLE语句,则取该模块的源程序文件名为模块名。
第 4章 伪指令及汇编语言源程序结构
2) 模块结束语句 (END)
格式,END[标号 /过程名 ]
功能:模块结束语句表示源程序到此结束,并可指出程序的启动地址。
说明:一个源程序必须有且只能有一个 END语句来指出源程序文件的结束。方括号中的标号或过程名是可选项,只有主模块才具有该项,其作用是指出该程序的第一条可执行指令的位置,系统将给 CS,IP赋初值。
第 4章 伪指令及汇编语言源程序结构
5.模块连接伪指令
1) 全局符说明语句 (PUBLIC)
格式,PUBLIC 符号名 1[,符号名 2,… ]
功能:将本文件中定义的符号名说明为全局符号,允许程序中其他模块使用。
说明:该语句中的符号名可以是标号、变量名、过程名或由
EQU(或= )伪指令定义的名字。这些符号名必须是在当前源程序中定义的,其他模块不能再用它们去定义别的内容。未被说明的符号名不能被其他模块引用。
需要注意的是,PUBLIC伪指令与 SEGMENT伪指令中的 PUBLIC
组合类型是两个不同的概念。
第 4章 伪指令及汇编语言源程序结构
2) 外部符说明语句 (EXTRN)
格式,EXTRN 符号名 1:类型 [,符号名 2:类型,… ]
功能:该语句中指定的符号名是在其他模块中用 PUBLIC伪指令语句定义过的。类型可以是 NEAR,FAR,BYTE,WORD,DWORD、
FWORD,QWORD,TBYTE或 ABS(由 EQU伪指令定义的常数符 ),具体类型必须与其他模块中定义的相同符号名的类型相一致。
说明:当前模块要引用其他模块中定义的符号名时,必须用
EXTRN伪指令说明,如果当前模块中没有用 EXTRN伪指令说明,或者在被引用模块中没有用 PUBLIC伪指令说明,均不能引用,否则
LINK程序将会产生一个错误信息。可见,EXTRN伪指令和 PUBLIC伪指令是互相对应的。
第 4章 伪指令及汇编语言源程序结构
3) 包含语句 (INCLUDE)
格式,INCLUDE 文件名功能:将指定文件的内容完整地插入到本语句出现的位置。
说明:使用本伪指令语句可避免重复书写多个模块都要使用的相同程序块。当汇编某一源程序文件时,若遇到 INCLUDE伪指令,就按文件说明打开磁盘上存在的相应文件,并将它插入到当前文件的该 INCLUDE伪指令处,然后汇编插入进来的文件中的语句。当该文件中的所有语句处理完后,MASM继续处理当前文件中 INCLUDE语句后面的语句。
汇编语言程序设计时,常用 INCLUDE伪指令语句将一个标准的宏定义插入到程序中。
第 4章 伪指令及汇编语言源程序结构
4) 公用符号说明语句 (COMM)
格式,COMM [NEAR/FAR] 符号名:尺寸 [:元素数 ],…
功能:将语句中的符号名说明为公用符号。公用符号既是全局的又是外部非初始化的。
NEAR/FAR语句中的符号名可以是近程 (NEAR)或远程 (FAR)数据段的符号,NEAR/FAR缺省时,在完整段和简化段的中、小模式下为 NEAR,其他模式下为 FAR。尺寸可以是 BYTE,WORD、
DWORD,DWORD,QWORD及 TBYTE。元素数为符号的个数,缺省值为 1。一条语句中可说明多个公用符号,多个符号间用逗号隔开。
该伪指令语句经常用在 INCLUDE文件中。如果一个变量用于多个模块中,可以在 INCLUDE文件中将它说明为公用变量,然后在每一个模块中都用 INCLUDE指令嵌入这个 INCLUDE文件。
第 4章 伪指令及汇编语言源程序结构例 4-24
.DATA
COMM NEAR NBUFFER,BYTE,20 ;在近程数据段中定义一个 20字节的公用缓存区
.FARDATA
COMM FAR FBUFFER,DWORD,12 ;远程数据段中定义一个 12双字的公用缓存区第 4章 伪指令及汇编语言源程序结构
4.3.3 过程定义伪指令语句汇编语言中常用定义过程来实现按模块管理程序代码的功能,因此过程是进行模块化程序设计的基础。过程是程序的一部分,它们可被程序调用。每次可调用一个过程,当过程中的指令执行完后,控制返回调用它的地方。 80x86中调用过程指令是 CALL,从过程返回的指令是 RET。这两条指令分为:段内的和段间的指令两种情况。段间的指令把过程应返回的地址的段地址和偏移量两者同时入栈 (CALL)和退栈 (RET)。段内的调用与返回指令只入栈和退栈地址偏移量。过程相当于高级语言程序中的子程序,常用于代替完成特定任务的代码模块。
第 4章 伪指令及汇编语言源程序结构过程定义包含两条伪指令,PROC和 ENDP。 PROC表示过程的开始,ENDP表示过程的结束。过程定义语句的格式为过程名 PROC [属性 ] ;过程开始;过程体
[RET]
RET
过程名 ENDP ;过程结束功能:定义一个过程 (子程序 )。
…
…
第 4章 伪指令及汇编语言源程序结构伪指令 PROC与 ENOP必须成对出现,ENDP指示过程结束,但它不会产生 HLT或 RET指令。利用过程定义语句可以把程序分段,
便于理解、调试和修改。若整个程序由主程序和若干子程序组成,则主程序和这些子程序都应包含在代码段中,而主程序及子程序都可以作为一个过程,用过程定义语句定义。
过程定义语句 PROC和 ENDP限定一个过程,并说明它是 NEAR
或 FAR过程。汇编程序根据过程定义语句,当汇编到 CALL过程时,
知道汇编的是什么样的过程调用,当汇编到从这个过程返回时,
知道是什么样的返回。
第 4章 伪指令及汇编语言源程序结构例 4-25
MY_CODE SEGMENT
UP_COUNT PROC NEAR
ADD CX,1
RET
UP_COUNT ENDP
START:
CALL UP_COUNT
HLT
MY_CODE ENDS
END START
…
…
第 4章 伪指令及汇编语言源程序结构因为 UP_COUNT标明是 NEAR过程,所以对它的调用,都汇编成段内调用,所有在它之中的 RET指令,都汇编为段内返回。
说明:
① 过程名是过程的标识符 (也可视为标号,当标号处理 )。
② 过程的属性可以是 FAR或 NEAR类型。 NEAR为近,即可在段内调用。 FAR类型为远,可跨段调用,缺省时为 NEAR。如果使用简化段指令,则不需要用 FAR指定类型,这时过程的类型是由,MODEL伪指令决定的。
第 4章 伪指令及汇编语言源程序结构
③ RET为返回指令,是过程的出口点,但不一定是过程的最后一条指令。一个过程可以有多个 RET指令,但至少要执行到一个 RET指令。
④ 过程可以嵌套,嵌套的深度 (层数 )只受堆栈的限制,
过程和段也可以嵌套,但不能交叉覆盖。
第 4章 伪指令及汇编语言源程序结构例 4-26 下面程序段定义了两个子程序 P1和 P2,其中 P1又调用了 P2。
P1 PROC ;定义过程 P1
CALL P2 ;过程嵌套
RET
P1 ENDP
P2 PROC ;定义过程 P2
RET
P2 ENDP
…
…
第 4章 伪指令及汇编语言源程序结构
4.3.4 列表伪指令语句汇编程序在对源程序进行汇编时,除可产生目标代码程序
(.OBJ)外,还可产生一个列表文件 (.LST)和一个交叉参考列表文件 (.CRE),它们都是能被显示或打印的文件,其中列表文件以源程序指令与其相应目标程序指令相对照形式给出汇编结果并随后给出程序中所用符号 (标号、变量名等 )的符号表;交叉参考列表文件按字母顺序列出源程序中所用的符号清单及其使用情况,并给出它们在程序中使用的行号。这两种文件便于程序调试。列表伪指令就是用来控制上述两种文件的输出格式和方式的。
第 4章 伪指令及汇编语言源程序结构
1.显示汇编信息语句格式,% OUT 信息功能:汇编时,将该伪指令语句给出的信息在屏幕上显示。
说明:,信息,可以是任意的 ASCII码字符串。若要显示多行信息,每行开头都要使用本语句。
第 4章 伪指令及汇编语言源程序结构
2.控制列表文件显示的页格式
1) TITLE
格式,TITLE 标题功能:指定列表文件每页的标题。
说明:,标题,可以是长度在 80个字符内的字符串。若无本语句,则标题为空。
第 4章 伪指令及汇编语言源程序结构
2) SUBTYL
格式,SUBTYL 子标题功能:指定列表文件每页的子标题。
说明:,子标题,可以是长度在 60个字符内的字符串。若无本语句或虽有但未给出子标题,则子标题为空。
第 4章 伪指令及汇编语言源程序结构
3) PAGE
格式,PAGE ([行数 ],[列数 ])
功能:控制列表文件的分页及每页的行列数。
说明:行数范围在 10~ 255之间,默认值为 58行;列数范围在
60~ 132之间,默认值为 80列。若没选行、列数这两个参数,
则使打印机换页,走纸到下页的顶端,页号加 1,并打印新页的标题、子标题及文件的其余部分。
第 4章 伪指令及汇编语言源程序结构
4) PAGE
格式,PAGE+
功能:控制换页并开始新的一节,且使节号加 1,页号重置为 1。
说明:节数是对整个文件而言,而页号则是在节中的页数。
第 4章 伪指令及汇编语言源程序结构
3.控制列表文件输出内容
1) LIST
格式,.LIST
功能:控制列表的开始。
2) XLIST
格式,.XLIST
功能:控制列表的结束。
说明,LIST和 XLIST一般成对出现,用来选择或禁止源程序中某些行的输出。
第 4章 伪指令及汇编语言源程序结构
3) LFCOND
格式,.LFCOND
功能:允许其后条件 1为假的条件块被列表。
4) SFCOND
格式,.SFCOND
功能:禁止其后条件为假的条件块被列表。
说明,LFCOND和 SFCOND一般成对出现,用于限制程序中条件块的列表输出。
第 4章 伪指令及汇编语言源程序结构
5) TFCOND
格式,.TFCOND
功能:改变对条件为假的条件块的现行列表状态,即原来列表改为不列表,原来不列表改为列表。
说明:其控制条件块列表的状态正好与 LFCOND和 SFCOND相反。
6) LALL
格式,.LALL
功能:将宏展开中的所有内容列表输出。
第 4章 伪指令及汇编语言源程序结构
7) SALL
格式,.SALL
功能:对所有的宏展开内容均不列表输出。
8) XALL
格式,.XALL
功能:只将宏展开中产生数据或目标代码的语句列表输出。
说明,LALL,SALL和 XALL用于控制宏展开的内容是否包含在列表文件中。
第 4章 伪指令及汇编语言源程序结构
4.控制交叉参考列表文件的输出
1) CREF
格式,.CREF
2) XCREF
格式,.XCREF
功能:这两条语句的功能是:控制交叉参考信息 (以字母顺序排列的符号、变量、标号的清单及其使用情况 )是否列在交叉参考列表文件 (.CRF)中。
说明,CREF恢复在,CRF文件中产生交叉参考信息。汇编程序默认的状态是,CREF; XCREF禁止在,CRF文件中产生交叉参考信息。
第 4章 伪指令及汇编语言源程序结构
4.4 标号、变量和表达式
4.4.1 标号标号在程序中是一个代表逻辑地址的名字。定义一个标号后,也相应定义了标号的四个属性:段属性,USE属性、标段偏移地址和标号类型。标号有两种类型,NEAR和 FAR。汇编语言预定义的标号有位置计数器,用 $代表。位置计数器的值是正在汇编的位置在当前段内的偏移量。 $一般作为指令或表达式的操作数。有两条伪指令控制位置计数器,ORG和 EVEN。
第 4章 伪指令及汇编语言源程序结构
1,ORG伪指令
ORG伪指令用来置位置计数器的值。因此,也包括代码的起始地址。一个 ORG表达式把代码或数据定位于当前段指定的偏移地址处。 ORG伪指令的格式如下:
ORG EXP
其中,EXP是一个常量表达式或一个标号。在 USE32段中,EXP
的值以 232-1为模,在 USE16段中,EXP的值是以 65 536为模。
第 4章 伪指令及汇编语言源程序结构例 4-27
ORG 100H ;把位置计数器定位于 100H处
ORG OFFSET($+1000)
ORG OFFSET($-1000)
第 4章 伪指令及汇编语言源程序结构
2,EVEN伪指令
EVEN伪指令保证代码或数据序列是以 DWORD或 WORD对界。
其格式如下:
EVEN
当程序汇编时遇到 EVEN伪指令,汇编系统就在代码或数据序列中加多达三个 NOP指令 (90H)。若是 USE32段则按最近的 DWORD对界,若是 USE16段则按 WORD对界。
第 4章 伪指令及汇编语言源程序结构
3,LABEL伪指令
LABEL伪指令在当前汇编的位置上建立一个名字,不管这个位置是数据还是代码。其格式如下:
NAME LABEL TYPE
其中,NAME是一个标识符; TYPE是 NEAR或 FAR,或一个变量类型
(BIT,BYFE,WORD,DWORD,PWORD,QWORD或 TBYTE)、一个标号名、一个记录名或一个结构名。标号、记录名、结构名不能超前引用,在此之前应定义过。利用 LABEL可以把一个 FAR标号定义成一个 NEAR标号别名。然而相反类型的别名标号只能作为 JMP或条件转移指令的操作数。如果子程序需要返回,用 CALL指令调用同一个子程序时,只能是同一类型的标号,不能又用 FAR标号,又用其别名后的 NEAR标号。子程序中的 RET指令要么是 NEAR,要么是 FAR,不能二者兼具。
第 4章 伪指令及汇编语言源程序结构例 4-28 LOWBYTE和 HIGHBYTE是两个相邻的 BYTE类型变量,
可以利用 LABEL伪指令把它们定义为一个 WORD类型的变量 AWORD。
这样,我们就可以用变量 AWORD来访问这两个相邻的单元了。
AWORD LABEL WORD
LOWBYTE DB 0
HIGHBYTE DB 0
第 4章 伪指令及汇编语言源程序结构例 4-29 在同一数据区域建立了三种访问方式。
BIT_ARRAY,TBYTE_AR_RAY和 WORD_ARRAY,都对应同一数据区
BYTE_ARRAY。
BYTE_RECORD RECORD B7,1,B6,1,B5,1,B4,1,
B3,1,B2,1,B1,1,B0,1
BIT_ARRAY LABEL BYTE_RECORD
TBYTE_ARRAY LABEL TBYTE
WORD_ARRAY LABEL WORD
BYTE_ARRAY DB 100 DUP(0)
第 4章 伪指令及汇编语言源程序结构
4.4.2 标号和变量
1.标号和变量程序中标号和变量都定义了一个逻辑地址。标号定义一个当前段的段内偏移地址,或者定义一个不在当前段的其他段的段选择符及其段内偏移地址。变量也定义一个地址,该地址存储单元的内容 (数据的值 )可以通过变量名来引用。
标号和变量都有自己的类型,每个汇编语言标号都具有以下两种类型之一:
(1) NEAR:指出标号代表的逻辑地址是一个偏移地址,
NEAR是汇编语言的缺省标号类型;
(2) FAR:指出标号代表的逻辑地址是一个段选择符和一个偏移量。
第 4章 伪指令及汇编语言源程序结构每个汇编语言变量的类型必须在定义该变量时给出,以分配一定的存储空间。变量的类型可以是简单类型,或是复合类型。复合类型由一种或多种简单类型构成。
变量的简单类型有以下几种,在汇编语言中的保留字分别为:
(1) bit 虽然定义为位,但分配 1个字节的存储空间;
(2) BYTE 为变量分配 8位存储空间;
(3) WORD 为变量分配 16位存储空间;
第 4章 伪指令及汇编语言源程序结构
(4) DWORD 为变量分配 32位存储空间;
(5) PWORD 为变量分配 48位存储空间;
(6) QWORD 为变量分配 64位存储空间;
(7) TBYTE 为变量分配 80位存储空间。
复合类型的变量是一个记录或结构。记录和结构是程序员定义的类型。可以利用记录和结构存储分配语句来定义这些类型的变量。
第 4章 伪指令及汇编语言源程序结构
2.符号数据的使用汇编程序中的标号和变量名是符号数据,所有程序定义的标识符都是符号数据,关键字和保留字也可作为符号。
用 EQU伪指令为符号另起一个新名字。用 PURGE伪指令告知汇编系统,忽略目标文件信息中的用 EQU定义的符号和程序员定义的符号。
第 4章 伪指令及汇编语言源程序结构
1) EQU伪指令格式,NAME EQU VALUE
其中,NAME是一个汇编语言标识符 VALUE赋给 NAME的值。
功能:为一个标识符赋一个值,也可为一个符号值建一个别名,或为一个汇编时的常量或运行时的表达式值建立一个标识符。
说明:给标识符赋的值可以是下列之一:变量名、标号名、
变量或寄存器表达式、一个寄存器、一个浮点栈元素、一个助记符或指令前缀、一个宏调用或前缀、操作符 NOT,AND,OR、
XOR,SHL或 SHR。 VALUE可以是任何地址表达式。
第 4章 伪指令及汇编语言源程序结构例 4-30 标号 ALAB代表的值可被 EQU超前引用。
ALABEL EQU ALAB
ALAB,MOV EAX,0
第 4章 伪指令及汇编语言源程序结构例 4-31 用 EQU为 80386寄存器定义一个别名。
COUNT EQU ECX
PNTR EQU EBX
MOV COUNT,10 ; ECX= 10
MOV PNTR,OFFSET ARRAY ; EBX= ARRAY的偏移地址第 4章 伪指令及汇编语言源程序结构例 4-32 为指令 MOV和 INC定义一个别名。
DATAMOVE EQU MOV
INCREMENT EQU INC
DATAMOVE EAX,EBX ;此语句即 MOV EAX,EBX
INCREMENT EAX ;此语句即 INCEAX
第 4章 伪指令及汇编语言源程序结构例 4-33 用 EQU赋常量。
TDTAL EQU 6
PI EQU 3.141592653589793
DD PI ;单精度
DQ PI ;双精度
DEG_TO_RAD EQU 3FF98EFA351294E9C8AEF ; PI/180
DT DEG_TO_RAD ;扩展精度第 4章 伪指令及汇编语言源程序结构例 4-34 此例说明汇编时的初始化赋值。
E1 EQU 2+3
E2 EQU E1 AND 4
E2 EQU (E1-E2)/12
第 4章 伪指令及汇编语言源程序结构例 4-35 用 EQU定义在堆栈中存取的变量。
STKWRD EQU WORDPTR[EBP+2]
ONEVAR EQU SS∶[EBX+3]
TWOVAR EQU SS∶[EBX]
第 4章 伪指令及汇编语言源程序结构
2) PURGE伪指令格式,PURGE NAME,[,… ]
其中,NAME是一个符号数据标识符。
功能:删除已定义的一个或多个符号。使用 EQU定义的标号、变量和关键字或寄存器别名都可用 PURGE删除。
说明,PURGE不能删除的符号有下面几种:说明为 PUBLIC
的名字、寄存器名、保留字。
第 4章 伪指令及汇编语言源程序结构例 4-36 删除用 EQU定义的指令和寄存器别名
DATAMOVE EQU MOV
COUNT EQU ECX
PURGE DATAMOVE,COUNT
…
第 4章 伪指令及汇编语言源程序结构例 4-37 在程序 END语句前的 PURGE语句,使汇编系统从目标文件中省略掉被 PURGE删掉的符号。
PURGE ALABEL,VAR1
END ;模块结束第 4章 伪指令及汇编语言源程序结构
4.4.3 汇编语言表达式表达式包括操作数和操作符,它可以是一个初始化数据的值或是一个存储器地址。一条汇编语言的指令对数据操作时,
该数据必须是作为该指令的一个操作数。一些指令有隐含的操作数,如寄存器。但是,大多数指令有明显的操作数。一条指令的操作数可以用下述形式表示:一个寄存器、一个常量、一个存储器地址或这些的组合。一些操作数可以用表达式来表示,
这包括一系列的变量名、基址和变址寄存器及用操作符连在一起的常量,例如,一个寄存器内容和一个常量可用操作符加在一起。
第 4章 伪指令及汇编语言源程序结构
1.常量表达式大多数的操作符都可用于常量,使常量成为一个表达式中的操作数。在存储分配伪指令中,可使用常量表达式初始化变量值。在汇编时,由其他模块定义的符号常量的值是不知道的。
例 4-38
EXTRN ANUMBER,ABS
DATA SEGMENT
AWORD DW ANUMBER ;当模块连接时 AWORD得到 ANUMBER的值
DATA ENDS
第 4章 伪指令及汇编语言源程序结构
2.地址表达式一个地址表达式定义一个存储器的存储单元位置,这个位置可用变量或标号表示。每一个地址表达式都是一个简单类型。
1) 变量名和标号名作为地址表达式最简单的地址表达式就是一个变量的名字或一个标号的名字。在这种情况下,该名字意味着寻址使用的是变量或标号在所定义的段中相对段基地址的偏移地址。这个地址是可重定位的。
第 4章 伪指令及汇编语言源程序结构例 4-39
ADD DX,COUNT ; COUNT是一个简单的地址表达式或是一个变量
ADD DX,COUNT+2 ;在这种情况下,地址表达式具有与 COUNT同样的段和类型;只是偏移值大于 2
第 4章 伪指令及汇编语言源程序结构
2) 寄存器表达式格式:
[BASE_REG] 或 [INDEX_REG * SCALE]
[BASE_REG+INDEX_REG * SCALE]
[BASE_REG+DISP] 或 [INDEX_REG * SCALE+DISP]
[BASE_REG+INDEX_REG * SCALE+DISP]
第 4章 伪指令及汇编语言源程序结构其中,BASE_REG是任何用于 32位寻址的 32位通用寄存器,以及
16位寻址的 BX或 BP; INDEX_REG是除 ESP外的任何 32位寻址的 32
位通用寄存器,以及用于 16位寻址的 SI或 DI; SCALE是一个可选的常量或常量表达式,其值是 1,2,4或 8,只用于 32位寻址,
不能用于 16位寻址; DISP在 32位寻址时是一个 8位或 32位的偏移,
16位寻址时是 8位或 16位的偏移。
一个寄存器表达式是一个使用基址和变址寄存器或基址或变址寄存器的地址表达式。
第 4章 伪指令及汇编语言源程序结构例 4-40
MOV CX,[BX] ;把 BX所指的 WORD类型数据送到 CX
例 4-41
MOV WORD PTR[DI],5 ;把 5赋于 2个字节
INC BYTE PTR[BX]+2 ; 1个字节单元增 1
第 4章 伪指令及汇编语言源程序结构
3) 简单地址表达式和寄存器表达式的组合格式,VARNAME[REG_EXP]
其中,VARNAME是一个变量名,REG_EXP是一个寄存器表达式,写在一对方括号内。实际形成的地址为变量的偏移地址与寄存器内容之和。
寄存器表达式与简单地址表达式组合,可组成为一个较复杂的地址。
第 4章 伪指令及汇编语言源程序结构例 4-42
COUNT[EBX] ;简单基址,COUNT的偏移地址加 EBX内容
COUNT[EBX]+2 ;比上一语句多一个偏移量 2
COUNT[EBX]+[ESI] ;基址加变址第 4章 伪指令及汇编语言源程序结构
4) 地址表达式中的结构域地址表达式的另一个形式是,利用结构域名作为偏移量再加上结构的段内偏移。对一个结构类型变量来说,二个域名代表了其在结构内的偏移量。一个域名可以和一个相同类型的变量名或一个寄存器表达式组合成一个地址表达式。
第 4章 伪指令及汇编语言源程序结构例 4-43
ASTRUC STRUC
ABYTE DB 0
AWORD DW 0
BYTE2 DB 0
ASTRUC ENDS
ANARRAY DB 1,2,3,4 ; ANARRAY.AWORD的类型为 WORD
MOV AL,ANARRAY.BYTE2 ; AL= 4
MOV CX,ANARRAY.AWORD ; CX= 0302H
MOV BX,OFFSET ANARRAY ;偏移地址送 BX
MOV AL,[BX].ABYTE ; AL= 1,[BX].ABYTE类型为 BYTE
…
…
第 4章 伪指令及汇编语言源程序结构
5) 可重定位表达式如果地址表达式中有变量名、标号名、段名,则在所有程序模块汇编、连接、定位之前,它们的结果是不知道的。这样的表达式称为可重定位的。系统软件将为这些地址表达式赋值。
第 4章 伪指令及汇编语言源程序结构例 4-44 段名代表了段描述符的逻辑地址,一个段名形成一个基址可重定位地址。
DATA1 SEGMENT
DATA1 ENDS
DATA2 SEGMENT
SEGBASE DW DATA1 ; SEGBASE装有 DATA1段的基址可重定位地址
DATA2 ENDS
…
…
第 4章 伪指令及汇编语言源程序结构例 4-45 变量名或标号名可形成一个偏移或指针可重定位地址。
DATA SEGMENT USE32
ABYTE DB 0
AN_OFFSET DDABYTE+2 ; AN_OFFSET装有 ABYTE+2的偏移可重定位地址
A_POINTER DPABYTE ; A_POINTER装有 ABYTE的指针可重定位地址
DATA ENDS
第 4章 伪指令及汇编语言源程序结构
4.4.4 指令操作数
1.寄存器操作数大多数的寄存器都可作为显式操作数。段寄存器只能用于指令 MOV,PUSH和 POP。
例 4-46
MOV AX,FS ; FS寄存器的内容送 AX
ADD ESI,EBX ; ESI= ESI+EBX
MOV AX,BX ; BX寄存器的内容送 AX
第 4章 伪指令及汇编语言源程序结构
2.立即操作数立即操作数是一个整数或序数常量值。立即操作数只能作为源操作数,而不能作为目的操作数。
例 4-47
MOV AX,5 ; AL= 5
CMP AX,0FFFFH ; AX寄存器的内容与 0FFFFH比较
CMP BL,15 0R 5 ;立即操作数是一个常量表达式
MOV EDX,0FFSET VAR+1000 ;立即操作数是一个产生整数的表达式
MOV AX,DATASEG ;立即操作数是段名 DATASEG
MOV DS,AX ; DS初始化为 DATASEG段第 4章 伪指令及汇编语言源程序结构
3.存储器操作数
1) 直接存储器寻址直接对存储器寻址,指令操作数应该用变量或标号表示。
例 4-48
MOV EAX,COUNT ;把存储器中 COUNT处的双字送到 EAX中第 4章 伪指令及汇编语言源程序结构
2) 间接存储器寻址例 4-49 寄存器间接存储器寻址。
MOV BX,OFFSET AVAR ; BX=变量 AVAR的偏移
MOV AX,[BX] ; AX= AVAR的值例 4-50 基址寻址。
MOV EBX,OFFSET DATASTRUC ; EBX= DATASTRUC的基址
MOV EBX,[EBX+4] ; EBX=距 DATASTRUC第 4个字节的双字第 4章 伪指令及汇编语言源程序结构例 4-51 基址变址寻址。
XOR EAX,EAX ; EAX= 0
MOV EBX,OFFSET ARRAYSTR ; EBX=数组 ARRAYSTR的基地址
MOV ECX,LENGTH ARRAYSTR
MOV ESI,0 ;变址寄存器 ESI指向 0
ALAB,ADD EAX,[EBX+ESI] ;利用基址加变址得到数组元素
ADD ESI,4 ;增加变址
LOOP ALAB ;继续第 4章 伪指令及汇编语言源程序结构例 4-52 变址寻址。
MOV SI,0
MOV DI,0
MOV CX,LENGTHSOURCE ; CX= SOURCE数据单元的个数
ALAB,MOV AX,SOURCE[SI] ;变址地址
MOV DEST[DI],AX ;变址地址
ADD SI,2 ;指向 SOURCE的下一个字
ADD DI,2 ;指向 DEST的下一个字
LOOP ALAB ;循环到 ALAB
第 4章 伪指令及汇编语言源程序结构
4.5 段 的 组 织
4.5.1 代码段和数据段的定义
1,SEGMENT..ENDS伪指令可用一对伪指令 SEGMENT..ENDS定义逻辑段。之所以称为逻辑段是因为它们表示的是逻辑地址,在程序运行前,必须先映射到 80x86的物理地址上。汇编程序把命名后的段变成一块连续的物理地址,当程序运行时,把该段名字装入到一个 80X86段寄存器,逻辑段就能实际地访问了。
第 4章 伪指令及汇编语言源程序结构格式
NAME SEGMENT[ACCESS][USE][COMBINE]
[指令,伪指令,数据的初始化定义 ]
NAME ENDS
功能:定义一个汇编语言程序的代码或数据段。
…
…
第 4章 伪指令及汇编语言源程序结构说明:
(1) NAME是程序员为该段命名的标识符,即段名。在一个模块中,NAME必须是惟一的,NAME表示了该逻辑段的起始逻辑地址。在 SEGMENT..ENDS之间的段的内容表示了从段名 NAME开始的逻辑偏移地址。
(2) ACCESS是汇编语言及保护模式的描述,对程序中某段的存取限制方式有:只读、只可执行、可执行、可读及可读可写,其保留字分别为,RO,EO,ER和 RW。当省略 ACCESS时,汇编程序产生一个警告信息,汇编程序根据段的内容赋一个
ACCESS值,规则是:如果一个段中只有数据,其值为 RW;只有代码,其值为 EO;代码和数据都有,其值为 ER。
第 4章 伪指令及汇编语言源程序结构
(3) USE定义段的 USE属性。 USE属性决定一个段中代码的寻址方式、最大段的大小和操作数尺寸。 USE有两个值,即
USE16和 USE32。
① USE16 为该段内的标识符 (变量、标号、结构、记录和过程名 )产生一个 16位的地址偏移,用 USE16定义的段可长达
64KB;
第 4章 伪指令及汇编语言源程序结构
② USE32 为该段内的标识符 (变量、标号、结构、记录和过程名 )产生一个 32位的地址偏移,用 USE32定义的段可长达 4GB。
如果 SEGMENT语句省略 USE的值,段的 USE属性取决于离它最近的段或模块的属性。一般情况下,程序模块的缺省值是 USE32。
段的 USE属性也决定了某些 80X86指令的操作数尺寸。例如,如果一个段为 USE32,则 ENTER指令需要的立即操作数是 32位;如果一个段为 USE16,则操作数会用 0扩展到 32位。
第 4章 伪指令及汇编语言源程序结构
(4) COMBINE描述不同模块中的同名段怎样合并,以便在存储器中形成一个单一的物理段。实际上合并是发生在连接的时候。 COMBINE的值有两个,即 PUBLIC和 COMMON。
① PUBLIC所有定义为 PUBLIC的名字相同的段,将连接起来形成一个物理段;
② COMMON所有定义为 COMMON的名字相同的段,将重叠起来形成一个物理段。每个模块中的段名都有相同的物理地址,
在合并后的段内,偏移均为 0。
第 4章 伪指令及汇编语言源程序结构如果 COMBINE属性没有赋值,则段是不能合并的,即各个模块中同名的段并不形成一个单一的物理段。合并后的 PUBLIC
段的长度近似等于各 SEGMENT..ENDS段长度之和。对于定义为
PUBLIC的段,合并后的段并不保证连接的前后顺序,即不能确定某个段的哪部分在合并后的段中有 0偏移。合并后的 COMMON
段的长度等于各模块中所定义的段中那个最长的段的长度。一个 COMMON段的 ACCESS属性不能为 EO或 ER。
第 4章 伪指令及汇编语言源程序结构例 4-53
PROG_CODE SEGMENT RO PUBLIC USE32
PROG_CODE ENDS
此例定义了一个名叫 PROG_CODE的段。它的 ACCESS属性是
RO(只读 ); COMBINE属性是 PUBUC(公共 ); USE属性是 USE32(段内偏移为 32位 )。
…
第 4章 伪指令及汇编语言源程序结构
2.一个段的多次定义段在一个源程序模块中可任意打开和关闭多次。所有单独定义的段都被汇编程序连接起来,就好像它们被定义在单一的一个 SEGMENT..ENDS内。
过程、代码宏和结构的定义在段的边界上不能重叠。
当一个段重新打开时,并不需要重新定义 ACCESS,USE和
COMBINE属性。当段的 ACCESS属性重新指定时,两者的 ACCESS
属性应是兼容的,即 RW兼容 RO和 RW,ER兼容 RO,EO和 ER。如果重新指定的 ACCESS属性不兼容,将会出错。
第 4章 伪指令及汇编语言源程序结构例 4-54 说明下述程序段实现的功能。
DATA SEGMENT
ABYTE DB 0
AWORD DW 0
DATA ENDS ;关闭 DATA段;这里可定义任意其他非 DATA段
DATA SEGMENT ;重新打开 DATA段
ANOTHERBYTE DB 0
ANOTHERWORD DW 0
DATA ENDS
…
第 4章 伪指令及汇编语言源程序结构该程序段实现的功能是重新打开名为 DATA的段。该程序段中的语句等同于以下语句:
DATA SEGMENT
ABYTE DB 0
AWORD DW 0
ANOTHERBYTE DB 0
ANOTHERWORD DW 0
DATA ENDS
第 4章 伪指令及汇编语言源程序结构例 4-55 段属性具有承接性。
CODE SEGMENT ROPUBLIC USE32
CODE ENDS
CODE SEGMENT EO;承上面,隐含为 PUBLIC和 USE32
CODE ENDS
…
…
…
第 4章 伪指令及汇编语言源程序结构例 4-56 段属性的修改要符合兼容性规则。
F_SEG SEGMENT RW COMMON USE16
F_SEG ENDS
F_SEG SEGMENT ER PUBLIC USE32; 有 3个错误,RW和 ER不兼容,不能改变 COMBINE属性,不能改变 USE属性
F_SEG ENDS
…
…
…
第 4章 伪指令及汇编语言源程序结构
3.段的嵌套在实际的存储器中,不会嵌套汇编程序中的段。为了方便起见,汇编语言程序可嵌套定义段,但这只是语法上的嵌套,
并不表示实际上的嵌套。编程时注意要把要嵌套的段定义在其他段的 SEGMENT..ENDS之内。
第 4章 伪指令及汇编语言源程序结构例 4-57
PROG_CODE SEGMENT;开始处理 PROG_CODE段
PROG_DATA SEGMENT;开始处理 PROG_DATA段,停止汇编 PROG_CODE段
PROG_DATA ENDS;停止处理 PROG_DATA段重新开始处理 PROG_CODE段
PROG_CODEENDS ;结束 PROG_CODE段
…
…
…
此例中说明了一个合法的汇编语言段结构的嵌套。汇编程序认为 PROG_CODE代码段与 PROG_DATA数据段是分开的,
PROG_DATA段中的数据并不在 PROG_CODE段中,连接后,
这两个段在 80x86存储器中的物理地址可能相距很远。
第 4章 伪指令及汇编语言源程序结构例 4-58 本例中 SEGMENT...ENDS并没有成对地嵌套出现,
在汇编时会产生错误。
PROG_CODE SEGMENT;开始处理 PROC_CODE段
PROG_DATA SEGMENT;开始处理 PROG_DATA段,停止汇编 PROG_CODE段
PROG_CODE ENDS ;出错,在关闭 PROG_DATA段前不能关闭 PROG_CODE段
PROG_DATA ENDS
…
…
第 4章 伪指令及汇编语言源程序结构
4.5.2 堆栈段的定义
1,STACKSEG伪指令格式如下:
name STACKSEG exp
其中,name是所定义的逻辑栈段名,在程序中 name必须是惟一的; exp是为堆栈开辟的空间尺寸,可为表达式,单位是字节。
对于 USE32段,exp值为 0~ 4GB;对 USE16段来说,exp的值为
0~ 64 KB。
功能:定义一个逻辑堆栈段,并在储存器中为该堆栈段分配一定字节的存储空间。
第 4章 伪指令及汇编语言源程序结构说明:
① STACKSEG伪指令打开一个段,随即也关闭了该段,不能用 ENDS关闭段。
② 汇编语言堆栈段的 ACCESS属性总是 EW,COMBINE属性总是 PUBLIC。同名堆栈段的多次定义导致一个尺寸为所有堆栈段总和的一个段。
③ 堆栈段并不明显地给 USE属性赋值,它的 USE属性与离它最近关闭的段的 USE属性或模块的 USE属性相同。
④ 在堆栈段内不能定义代码、变量、标号或数据。可用
STACKSTART操作符初始化堆栈指针,即 SS∶ (E)SP中的内容。
第 4章 伪指令及汇编语言源程序结构
2.堆栈段和数据段的合并如果一个数据段和一个堆栈段具有一个相同的名字,并且它们的属性兼容,则它们合并为单一的数据 /堆栈段,数据段的属性必须为 PUBLIC和 RO或 RW。如果数据段不为 PUBLIC或它的
ACCESS属性是 EO或 ER时,则会产生错误。在这种情况下,汇编程序不会合并数据段和堆栈段,而在堆栈段的名字后附加上一 STACK,以区别每个段。
第 4章 伪指令及汇编语言源程序结构
4.5.3 段访问的指定
1,ASSUME伪指令格式:
ASSUME SREG∶ SEGPART[,…]
或 ASSUME SREG∶ NOTHING[,…]
或 ASSUME NOTHING
其中,SREG 是一个段寄存器,即 DS,ES,FS,GS或 SS。只有指定 NOTHING时,SREG才可以是 CS; SEGPART可以是保留字 NOTHING、段名或格式 SEG 变量名,SEG 过程名和 SEG外部名中的一个。
第 4章 伪指令及汇编语言源程序结构功能:告知汇编程序,CPU的哪个段寄存器指向程序中的一个逻辑段。值得注意的是,ASSUME并不对段寄存器实际装填,段寄存器需通过指令 (如 MOV等 )来进行装填。
说明:
① 当一条指令的操作数是变量或标号时,需要知道该变量或标号按哪个段访问。
② ASSUME 一般出现在代码段中可执行的汇编指令之前。
第 4章 伪指令及汇编语言源程序结构例 4-59 变量 ABYTE在 ESEG段中定义,现要在 CSEG段中使用,利用 ASSUME伪指令告知汇编程序 ES寄存器装有 ABYTE所在段的选择符。
ESEG SEGMENT RW USE32
ABYTE DB?
ESEG ENDS
CSEG SEGMENT ER USE32
ASSUME ES∶ ESEG
MOV AL,ABYTE ;汇编程序产生一个 ES段超越字节,;并对 ABYTE重新定位
MOV AL,ES,BYTE PTR 0 ;对 ES,BYTE PTR 0重新定位
…
…
…
第 4章 伪指令及汇编语言源程序结构例 4-60 若要通知汇编程序 DS寄存器装有 ABYTE所在段的选择符,可选用如下程序段。
ASSUME DS∶ SEG ABYTE
第 4章 伪指令及汇编语言源程序结构例 4-61 汇编程序处理 ASSUME语句和检查存储器访问的过程与方法如下述程序段描述。
DATA SEGMENT RW PUBLIC
ABYTE DB 0
AWORD DW 0
DATA ENDS
EDATA SEGMENT RW PUBLIC
WHERE DB 0
EDATA ENDS
CODE SEGMENT ER PUBLIC
CBYTE DB 0 ; CODE段的内容
…
第 4章 伪指令及汇编语言源程序结构
ASSUME DS,DATA ; DATA段通过 DS寻址
MOV AX,DATA ; AX= DATA段的选择符
MOV DS,AX ;初始化 DS
MOV AL,ABYTE ; ABYTE在 DS段中,通过 DS寻址,指令是正确的
MOV BL,CBYTE ; CBYTE在 CODE段中,就在当前段,指令是正确的,;汇编系统将生成一个 CS段超越,字节
MOV CL,WHERE ;这是一个程序错误,WHERE在 EDATA段中没有被任何; ASSUME指定,汇编程序将发出警告信息
…
第 4章 伪指令及汇编语言源程序结构
MOV AX,EDATA
MOV ES,AX ;现在 ES可寻址 WHERE,但汇编程序并不知道,;于是会发出警告
MOV CL,WHERE
ASSUME ES,EDATA
MOV CL,WHERE ;语句合法,因为 WHERE所在的段 EDATA被指定为 ES,;汇编程序将产生 ES段超越
CODE ENDS
…
第 4章 伪指令及汇编语言源程序结构
2,ASSUME NOTHlNG伪指令格式:
ASUUME NOTHING
功能,清掉以前的 ASSUME命令,等价于下列语句:
ASSUME CS∶ NOTHING,DS∶ NOTHING,
ES∶ NOTHING,FS∶ NOTHING,GS∶ NOTHING,
SS∶ NOTHING
说明:如果对段中定义的符号没有指定段寄存器,对符号的引用必须采用明显的 DS,ES,FS,GS或 SS段超越。汇编程序对代码段的访问总是通过 CS段寄存器进行。
第 4章 伪指令及汇编语言源程序结构例 4-62 说明 ASSUMEDS∶ DSEG和 ASSUMEDS∶ NOTHING
如何影响对 CSEG段中的 ABYTE符号的引用。
ASSUMEDS∶ DSEG
DSEG SEGMENTRW USE32
ABYTE DB?
DSEG ENDS
CSEG SEGMENT ER USE32
MOV AL,ABYTE ; ASSUME DS∶ DSEG仍影响着对 ABYTE的寻址,;汇编程序对有效的符号引用总是重新寻址
ASSUMEDS,NOTHING
MOV AL,ABYTE ;发生错误
MOV AL,DS∶ ABYTE ;采用段超越,因此无错
…
第 4章 伪指令及汇编语言源程序结构例 4-63 说明在一个数据段内,ASSUME ES∶ SEGMENT和 ASSUME
ES∶ NOTHING如何影响汇编程序对地址的生成。
ASSUME DS∶ DSEG,ES∶ ESEG;这里定义 ESEG段
DSES SEGMENT RW USE32
VAR1 PP ES∶ WORD PTR 0 ;汇编程序为 VAR1产生一个;可重定位的地址指针
ASSUME ES∶ NOTHING
VAR2 DP ES∶ WORD PTR 0 ;但并不为 VAR2产生
DSEG ENDS
…
…
…
第 4章 伪指令及汇编语言源程序结构
4.5.4 段寄存器的初始化
ASSUME伪指令仅仅指定逻辑段与段寄存器的匹配关系,
告知汇编程序某个逻辑段中的数据应通过哪个段寄存器寻址。
但是 ASSUME伪指令并没有将段选择符装入段寄存器。因此,
必须在程序中通过一定的指令 (如 MOV指令 ),把段选择符装入到段寄存器中。
第 4章 伪指令及汇编语言源程序结构
1,CS的初始化
CS寄存器的装填是自动进行的。主模块代码段的入口点必须指定一个标号,主模块的 END语句必须指示出这个入口点标号。当程序装载时,CS∶ (E)IP自动指向代码段入口点标号。
第 4章 伪指令及汇编语言源程序结构例 4-64 若要告诉汇编程序,程序从 START标号处开始,
CS∶ EIP装填标号 START的段选择符和偏移地址,可采用下述程序段。
CODE SEGMENT ER USE32
START:
CODE ENDS
END CS∶ START
当计算机复位、中断、程序转移时,CS∶ EIP的装填都是自动进行的,不用程序员干预。
…
第 4章 伪指令及汇编语言源程序结构
2,DS,ES,FS和 GS的初始化这 4个寄存器在源程序的代码段中,有 4种装填方法。
(1) 利用段名和 MOV指令。
例 4-65 在 ES中装入 DATA2段的选择符。
DATA1 SEGMENT RW
DATA1 ENDS
DATA2 SEGMENT RW
VAR32 DD 0
DATA2 ENDS
MOV BX,DATA2
ASSUME ES∶ DATA2
MOV ES,BX
…
…
第 4章 伪指令及汇编语言源程序结构
(2) 利用 SEG操作符和 MOV指令。
例 4-66 在 FS中装入 VAR32所在段的选择符,EXTRN伪指令指出 VAR32是在另一个源程序模块中定义的。
EXTRN VAR32 DWORD
MOV CX,SEG VAR32
ASSUME FS∶ SEG VAR32
MOV FS,CX
…
…
第 4章 伪指令及汇编语言源程序结构
(3) 利用一条 MOV指令,DS,ES,FS或 GS作为目的操作数,一个已初始化的存储器地址作为源操作数。
(4) 利用 LDS,LES,LFS或 LGS指令,这些指令的操作数是存储器指针。不要用段名作为源操作数。段名是立即数,不是存储器操作数。
第 4章 伪指令及汇编语言源程序结构
3,SS的初始化初始化 SS,(E)SP寄存器有 3种方法:
(1) 同数据段寄存器一样,可用若干条 MOV指令装填 SS。
(2) (E)SP的装填可用 MOV指令,(E)SP作为目的操作数,
带有 STACKSTART操作符的堆栈段名作为源操作数。
(3) 利用 LSS指令,不要用堆栈名作为 LSS的源操作数。
第 4章 伪指令及汇编语言源程序结构例 4-67 使用堆栈段名装填 SS和 ESP。
MOV AX,PROG_STACK ; PROG_STACK是定义的堆栈段名
MOV SS,AX
MOV ESP,STACKSTART PROG_STACK
段寄存器的初始化也可利用 END语句,而不必用指令装填。
第 4章 伪指令及汇编语言源程序结构例 4-68 可用 END语句初始化段寄存器 CS,DS,SS,即将段寄存器与对应的段名一起放在 END语句的后面。设 START为代码段的入口标号,DATA1为数据段名,PROG_STACK为堆栈段名,则用 END语句初始化段寄存器 CS,DS,SS描述如下:
END CS∶ START,DS∶ DATA1,SS∶ PROG_STACK
第 4章 伪指令及汇编语言源程序结构
4.6 程 序 段 前 缀
4.6.1 程序段前缀结构程序前缀 (PSP)是一个 256个字节的保留区,它位于分配给暂住程序内存块的底端,由 DOS创建。 PSP包含一些可被暂住程序使用的 DOS入口,一些 DOS为自己的目的所存储的信息,一些由 DOS传送给暂住程序的信息,这些信息视程序需要可能会使用也可能不会被使用。程序前缀的结构如图 4-3所示。
第 4章 伪指令及汇编语言源程序结构图 4-3 程序前缀的结构偏移地址
0000H INT 20H
0002H 段,分配块尾
0004H 保留区
0005H DOS功能调用
000AH 终止处理程序中断向量的以前的内容 (INT 22H)
000EH Ctrl-C中断向量以前的内容 (INT 23H)
0012H 出错处理中断向量以前的内容 (INT 22H)
0016H 保留区
002CH 环境块段地址
002EH 保留区
005CH 缺省文件控制块# 1
006CH 缺省文件控制块# 2(第 2个未经打开时将被覆盖 )
0080H
00FFH 命令行尾和缺省磁盘传送区域 (缓冲区 )
第 4章 伪指令及汇编语言源程序结构一个典型的,EXE型文件在刚刚加载进入内存后的映像如图
4-4所示。 EXE的内容被重新定位后,被加载到重新段前缀之后。
代码段、数据段和堆栈段驻留在不同的段中 (可不必与图 4-4所示的顺序相同 )。程序入口可位于代码段的任何地址中,该入口由程序主模块的 END语句给出。程序取得控制权后,DS和 ES寄存器指向程序段前缀,通常程序先将这两个值保存起来,然后 DS
和 ES寄存器指向数据段 (或附加段 )。
汇编时,汇编程序必须知道程序的段结构和在各种指令执行时访问哪一段,这个信息是由 ASSUME命令提供的。
第 4章 伪指令及汇编语言源程序结构图 4-4 一个典型的,EXE型文件刚加载进入内存后的映像地 址
SS∶ SP 堆栈段:堆栈由高端向下生长
SS∶ 0000H 数据段
CS∶ 0000H 程序代码
DS∶ 0000H 程序段前缀第 4章 伪指令及汇编语言源程序结构例 4-69 阅读下面给出的程序,回答以下 3个问题。
(1) 使用 SEGMENT,ENDS和 ASSUME命令定义代码段、
数据段、堆栈段和附加段的方法;
(2) 在用过程定义的程序中,为什么在程序的开始部分会有:
PUSH DS
SUB AX,AX
PUSH AX
这样的 3条指令,即程序中标有 **的 3条指令。
…
第 4章 伪指令及汇编语言源程序结构
(3) 程序前缀 (PSP)的使用。
DATA SEGMENT ;数据段
X DB?
Y DW?
Z DD?
DATA ENDS
ESTRA SEGMENT ;附加段
ALPHA DB?
BETA DW?
GAMA DD?
ESTRA ENDS
第 4章 伪指令及汇编语言源程序结构
STACK SEGMENT PARA STACK 'STACK' ;堆栈段
STAPN DB 100 DUP(?) ; 100个字节栈空间
TOP EQU LENGTH STAPN
STACK ENDS
CODE SEGMENT ; 代码段
ASSUME CS∶ CODE,ES∶ ESTRA,DS∶ DATA,SS∶ STACK
HAIN PROC FAR
PUSH DS
SUB AX,AX **
PUSH AX
MOV AX,DATA
第 4章 伪指令及汇编语言源程序结构
MOV DS,AX
MOV AX,EXTRA
MOV ES,AX
MOV AX,STACK
MOV SS,AX
MOV AX,TOP
MOV SP,AX
ORG 0009H
RET
MAIN ENDP
CODE ENDS
END MAIN
第 4章 伪指令及汇编语言源程序结构本例中的数据段和附加段均定义了一些数据,在堆栈段中定义了 100个字节的堆栈空间。
ASSUME的格式、功能和使用方法在前面已作过介绍,
ASSUME语句告诉汇编程序可以假定一个特定的段寄存器指向一个特定的段,汇编程序还无法生成目的码程序,即 ASSUME
伪指令只是指出各段的段寄存器的分配,并没有把段地址装入相应的段寄存器,因此,在代码段中,还必须把段地址装入相应的段寄存器中,这个过程称之为段寄存器的加载。本例中由
ASSUME指明 CS寄存器指向命名为 CODE的段,ES指向 EXTRA
段,DS指向 DATA段,SS指向 STACK段。
第 4章 伪指令及汇编语言源程序结构各个段寄存器的加载方法是:由 DOS将控制权交给程序时,通过,EXE文件头的入口信息和程序加载地址计算得到代码段寄存器 CS和指令指针 (E)IP的初始值。入口信息由源代码中某程序模块中的 END语句的参数转换而来。数据段 CS和附加段 ES,FS,GS寄存器被设置指向程序段前缀,以便程序存取环境块指针、命令行尾以及包含于其中的别的有用的信息。
堆栈段寄存器 SS和堆栈指针 (E)SP的值由文件头给出。该指针信息由源程序中 STACK属性段转换而来,分配给堆栈的内存空间依堆栈段的定义,可以是初始化的,也可以是不经初始化的。
第 4章 伪指令及汇编语言源程序结构若将堆栈内存初始化为可识别的数据类型,能观察内存信息,确定程序使用了多少堆栈空间。要完成这一工作,必须通过一定的指令来实现。其中,CS的加载较为特殊,只有它是无需用户专门处理,DS,SS,ES,FS和 GS必须由用户通过编程自行加载。
第 4章 伪指令及汇编语言源程序结构
1,CS的加载
CS的加载有以下几种情况:
(1) 用户执行的 END后有标号,连接后的可执行程序自动将
CS,(E)IP在执行时执行该标号处;
(2) 遇到 JMP或 CALL指令时,自动修正 CS,(E)IP的值;
(3) 当使用 INT n时,或产生硬件中断时,将利用 n× 4的物理地址,从中取出低字装入 (E)IP、高字装入 CS;
(4) 硬件复位时,自动将 (E)IP清 0,CS置为 0FFFFH,以指向
ROM中初始化程序。
第 4章 伪指令及汇编语言源程序结构
2,DS,SS,ES,FS和 GS加载这几个段寄存器的加载应由用户编程实现,一般方法:
MOV AX,<逻辑段名 >
MOV <段寄存器名 >,AX
设数据段的段名为 DATA,加载 DS段寄存器的方法如下:
MOV AX,DATA
MOV DS,AX
一个,EXE程序执行完后,将通过 INT 20H功能调用将控制权返回 DOS。
第 4章 伪指令及汇编语言源程序结构在此程序中,若要求把字节单元 X的内容传送至字节单元
ALPHA,这需要在码段中增加一些指令。先把 X的内容传送给一个寄存器 (例如 BX),然后再从这个寄存器传送给 ALPHA,所以需要如下命令:
MOV BX,X
MOV ALPHA,BX
第 4章 伪指令及汇编语言源程序结构在指令执行时,80x86 CPU将用寄存器 DS去寻找所指定的项 (X或 ALPHA)所在段的起始地址。执行第一条指令工作正常,
因为 X确实是在由 DS的内容 DATA作为起始地址的段内。但在执行第二条指令时,如何能正常工作呢?因为包含有 ALPHA的这一段的起始地址 EXTRA并不在 DS中,对这样的指令,在汇编时,
由 ASSUME语句告诉汇编程序,EXTRA不在 DS中,而在另一个段寄存器 ES中。所以要正确执行第二条指令,必须要有 — 个段超越前缀,虽然指令中没有,汇编程序会产生这样的前缀,
加到第二条指令中去,以便将来能正确执行。
第 4章 伪指令及汇编语言源程序结构有些情况下,为了更明确地指明段寄存器,或代替
ASSUME语句的作用,可以在有关的指令中增加段超越前缀,
用以告诉汇编程序,在这一条指令执行时,应使用哪 — 个段寄存器,例如上面提到的把 X的内容移至 ALPHA中可以写成:
MOV DX,DS∶ X
MOV ES∶ ALPHA,BX
这表示当访问 X时,应用 DS,而访问 ALPHA时,应该用 ES。
第 4章 伪指令及汇编语言源程序结构由于程序采用的是过程定义方式 (过程定义在 4.3.4节中作了描述 ),在程序执行完成后能正确地返回,如本例所示,必须有标有 **的一段程序。当执行此程序时,DOS把控制权转给这个程序时,在程序段前缀的开始 (偏移地址 00H)处安排了一条中断返回指令 INT 20H(如图 4-3)。为了在程序执行后正常返回,必须先将 DS进栈,同时将段内偏移量 (AX中的零 )进栈。然后再把数据段的地址传送给 DS,由 ASSUME语句告诉汇编程序,DS寄存器指向数据段。
第 4章 伪指令及汇编语言源程序结构
4.6.2 COM文件结构
.COM文件结构的源程序经过汇编、连接形成,EXE文件后,
再用 EXE2BIN.EXE命令即可转换成,COM文件。
扩展名为,COM的文件也可以通过在 DOS下直接键入文件名的方法装入并执行,而且也产生一个程序段前缀。但是与,EXE
文件不同的是,DOS把段前缀看作是被装入文件的一部分,覆盖着被装入文件的前面 100H个字节。因此程序员必须保证程序中第一条可执行的指令一定在 CS∶ 100H处。
第 4章 伪指令及汇编语言源程序结构
.COM文件被装入后,CS,DS,ES,SS都设置为指向程序段前缀的段地址,IP固定为 100H,整个程序只占一个物理段 (最大 64 KB),SP指向这一物理段的末尾,并在栈顶存放了两个字节 00H。,COM文件不像,EXE文件那样带有定位信息,因此只能把整个文件看作一段,整段可重定位。但不能分段重定位。
正因为不带定位信息,因此程序中不能出现如 MOV AX,DATA
这样的指令,因为装入程序无法确定 DATA的定位信息。,COM
文件中若要对段寄存器进行操作,程序员应确保这些操作是参照当前 CS的。例如,应该用 PUSH CS与 POP DS指令代替,EXE
文件中的 MOV AX,CODE与 MOV DS,AX指令。,COM文件中任何地方都可以安排 INT 20H指令,以实现退出程序,返回
DOS。,COM文件占用内存少。
第 4章 伪指令及汇编语言源程序结构再者,因为不需要重定位信息,所以在用 DEBUG调试完,COM文件后,可用 DEBUG的写入命令将文件写回盘上。注意,因 DEBUG不能生成重定位信息,所以,.EXE文件经
DEBUG调试完后,不能直接写回盘上。
如果程序在编写时就符合,COM文件的规定要求,那么,
经汇编连接后生成的,EXE文件可以直接转换为,COM文件;
DOS中的 EXE2BIN程序可以将,EXE文件转换成,COM文件,但被转换的,EXE文件必须符合,COM文件的规定。例 4-70给出的程序是一个符合,COM文件要求的例子。
第 4章 伪指令及汇编语言源程序结构例 4-70
CODE SEGMENT
ASSUME CS∶ CODE,DS∶ CODE ;数据段和代码段是同一个物理段
ORG 100H
START,JMP BEGIN ;第一条可执行指令存放在 0100H处
BUF DB 35H,78H,0A5H
SUM DB?
BEGIN,MOV AX,CS
MOV DS,AX ;设置数据段地址
MOV AL,0
第 4章 伪指令及汇编语言源程序结构
MOV SI,OFFSET BUF
ADD AL,[SI]
INC SI
ADD AL,[SI]
INC SI
ADD AL,[SI]
MOV SUM,AL ;存储累加结果
MOV AH,4CH
INT 21H ;返回 DOS
CODE ENDS
END START
第 4章 伪指令及汇编语言源程序结构由此可看出,.COM结构的程序有如下两个特点:
(1) 整个程序逻辑段可以有几个,但物理段只能有一个,
即整个程序 (包括数据和代码 )在一个段 (64 KB)的范围内。
(2) 程序中的第一条可执行指令在段中的 0100H处存放。
第 4章 伪指令及汇编语言源程序结构习 题 四
4.1 对于下面数据定义,三条 MOV指令分别汇编成什么?
(可用立即数方式表示)
TABLEA DW 10 DUP(?)
TABLEB DB 10 DUP(?)
TABLEC DB '1234'
MOV AX,LENGTH TABLEA
MOV BL,LENGTH TABLEB
MOV CL,LENGTH TABLEC
…
第 4章 伪指令及汇编语言源程序结构
4.2 在指令 AND AX,OPD1 AND OPD2中,OPD1和 OPD2
是两个已赋值的变量,问两个 AND操作分别在什么时间进行?
有什么区别?
4.3 如下指令或程序是否有错? 错在哪里?
(1) K1 EQU 1024
MOV K1,AX
(2) MOV DS,100
MOV [1000],[2000]
(3) IMP DB?
MOV IMP,AX
第 4章 伪指令及汇编语言源程序结构
(4) A1 DB?
A2 DB 10
CMP A1,A2
(5) 将 1000送入 X1单元,用如下程序:
X1 DB?
MOV BX,X1
MOV [BX],1000
第 4章 伪指令及汇编语言源程序结构
4.4 指出下列伪指令表达方式的错误,并改正之。
(1) STACK_SEG SEGMENT 'STACK'
(2) DATA_SEG SEG
(3) MYDATA SEGMENT 'DATA'
ENDS
(4) SEGMENT 'CODE'
(5) MAIN_PROC PROC FAR
END MAIN_PROC
MAIN_PROC ENDP
…
…
第 4章 伪指令及汇编语言源程序结构
4.5 下列语句在存储器中分别为变量分配多少字节?
VR1 DW 9
VR2 DW 4 DUP(?),2
CONT EQU 10
VR3 DD CONT DUP(?)
VR4 DB 2 DUP(?,CONT DUP(0))
VR5 DB 'HOW ARE YOU? '
第 4章 伪指令及汇编语言源程序结构
4.6 下面语句有何区别?
X1 EQU 1000H
X2 = 1000H
4.7 分析操作符和合成操作符各有哪几种,分别举例并加以解释说明。
4.8 80x86汇编语言程序中段的类型有几种?各段如何定义?
段定义中,定位类型,组合类型、类别各起什么作用?各有什么含义?
第 4章 伪指令及汇编语言源程序结构
4.9 画图说明下列伪指令所定义的数据在内存中的存放形式。
ARY1 DB 7,43H,-2
ARY2 DW 476FH,1,?
ARY3 DB 3 DUP(1,2 DUP(2),3)
第 4章 伪指令及汇编语言源程序结构
4.10 定义一个名字为 DATA的数据段,段中的变量及数据如下:
DA1为字符串变量,'ABCDEPGH'
DA2为字节变量,43H,76,-5,0F8H
DA3为字变量,20个 0
DA4为字变量,4F5AH,3786,-2
DA5为双字变量,768AEF4BH
第 4章 伪指令及汇编语言源程序结构
4.11 假设有如下数据定义伪指令:
BUF1 DB 1,2,3,4,5
BUF2 DB 10 DUP(?)
BUF3 DW 4786H,5F6BH
BUF4 DW 20 DUP(?)
第 4章 伪指令及汇编语言源程序结构写出下列指令执行后的结果:
MOV AL,TYPE BUF1 AL=( )
MOV BL,TYPE BUP4 BL=( )
MOV CL,LENGTH BUF1 CL=( )
MOV DL,LENGTH BUF2 DL=( )
MOV AH,LENGTH BUF4 AH=( )
MOV BH,SIZE BUF2 BH=( )
MOV CH,SIZE BUF3 CH=( )
MOV DH,SIZE BUF4 DH=( )
第 4章 伪指令及汇编语言源程序结构
4.12 给定如下数据定义伪指令:
BUFB DB 42H,1,-1
BUFW DW 4785H,2A60H
写出下列指令执行后的结果:
MOV AL,BUFB AL= ( H)
MOV Bl,BYTE PTR BUFW BL= ( H)
MOV AX,WORD PTR BUFB+1 AX= ( H)
MOV BX,BUFW+2 BX= ( H)
第 4章 伪指令及汇编语言源程序结构
4.13 给出如下伪指令:
BUF DW 10,20,30,40,50
下面的程序段执行后,AX= ( H)
MOV BX,OFFSET BUF
ADD BX,5
MOVAX,[BX]
第 4章 伪指令及汇编语言源程序结构
4.14 自 BX寄存器所指的内存单元开始,连续存放着两个四字节的有符号数 (低位字节在前 ),编程序求它们的差 (第一个数减第二个数 ),并将结果存放在这两个数之后,若有溢出,
将 BX寄存器清零。
第 4章 伪指令及汇编语言源程序结构
4.15 编程序使:
(1) AX寄存器的低四位清零。
(2) BX寄存器的低四位置 1。
(3) CX寄存器的低四位变反。
(4) 用 TEST指令测试 DL寄存器的位 3位 6是否同时为 0,若是,
将 0送 DL寄存器;否则,将 1送 DH。要求用两种方法。
4.16 编程序使 AL寄存器中的无符号数乘 20。
第 4章 伪指令及汇编语言源程序结构
4.17 数据定义语句如下所示:
FIRST DB 90H,5FH,6EH,69H
SECOND DB 5 DUP(?)
THIRD DB 5 DUP(?)
FOURTH DB 5 DUP(?)
自 FIRST单元开始存放的是一个四字节的十六进制数 (低位字节在前 ),注意保留移出部分。要求:
(1) 编一段程序将这个数左移两位后存放到自 SECOND开始的单元。
(2) 编一段程序将这个数右移两位后存放到自 THIRD开始的单元。
(3) 编一段程序将这个数求补以后存放到自 FOURTH开始的单元。
4.1 汇编程序结构
4.2 汇编语言语句格式
4.3 伪指令语句
4.4 标号、变量和表达式
4.5 段的组织
4.6 程序段前缀第 4章 伪指令及汇编语言源程序结构
4.1 汇编程序结构
4.1.1 寄存器组和语法元素
1,80x86的可编程的寄存器组
1) 通用寄存器组
EAX,EBX,ECX,EDX,ESI,EDI,EBP和 ESP是 32位可编程的通用寄存器,即程序员编程可以使用的寄存器。其中低 16位用 AX,BX,CX,DX,SI,DI,BP或 SP表示。 AX,BX,CX,DX还可以分成两个 8位寄存器,即低 8位为 AL,BL,CL,DL;高 8位为
AH,BH,CH,DH。
第 4章 伪指令及汇编语言源程序结构
2) 段寄存器
8086有 4个 16位的段寄存器,CS,SS,DS,ES,而 80486有六个 16位的段寄存器,CS,SS,DS,ES,FS和 GS。在实地址方式下,段寄存器的内容左移 4位而得到段基地址。在保护方式下,
段寄存器存放的是描述符的选择符。
3) 指令计数器指令计数器保存下一条指令相对于 CS段基地址的偏移值,
它可作 16位用,也可作 32位用。指令计数器采用 16位段时用 IP,
采用 32位段时用 EIP。调试程序时,(E)IP的值显示的是下条要执行的指令在 CS段中的偏移地址。
第 4章 伪指令及汇编语言源程序结构
4) 标志寄存器
EFLAGS是一个 32位的标志寄存器,可用指令 PUSHFD压入堆栈,指令 POPFD从堆栈弹出。可对 EFLAGS的低 16位 FLAGS单独进行操作,通过 PUSHF将其压入堆栈,POPF从堆栈弹出。
5) 控制寄存器
4个 32位控制寄存器 CR0,CR1,CR2,CR3中的 3个,即 CR0、
CR2,CR3为程序员使用。 Intel公司保留了 CR1。使用 MOV指令传送控制寄存器 CR0,CR2,CR3中的内容。例如,指令 MOV CR0,
EBX实现的功能就是将 EBX的内容送到 CR0中。
第 4章 伪指令及汇编语言源程序结构
6) 调试寄存器
DR4和 DR5为 Intel公司保留,程序员编程时不能使用 DR4和
DR5,其余的调试寄存器的内容可通过 MOV指令传送。例如,指令 MOV EAX,DR6是将调试寄存器 DR6中的内容送到 EAX中。
7) 测试寄存器程序员编程时能使用的测试寄存器只有 TR6和 TR7,其他为
Intel公司保留,则不能使用。例如,指令 MOV ECX,TR7实现的功能就是将 TR7的内容送到 ECX中。
第 4章 伪指令及汇编语言源程序结构
8) 系统地址寄存器
80486用 4个寄存器把在保护模式中常用的数据结构基地址、
限制和其他属性保存起来,以确保其快速性。这 4个寄存器是:
全局描述符寄存器 GDTR、局部描述符寄存器 LDTR、中断描述符寄存器 IDTR和任务寄存器 TR。与这 4个寄存器有关的指令是 LGDT、
LIDT,LLDT,LTR,LGDT或 LIDT,实现的功能就是将内存中六个字节的内容装入 GDTR或 IDTR中。 LLDT或 LTR把寄存器或内存中两个字节的内容装入 LDTR或 TR中,与上述 4条指令传送方向相反的指令是 SGDT,SIDT,SGDT,STR。注意这里任务寄存器 TR与测试寄存器 TR6,TR7的区别。
第 4章 伪指令及汇编语言源程序结构
2.语法规则和语法要素
1) 字符集汇编语言字符集是 ASCII字符集的一个子集,源文件中的每一个字符都应该是下列字符之一,
(1) 字母 26个英文大小写字母;
(2) 数字 0~ 9;
(3) 特殊字符 + - × / ( ) [ ] < > ; ’ 。,
-,? @ $ &;
(4) 定界符 空格符、制表符、回车符 (CR)、换行符 (LF)。
第 4章 伪指令及汇编语言源程序结构程序中出现不在上列字符集中的字符,汇编系统把该字符当作一个逻辑空格符来处理。逻辑空格符就是把多个连续的空格符或制表符当作一个空格符来处理。
在程序中,字母的大小写是无关的,可以互换。但是字符串中的字母大小写是不能互换的,如 ‘ XYZ’与 ‘ xyz’,是不相等的字符串。
第 4章 伪指令及汇编语言源程序结构
2) 标识符一个标识符是程序员用来定义段、变量、标号或常量等项目的名字。一个有效的标识符应遵循以下规则,
(1) 标识符的首位字符必须是一个字母或下述 3个特殊字符之一,? (问号 ),@ (AT符号 ),_ (下划线符号 )
(2) 其余的字符可以是字母、数字或是上面 3个特殊字符,标识符中间不能有分隔符 (逻辑空格或定界符 );
(3) 一个标识符可有长达 255个字符,系统只识别前 31个字符;
(4) 一个程序模块内的每一个标识符只代表而且仅仅代表一个项,在模块的任何地方都可以通过标识符访问它所表示的项。
第 4章 伪指令及汇编语言源程序结构
3) 关键字和保留字汇编语言的关键字和保留字都是系统自己预定义的标识符。
关键字指的是指令助记符,如加法指令 ADD、中断返回指令
IRET等。保留字指的是伪指令或其他功能符号,如 SEGMENT、
DWORD等。
第 4章 伪指令及汇编语言源程序结构
4) 语言符号和分隔符语言符号是源程序中最小的有意义的单元,非常类似英语语句中的单词。汇编语言的语言符号有以下几种:
(1) 一条语句的结束,如换行符 (LF)或回车 /换行符
(CR/LF),用来分开两条汇编语句;
(2) 一个定界符,如逗号,,,和分号,;,;
(3) 一个标识符,如用户定义的 PROGRAM_DATA,FTT等;
第 4章 伪指令及汇编语言源程序结构
(4) 一个常量,如 56DEH,3.1415等;
(5) 一个关键字或保留字,如 SUB,ASSUME等。 ASSUME是一条伪指令语句,其格式、功能和使用方法将在 4.3.2节的
,逻辑段定义伪指令,中讲述。
一个分隔符是一个逻辑空格或一个定界符,在相邻的标识符、常量、关键字、保留字之间,必须用分隔符把它们隔开。
最常用的分隔符是空格。
第 4章 伪指令及汇编语言源程序结构
4.1.2 源程序框架结构
1.源程序结构一个以 MASM为基础的汇编语言源程序的结构形式如例 4-1所示。
例 4-1
NAME MAIN_PROGMODULE
DATA SEGMENT ;定义数据段
(数据定义伪指令序列 )
DATA ENDS
STACK SEGMENT ;定义堆栈段
(数据定义伪指令序列 )
…
…
第 4章 伪指令及汇编语言源程序结构
STACK ENDS
CODE SEGMENT ;定义代码段
ASSUME CS∶CODE,SS∶STACK,DS∶DATA,ES∶DATA
START,MOV AX,DATA ;建立数据段和附加数据段的可寻址性
MOV DS,AX ;置 DS和 ES初值
MOV ES,AX
(用户编写的程序段 )
MOV AH,4CH ;返回操作系统
INT 21H
CODE ENDS
END START
…
第 4章 伪指令及汇编语言源程序结构该源程序结构中的每行语句的用法及含义是:
1) NAME MAIN_PROGMODULE
NAME是保留字,用于定义程序模块的名称,MAIN_MODULE
是程序名称,用户可用任意一个标识符为程序命名。
第 4章 伪指令及汇编语言源程序结构
2) DATA SEGMENT
(数据定义伪指令序列 )
DATA ENDS
DATA是程序员命名的数据段名称。 SEGMENT和 ENDS是保留字,SEGMENT与 ENDS配对使用,ENDS前的 DATA应与 SEGMENT取的
DATA一致。其功能是使用伪指令语句定义数据段、代码段和变量,并可预置变量的初值。
…
第 4章 伪指令及汇编语言源程序结构
3) STACK SEGMENT
(数据定义伪指令序列 )
STACK ENDS
STACK是程序员命名的堆栈段名称。其功能是使用伪指令语句定义堆栈段。
4)CODE SEGMENT
ASSUME CS,CODE,SS,STACK,DS,DATA,ES,DATA
CODE ENDS
CODE是程序员命名的代码段名称,SEGMENT在这里定义一个代码段。
…
…
第 4章 伪指令及汇编语言源程序结构
5) ASSUME CS∶CODE,SS∶STACK,DS∶DATA,ES∶DATA
ASSUME是保留字,指示段寄存器对应前面定义的哪个段。
CS∶CODE,SS∶STACK,DS∶DATA,ES∶DATA 分别指出 CS,SS、
DS和 ES寄存器与 CODE,STACK,DATA段对应。
6) START
START是程序员定义的程序入口处的标号名。用冒号,,,
说明 START是一个标号。
第 4章 伪指令及汇编语言源程序结构
7) 程序部分
START,MOV AX,DATA
MOV DS,AX
MOV ES,AX
(用户编写的程序段 )
MOV AH,4CH
INT 21H
这里是程序员编写的程序。
…
第 4章 伪指令及汇编语言源程序结构
8) CODE ENDS
这条语句指出所定义的 CODE代码段到此结束。
9) END START
END是保留字,指示整个程序模块到此结束。
按上述格式写出的一个程序如例 4-2所示:
第 4章 伪指令及汇编语言源程序结构例 4-2
NAME SIMPLE_EXAMPLE
FIRST_DATA SEGMENT
STRING_DA DB 'This is My First Program $' ;要显示的字符串
FIRST_DATA ENDS
FIRST_STACK SEGMENT PARA STACK ' STACK'
DB 100 DUP(?)
FIRST_STACK END
FIRST_CODE SEGMENT
ASSUME DS∶FIRST_DATA,SS∶FIRST_STACK,CS∶FIRST_CODE
第 4章 伪指令及汇编语言源程序结构
START,MOV AX,FIRST_DATA
MOV DS,AX
MOV DX,STRING_DA
MOV AH,02H
INT 21H ; DOS功能调用
MOV AH,4CH
INT 21H
FIRST_CODE ENDS
END START
第 4章 伪指令及汇编语言源程序结构该程序运行的结果是在屏幕上显示一行字符:,This is
My First Program”。
80x86系列微处理器的存储器采用了分段管理的方法,其汇编语言是以逻辑段为基础,按段的概念来组织代码和数据的,
汇编语言源程序的结构特点有:
(1) 由若干逻辑段组成,各逻辑段由伪指令语句定义和说明。
(2) 整个源程序以 END伪指令结束。
第 4章 伪指令及汇编语言源程序结构
(3) 每个逻辑段由语句序列组成,各语句可以是:
指令语句 —— 完成一定操作功能,能够翻译成机器代码的语句,即为第 3章介绍的指令所形成的语句。指令语句对应于 CPU指令系统中的一条指令,因此为可执行语句。汇编时汇编成目标码。
第 4章 伪指令及汇编语言源程序结构伪指令语句 —— CPU不执行的语句,只是为汇编程序在翻译成汇编语言源程序时提供有关信息,并不翻译成机器代码的语句。因此,伪指令语句是协助汇编系统实现某种特定的操作,
决定程序的数据段、堆栈段和代码段的组织。伪指令语句本身并不完成任何机器指令的功能,但对汇编系统生成的所有操作码是要产生影响的。如:在某程序中:
BUFFERA DB 35H
BUFFERB DW 123AH
SUM DD?
第 4章 伪指令及汇编语言源程序结构就是伪指令语句,其功能是在内存中设置 3个存储单元,单元的名字分别是,BUFFERA,BUFFERB和 SUM。 BUFFERA,BUFFERB的初值是 35H和 123AH,而 SUM单元未定义初值。
宏指令语句 —— 由若干条指令语句形成的语句。一条宏指令语句的功能相当于若干条指令语句的功能。宏指令语句实际上是一个指令序列,汇编时产生对应的目标代码序列。
第 4章 伪指令及汇编语言源程序结构注释语句 —— 以分号,;,开始的说明性语句,汇编程序不予以处理,只起注释作用,使程序易于理解。
空行语句 —— 为保持程序书写清晰,仅包含回车换行符的语句行。
注意:有关逻辑段的定义和说明伪指令,以及其他伪指令 /
指令语句的格式与参数规定等,因汇编程序的类型和版本不同而有所不同。
第 4章 伪指令及汇编语言源程序结构
(4) 80x86汇编语言源程序一般具有数据段、附加数据段、
堆栈段和代码段。但是,根据程序的实际情况,堆栈段、数据段和附加段也可以没有;只有代码段是必不可少的,每个程序至少必须有一个。当然,对于复杂、庞大的源程序,这几种逻辑段也分别允许定义多个。不过允许同时使用的段则是有限定的,8086/8088只允许同时使用 4个段,即堆栈段 (SS)、数据段
(DS)、附加段 (ES)和代码段 (CS)各一个; 80486允许同时使用 6
个段,即除以上 4个段外,还可有 FS和 GS两个附加数据段。在
8086和实地址方式下,每个段的大小可以是 1~ 64 KB;而在保护方式下,80486允许 4 GB。
第 4章 伪指令及汇编语言源程序结构
(5) 由于段寄存器说明伪指令只说明了各段寄存器与逻辑段的关系,并没有设置段寄存器的初值,所以在源程序中,除代码段 CS(有时还有堆栈段 SS)外,其他所有定义的段寄存器的初值都要在程序代码段的起始处由用户自己设置,以建立这些逻辑段的可寻址性。
(6) 每个源程序在其代码段中都必须含有返回到 DOS操作系统的指令语句,以保证程序执行完后能自动返回 DOS状态,可继续向计算机键入命令或程序。终止当前程序,使其正确返回 DOS
状态的方法通常有以下四种:
第 4章 伪指令及汇编语言源程序结构
① 采用 DOS 4CH号功能调用。这种方法在代码段结束前加调用语句:
MOV AH,4CH ;功能号 4CH→AH
INT 21H ;中断调用这种方法在前面的源程序结构中我们已使用过。这是返回 DOS最有效且兼容性最好的一种方法。
第 4章 伪指令及汇编语言源程序结构
② 将主程序定义为远过程。这种方法在代码段开始处按例
4-3所述方式定义主程序:
例 4-3
CODE SEGMENT …
ASSUME …
主过程名 PROC FAR
PUSH DS
MOV AX,0
PUSH AX
RET
主过程名 ENDP
END 主过程名一般也将这种方法称为,标准序,方法。
…
…
…
第 4章 伪指令及汇编语言源程序结构
③ 利用 20号软中断调用。调用方式:
INT 20H
这种方法在产生扩展名为,EXE的可执行文件中是不能使用的,
但可用于小模式的扩展名为,COM的可执行文件中,作为返回 DOS
的一种方法。但是任一汇编语言源程序经汇编、连接之后产生的可执行文件都是扩展名为,EXE类型的,这时如果源程序是按小模式形式编写的,则在连接之后可用 DOS提供的,EXE 2BIN”
转换程序将,EXE文件转换成,COM文件。这样在程序中的 INT
20H指令就可使控制权返回到 DOS。
第 4章 伪指令及汇编语言源程序结构
④ 利用 DOS的 0号功能调用。调用方式:
MOV AH,0
INT 21H
该方式也是只有在,COM格式的可执行文件中才可使用。
第 4章 伪指令及汇编语言源程序结构
4.2 汇编语言语句格式
4.2.1 语句种类根据汇编语言的语法规则,编写汇编语言源程序除了需要用第 3章介绍的指令系统中的指令并满足一定的结构要求外,还要用到伪指令甚至宏指令。汇编语言使用的语句一般包括:指令语句,伪指令语句,宏指令语句。
第 4章 伪指令及汇编语言源程序结构
4.2.2 语句格式本节只介绍指令语句和伪指令语句的格式,有关宏指令语句格式及其使用在第 8章中讲述。
指令语句和伪指令语句的格式基本相同,均由 4部分 (又称 4个域 )组成。其格式分别是:
指令语句,[标号,]助记符 [操作数 ][;注释 ]
伪指令语句,[名字 ]定义符 [操作数 ][;注释 ]
其中,格式中方括号,[ ]”内的内容为可选项。
这两种语句在格式上的主要不同在于,指令语句中的标号后面要加冒号,,,,而在伪指令语句中的名字后面不能跟冒号。
现对格式中的四个部分作如下说明。
第 4章 伪指令及汇编语言源程序结构
1.标号和名字标号和名字分别是给指令单元和伪指令起的符号名称,统称为标识符。标号指出了指令的起始地址。程序员可通过标号来引用所标识的指令,如可作为 JMP和 CALL指令的转移目标,与具体的指令地址相联系。而伪指令语句中的名字一般用作定义变量名、过程名、记录名等,不作为指令的操作数使用。标号可以任选或省略,而名字有时可任选或省略,有时则是强制的,
具体取决于实际的定义符。标号和名字都可由不超过 31个的字符串组成。可选字符集为:
第 4章 伪指令及汇编语言源程序结构
1.标号和名字标号和名字分别是给指令单元和伪指令起的符号名称,统称为标识符。标号指出了指令的起始地址。程序员可通过标号来引用所标识的指令,如可作为 JMP和 CALL指令的转移目标,与具体的指令地址相联系。而伪指令语句中的名字一般用作定义变量名、过程名、记录名等,不作为指令的操作数使用。标号可以任选或省略,而名字有时可任选或省略,有时则是强制的,
具体取决于实际的定义符。标号和名字都可由不超过 31个的字符串组成。可选字符集为:
第 4章 伪指令及汇编语言源程序结构
(1) 字母 A~ Z或 a~ z;
(2) 数字 0~ 9;
(3) 特殊符号 @$- ·:? [] () ; / + - * % &等。
必须注意,标号不允许用数字开头,也不允许用特殊符号单独作为标识符,更不允许用汇编语言中有特定意义的保留字,
如指令助记符、伪指令、寄存器名和运算符等。
第 4章 伪指令及汇编语言源程序结构
2.助记符和定义符助记符和定义符分别用于规定指令语句的操作性质和伪指令语句的伪操作功能,所以统称为操作符。要注意的是,在指令语句的助记符前面,还可根据需要加,前缀,。
第 4章 伪指令及汇编语言源程序结构
3.操作数操作数也叫参数。助记符和定义符都可后跟一个或多个操作数,作为操作处理的对象,当然也可不跟。各操作数之间要用逗号,,,分隔开。
根据寻址方式等因素的不同,操作数可以有 4类:常量、寄存器、存储器和表达式。对常量、存储器和表达式 3种操作数作如下说明。
第 4章 伪指令及汇编语言源程序结构
1) 常量操作数常量操作数可以是二、八、十或十六进制的整型常数,十六进制实数,字符串和已赋值的常数标识符,也可以是寄存器名和 I/O端口地址,如 EAX,SI和 5FH等。
第 4章 伪指令及汇编语言源程序结构
2) 存储器操作数存储器操作数分为标号和变量两种。标号是某条指令所存放单元的符号化地址,这个地址一定在代码段中,它是转移 /调用指令的目标操作数。变量则是数据所存放单元的符号化地址,
它一般位于数据段或堆栈段中,不可能在代码段中。可用各种寻址方式对变量进行存取。
第 4章 伪指令及汇编语言源程序结构作为存储器操作数的标号和变量有三种共同属性:
段值 —— 段基址,可用 SEG运算符求得。
偏移值 —— 段内偏移地址,可用 OFFSET运算符求得。
类型 —— 对变量有字节、字、双字、四字、十字等 5种类型;
对标号有 NEAR和 FAR两种类型。可用 TYPE运算符求得。
除此之外,变量操作数还有另外两个属性:长度和字节数,
可分别用 LENGTH和 SIZE运算符求得。
第 4章 伪指令及汇编语言源程序结构
3) 表达式操作数它由各种操作数、界限符 (如圆括号,( )”、方括号,[ ]”
等 )和运算符组成。汇编时,每个表达式都能产生一个确定的值。
运算符包括:算术运算符、逻辑运算符和关系运算符。操作符有分析操作符和合成操作符两种。
(1) 算术运算符有:加 (+)、减 (-)、乘 (*)、除( /)和求模( MOD)。算术运算符总可以应用于数字操作数,结果也是数字的。应用于存储器地址操作数时,有意义的运算符是加和减。
第 4章 伪指令及汇编语言源程序结构
(2) 逻辑运算符是按位操作的与 (AND)、或 (OR)、异或 (XOR)
和非 (NOT)。逻辑运算符的操作数只能是数字的,且结果也是数字的。存储器地址操作数不能进行逻辑运算。
注意:有些运算符尽管与指令的名字相同,但它们与指令有着本质区别:指令是在程序运行时执行的语句,而运算符是在汇编时由汇编程序完成其功能的。如,AND,OR,XOR和 NOT也是指令助记符。作为运算符使用时,它们是在程序汇编时计算的。而作为指令助记符时,则是在程序执行时计算的。例如第 4章 伪指令及汇编语言源程序结构
AND DX,PORT AND 0FEH
其中第二个 AND是逻辑运算符,在汇编时,计算 PORT AND 0FEH
后,产生一个立即数作为指令的操作数。而第一个 AND是指令助记符,在汇编以后,执行 AND指令时,DX的内容与上述立即数相
,与,,结果放在 DX中。
第 4章 伪指令及汇编语言源程序结构
(3) 关系运算符有相等 (EQ)、不等 (NE)、小于 (LT)、大于
(GT)、小于或等于 (LE)、大于或等于 (GE)。关系运算符连接两个操作数,必须都是数字的或是在同一段内的存储器地址。运算结果始终是一个数字值。若关系是假 (关系不成立 ),则结果为 0;若关系为真,则结果为 0FFFFH。
第 4章 伪指令及汇编语言源程序结构例 4-4
MOV BX,PORT LT 5
若 PORT的值小于 5,则汇编程序将把这条指令汇编为
MOV BX,0FFFFH
否则,若 PORT的值不小于 5,则汇编为
MOV BX,0
第 4章 伪指令及汇编语言源程序结构一般不单独使用关系运算符。因为运算的结果不是 0就是
0FFFFH,没有别的选择,所以,常与其他运算符组合起来使用。
例如:
MOV BX,((PORT LT 5) AND 20) OR ((PORT GE 5)
AND 30)
当 PORT的值小于 5时,上述指令将汇编为
MOV BX,20
否则为 MOV BX,30
第 4章 伪指令及汇编语言源程序结构
(4) 分析操作符和合成操作符。分析操作符也叫分解操作符,可从变量或标号中分解出某些属性值,把存储器操作数分解为它的组成部分;合成操作符也叫属性操作符,可用来改变原有变量或标号的类型,把组成部分综合为存储器操作数。分析操作符有,SEG(返回段基址),OFFSET(返回偏移地址)、
LENGTH(返回变量单元数),TYPE(返回元素字节数),SIZE
(返回变量总字节数),返回的运算结果分别是:段基址、偏移地址、单元数、字节数和总字节数。
分析操作符和合成操作符将在 4.3.1节中作详细介绍。
第 4章 伪指令及汇编语言源程序结构
4.注释注释部分以分号开始,其作用与注释语句相同。注释语句是对后跟程序段的功能加以说明,而以分号开始的注释是对语句的功能加以说明,目的在于增加程序的可读性。注释部分不被汇编程序汇编,也不被执行,只对源程序起说明作用。
第 4章 伪指令及汇编语言源程序结构
4.3 伪 指 令 语 句
4.3.1 符号 /数据 /标号定义伪指令语句
1.符号定义伪指令符号定义伪指令可用来为表达式赋予一个符号名,表达式可以是常数、变量、标号、指令语句和字符等。在程序中,任何需要这种表达式的地方都可使用被赋予的符号名来代替它。
符号定义伪指令语句有两种,即等值语句和等号语句。
第 4章 伪指令及汇编语言源程序结构
1) 等值语句 (EQU)
格式:符号名 EQU 表达式功能:用符号名代替表达式的值,供以后引用。
说明,EQU语句不能重新定义,即在同一源程序中,用它定义的符号名不能再赋予不同的值。使用 EQU语句时,必须先赋值后使用。
例 4-5 下面是等值语句的例子。
X EQU 50
Y EQU X+10
COUNT EQU CX
第 4章 伪指令及汇编语言源程序结构
2) 等号语句 (=)
格式:符号名=表达式功能:等号语句的功能与 EQU语句的功能相同,只是其符号名可以再定义。
例 4-6 下面是等号语句的 3个例子。
PORT1= 30H
PORT1= PORT1+ 20H
PORT1= 325 * 8
第 4章 伪指令及汇编语言源程序结构
2) 数据定义伪指令格式,[符号名 ] DB/DW/DD/DF/DQ/DT 初值序列功能:为数据项分配一个或多个字节 /字 /双字 /长字 /四字
/十字节的存储空间,给它们赋初值,并用一个符号名与之相联系。
第 4章 伪指令及汇编语言源程序结构说明:
(1) 数据定义伪指令按数据长度可分为 DB,DW,DD,DF、
DQ,DT 6种类型,分别定义 8位,16位,32位,48位,64位、
80位数据。具体地讲就是:
● DB指一个操作数占用一个字节单元,定义的变量为字节变量;
● DW指一个操作数占用一个字单元 (2个字节单元 ),定义的变量为字变量;
● DD指一个操作数占用一个双字单元 (4个字节单元 ),
定义的变量为双字变量;
第 4章 伪指令及汇编语言源程序结构
● DF指一个操作数占用一个三字单元 (6个字节单元 ),定义的变量为三字变量,该助记符仅用于 386以上的 CPU,定义的变量作为指针使用,其低 4字节存放偏移地址,高 2字节存放段地址;
● DQ指一个操作数占用一个四字单元 (8个字节单元 ),定义的变量为四字变量;
● DT指一个操作数占用 10个字节单元,定义的变量为十字节变量,使用该助记符时,对于十进制操作数,必须给出后缀 D,没有后缀的默认为压缩 BCD码。
第 4章 伪指令及汇编语言源程序结构
(2) 与数据项相联系的符号名称为变量,经过定义的变量名有 3个属性:数据类型 (字节、字、双字、长字、四字、十字 )、
偏移量 (可用 OFFSET运算符获得 )和段基址 (可用 SEG运算符求得 ),
符号名为可选项。
第 4章 伪指令及汇编语言源程序结构
(3) 给变量赋初值:
① 可以是赋确定的值,也可以是赋用,?,表示不确定的值。赋不确定值,实质是不赋值,而只预留规定长度的存储空间。
② 初值序列可以是一个元素,也可以是用逗号分隔的多个元素。
③ 用 DUP运算符建立单个值的多次拷贝,确定值可以是整数、浮点数 (只允许 DD,DQ和 DT伪指令,并只用于 80486和
80387/80287协处理器上 )、字符、字符串或表达式。
第 4章 伪指令及汇编语言源程序结构例 4-7
VAR1 DB? ;给变量 VAR1分配一个字节,但不赋初值
VAR2 DD? ;给变量 VAR2分配 4个字节,但不赋初值
XY DT 3456H ;给变量 XY分配 10个字节,初值为 3456H
STR1 DB 'ABCDE' ;给字符串分配 5个字节,并赋初值 (ASCII码 )
ARRAY DW 20 DUP(1) ;给数组变 ARRAY分配 20个字,初值均为 1
BUFF DB 6 DUP(? ) ;相当于 DB?,?,?,?,?,?
COUNT DB 25,35,45 ;给变量 COUNT分配 3个字节,并赋初值。
第 4章 伪指令及汇编语言源程序结构
(4) 对操作数的说明。
① 操作数是常数或表达式 (代表的是数据或内存单元地址 )。
例 4-8 操作数是数据的定义形式。
DATAB DB 18H,-1,30 ;每个数占用一个字节单元
DATAW DW 18H,2A45H ;每个数占用一个字单元
DATAD DD 18H,2F3A124BH ;每个数占用一个双字单元第 4章 伪指令及汇编语言源程序结构在内存中的存储情况如图 4-1所示。
说明:操作数可用各种进制形式书写,汇编程序将其转换成相应的补码存入内存单元中。同样一个数 (如 18H),由于数据定义助记符的不同,所占用的内存空间是不一样的。数据的高字节存放在高地址单元,低字节存放在低地址单元。
第 4章 伪指令及汇编语言源程序结构图 4-1 内存中的存储情况
18
FF
1E
18
00
45
2A
18
00
00
00
4B
12
3A
2F
D A T A D
D A T A W
D A T A B
第 4章 伪指令及汇编语言源程序结构例 4-9 操作数是地址的定义形式。
ADDR1 DW NEXT ;存放偏移地址
ADDR2 DD NEXT ;存放偏移地址和段地址
NEXT,MOV AL,34H
NEXT是一条指令的标号,表示这条指令所在单元的地址,
ADDRW是一个字单元,只存放偏移地址,ADDRD是一个双字单元,
存放的是偏移地址和段地址,存储情况如图 4-2所示。
第 4章 伪指令及汇编语言源程序结构图 4-2 偏移地址和段地址偏移地址低字址偏移地址高字址偏移地址低字址偏移地址高字址段地址低字址段地址高字址
A D D RW
A D D RD
第 4章 伪指令及汇编语言源程序结构
② 操作数是字符串时,内存中存放的是每个字符的 ASCII码。
例 4-10 下面 3个定义语句是等价的。
STR1 DB 'ABCD'
STR1 DB 'A','B','C','D'
STR1 DB 41H,42H,43H,44H
第 4章 伪指令及汇编语言源程序结构例 4-11 下面两个定义语句是等价的。
STR2 DB,'AB'
STR2 DW,'BA'
当定义的字符串中字符多于两个时,只能使用 DB定义,不能使用 DW。例如,定义 STR3 DW,'ABCD'是错误的。
第 4章 伪指令及汇编语言源程序结构
③ 操作数是,?”,此时只分配单元,不定义初值。例如:
BUF1 DB 5,6,7,?
BUF2 DW 56H,78H,?,345FH
第 4章 伪指令及汇编语言源程序结构
④ 复制操作符 DUP。操作数用复制操作符 DUP,表示操作数重复若干次。例如:
BUFFER1 DB 2 DUP(2,3,4)
等价于 BUFFER1 DB 2,3,4,2,3,4
BUFFER2 DW 1,2,3 DUP(6)
等价于 BUFFER2 DW 1,2,6,6,6
BUFFER3 DB 2 DUP(5,6,3 DUP(7))
等价于 BUFFER3 DB 5,6,7,7,7,5,6,7,7,7
第 4章 伪指令及汇编语言源程序结构
(5) 指令单元 NEAR和 FAR。一个指令单元能出现在一个
JMP或 CALL指令语句中。若这个单元的类型是 NEAR,汇编程序将产生一个段内 JMP或 CALL指令;若单元的类型是 FAR,则产生一个段间 JMP或 CALL指令。 — 个 NEAR指令单元规定了 — 个长度为两个字节的指针,即此指令单元在段内的地址偏移量。获取了此地址偏移量,就可以实现段内的转移和调用。一个 FAR指令单元规定了一个长度为四个字节的指针,即此指令单元所在段的段地址和段内的地址偏移量。只有获取了这四个字节,才能得到一个 FAR指令单元的全地址,才能实现段间的调用和转移。
第 4章 伪指令及汇编语言源程序结构例 4-12
CYCLE,CMP SUM,100
若存储单元 CYCLE的类型是 NEAR,当汇编程序遇到指令
JMP CYCLE
时,就产生一个段内 JMP指令。
从一个存储单元加或减一个数字值形成的新的存储器地址与原存储单元有相同的类型。若 SUM,BIG,CYCLE分别是字节型、
字型,NEAR型指令单元,则 SUM+2,BIG-3,CYCLE+1也分别是字节型、字型,NEAR型指令单元。
第 4章 伪指令及汇编语言源程序结构
3.除定义伪指令 PURGE
格式,PURGE 符号 1,符号 2,…,符号 n
功能:解除指定符号的定义,解除符号定义后,可用 EQU重新定义。
例 4-13 执行指令
DATA EQU 7
PURGE DATA
后,DATA可重新用 EQU进行定义。
DATA EQU 28
第 4章 伪指令及汇编语言源程序结构
4.标号定义伪指令 (LABEL)
格式:符号名 LABEL 类型功能:将紧跟在本伪指令语句后的标号、操作码、过程或变量建立新的符号名,并刷新其类型属性。对标号、操作码或过程,其类型为 NEAR,FAR;对变量,其类型为 TYTE,WORD、
DWORD,FWORD,QWORD或 TBYTE。
第 4章 伪指令及汇编语言源程序结构说明,LABEL伪指令提供了另一种定义标号或变量名的方法,
但它并不为符号名分配存储空间。如:
SUBRF LABEL FAR ;远调用入口
SUBRN,… ;近调用入口两个标号 SUBRF与 SUBRN均指向同一条指令,但由于它们的类型不同 (SUBRF是 FAR,而 SUBRN后有冒号,其类型隐含为 NEAR),
所以可用不同的调用方法 (远或近 )来访问标号所指的程序段,
即其他代码段可通过远标号 SUBRF来访问该程序段,而当前代码段可通过近标号 SUBRN来访问该程序段。
…
第 4章 伪指令及汇编语言源程序结构再如:
BAARAY LABEL BYTE
ARRAY DW 200 DUP(? )
MOV AL,[99] ;取数组的第 100个字节值 → AL
MOV AX,[98] ;取数组的第 99个字值 → AX
…
…
第 4章 伪指令及汇编语言源程序结构这里用两种方法定义了数组。由于 LABEL伪指令不为变量分配存储空间,因此 BARRAY与 ARRAY的地址实际上是相同的,即它们指向同一个数组,只是 BARRAY被定义为字节型,而 ARRAY被定义为字型。这样,可根据需要按不同类型去存取数组中的数据。
第 4章 伪指令及汇编语言源程序结构
5.分析和合成操作符
(1) 分析操作符把存储器地址操作数分解成它们的组成部分。这些操作符是 SEG,OFFSET,TYPE,SIZE,LENGTH。
① SEG操作符。
格式,SEG <变量或标号 >
功能:计算变量或标号的段地址,即返回存储器地址操作数所在段的段地址部分。
第 4章 伪指令及汇编语言源程序结构
② OFFSET操作符。
格式,OFFSET <变量或标号 >
功能:计算变量或标号的段内偏移地址,即返回地址的段内偏移量部分。
例 4-14 说明指令 MOV AX,SEG DATA和 MOV SI,OFFSET
DATA的功能。
指令 MOV AX,SEG DATA的功能是把 DATA的段地址存入 AX寄存器中,指令 MOV SI,OFFSET DATA的功能是把 DATA的偏移地址存入 SI寄存器中,等价于指令 LEA SI,DATA。
第 4章 伪指令及汇编语言源程序结构
③ TYPE操作符。
格式,TYPE <变量或标号 >
功能:计算变量的类型值或标号的类型值,即返回一个数字值,它表示存储器操作数的类型部分。
各种存储器地址操作数类型部分的值如下:
第 4章 伪指令及汇编语言源程序结构存储器操作数 类型部分字节数据 1
字数据 2
双字数据 4
长字数据 6
四字数据 8
十字数据 10
NEAR指令单元 - -1
FAR指令单元 -2
第 4章 伪指令及汇编语言源程序结构从此表可看出,用 DB,DW,DD,DF,DQ,DT定义的变量对应的类型值分别为 1,2,4,6,8,10; NEAR,FAR型标号对应的类型值分别为 -1,-2。注意:字节、字、双字、长字、四字和十字的类型部分,分别是它们所占有的字节数,而指令单元的类型部分的值没有实际的物理意义。若 TYPE放在一个结构名前,则返回此结构所占用的字节数。
第 4章 伪指令及汇编语言源程序结构
④ LENGTH和 SIZE操作符只应用于数据存储器地址操作数。
格式,LENGTH <变量 >
功能:返回一个与存储器地址操作数相联系的单元数,对于使用 DUP定义的变量,计算分配给该变量的单元数,其他变量的 LENGTH值为 1。
格式,SIZE <变量 >
功能:返回一个为存储器地址操作数分配的字节数,即计算分配给该变量的字节数,其值为 TYPE和 LENGTH的乘积。
第 4章 伪指令及汇编语言源程序结构例 4-15 若 MULT_WORDS定义为
MULT_WORDS DW 50 DUP(0)
则 LENGTH MULT_WORDS是 50,而 SIZE MULT_WORDS是 100,即
SIZE X= (LENGTH X)× (TYPE X)
(2) 合成操作符由地址部分建立存储器地址操作数,这些操作符是,PTR和 THIS。
第 4章 伪指令及汇编语言源程序结构
① PTR操作符。
格式:类型 PTR 表达式类型可以是 BYTE,WORD,DWORD,NEAR,FAR。
功能:给表达式 (一般是变量或标号 )指定类型,不管它原来有无类型或是什么类型,均以 PTR前的类型为准。对于变量,可以指定的类型是 BYTE(字节 ),WORD(字 ),DWORD(双字 );对于标号,可以指定的类型是 NEAR(段内引用型 ),FAR(段间引用型 )。
PTR操作符建立一个存储器地址操作数,它与其后的存储器地址操作数有相同的段地址偏移量,但有不同的类型。不像一个数据定义语句,PTR操作符并不分配存储器,它可以给已分配的存储器一个另外的意义。
第 4章 伪指令及汇编语言源程序结构例 4-16 若 TWO_BYTE定义为
TWO_BYTE DW?
于是能给 TWO_BYTE的第一个字节定义为
ONE_BYTE EQU BYTE PTR TWO_BYTE
这里,PTR操作符建立了一个与 TWO_BYTE有相同的段和偏移量的新的存储器地址操作数,但它的类型部分是字节。可以给第二个字节定名为
OTHER_BYTE EQU BYTE PTR TWO_BYTE+1
或简单地定义为
OTHER_BYTE EQU ONE_BYTE+1
第 4章 伪指令及汇编语言源程序结构例 4-17 用 PTR操作符建立字和双字。
MANY_BYTES DB 100 DUP(?) ;一个 100个字节的矩阵
FIRST_WORD EQU WORD PTR MANY_BYTES ; 50个字
SECOND_DOUBLE EQU DWORD PTR MANY_BYTES ; 25个双字第 4章 伪指令及汇编语言源程序结构例 4-18 设 INCHES的类型是 NEAR,使用 PTR运算符为 MILES
建立 FAR型的指令单元。
INCHES,CMP SUM,100
JMP INCHES ;段内转移
MILES EQU FAR PTR INCHES ; MILES类型是 FAR
JMP HILES ;段间转移第 4章 伪指令及汇编语言源程序结构
② THIS操作符。像 PTR一样,合成操作符 THIS可用来建立一个特殊类型的存储器地址操作数,而没有为它分配存储器。
新的存储器地址操作数的段和偏移量部分,就是下一个能分配的存储单元的段和偏移量。
格式,THIS <属性或类型 >
功能:将变量或标号定义成指定的类型,但并不分配新的存储单元,其寻址空间与跟在后面的变量的寻址空间相同。对于变量,类型可以是 BYTE,WORD,DWORD,对于标号,类型可以是 NEAR,FAR。
第 4章 伪指令及汇编语言源程序结构例 4-19 定义:
HY_BYTE EQU THIS BYTE
HY_WORD DW?
后,将建立 HY_BYTE具有字节类型,且与 HY_WORD具有相同的段和偏移量部分。在这个例子中,HY_BYTE也可用 PTR操作符建立:
HY_BYTE EQU BYTE PTR HY_WORD
第 4章 伪指令及汇编语言源程序结构也可使用 THIS操作符建立 FAR指令单元:
MILES EQU THIS FAR
CMP SUM,100
JMP MILES
…
第 4章 伪指令及汇编语言源程序结构注意:上例中使用 THIS操作符,并不需要有一个与 MILES
具有相同的段和偏移量的 NEAR指令单元。但若用 PTR操作符代替 THIS这样的 NEAR指令是需要的。
说明:用数据定义伪指令,定义的变量是有类型的。在指令中使用变量作操作数时,要注意其类型与其他操作数的匹配。
第 4章 伪指令及汇编语言源程序结构例 4-20 如果有数据定义伪指令
OPDATA1 DB 23H,4AH
OPDATA2 DW 127FH,25A6H
则如下两条指令是错误的,
MOV BX,OPDATA1 ; BX为字寄存器,OPDATA1为字节变量
MOV AL,OPDATA2 ; AL为字节寄存器,OPDATA2为字变量第 4章 伪指令及汇编语言源程序结构使用合成操作符 PTR,书写成如下形式才是正确的:
MOV BX,WORD PTR OPDATA1 ; BX为字寄存器,OPDATA1为字变量
MOV AL,BYTE PTR OPDATA2 ; AL为字节寄存器,OPDATA2为字节变量指令执行后,BX=4A23H,AL=7FH。
第 4章 伪指令及汇编语言源程序结构
6.操作符及运算符的优先权级的规定操作符及运算符的优先权级按如下顺序,从高到低排列为:
① 圆括号,(记录中使用的 )尖括号、方括号,(结构中使用的 )圆点符,LENGTH,SIZE,WIDTH,MASK。
② PTR,OFFSET,SEG,TYPE,THIS、段寄存器名,(加段前缀 )。
③ *,/,MOD(求模 ),SHL,SHR。
④ HIGH,LOW(操作数高、低字节 )。
第 4章 伪指令及汇编语言源程序结构
⑤ +、-。
⑥ EQ,NE,LT,LE,GT,GE。
⑦ NOT。
⑧ AND。
⑨ OR,XOR。
⑩ SHORT。
当各种运算符同时出现于同一表达式中时,具有不同的优先级。优先级相同的运算符操作顺序为先左后右。
第 4章 伪指令及汇编语言源程序结构
4.3.2 程序结构伪指令语句
1.方式选择伪指令方式选择伪指令又称指令集选择伪指令。这是汇编程序为区分使用的是哪种 CPU执行程序而提供的选择处理器的伪指令。
每种处理器的指令系统都有一个汇编执行语句集合,也就是通常所称的指令集,处理器方式选择伪指令本质上就是指令集选择伪指令。这些指令的一个共同特点是,使用时用一点,,”为引导,程序中放在段外,一般放在程序的开始处,对整个源程序起作用。,586和,586P用于 MASM6.11以上的汇编语言版本,其他的可用于 MASM5.0以上的汇编语言版本。
第 4章 伪指令及汇编语言源程序结构
(1),8086:默认方式,此伪指令可以省略,选择
8086/8088指令集,即汇编程序只接受 8086/8088指令。
(2),286/.286C:选择 80286指令集。,286不包括特权指令,
汇编程序只接受 8086/8088及 80286非保护方式 (即实地址方式 )下的指令,用,8086可删除该伪指令。
(3),286P:选择 80286指令集。,286P包括特权指令,允许汇编程序接受 8086/8088及 80286的所有指令 (包括保护方式和非保护方式下的指令 )。该伪指令一般只有系统程序员使用,并可用,8086伪指令删除。
第 4章 伪指令及汇编语言源程序结构
(4),386/.386C:选择 80386指令集。,386不包括特权指令。允许汇编 8086/8088及非保护方式下的 80286/80386指令。
与,286/.286C类似,在此方式下将禁止所有保护方式下的指令出现,否则将出错。可用,8086删除。
(5),386P:选择 80386指令集。,386P包括特权指令,除具有,386/.386C功能外,还允许汇编保护方式下的 80286/80386
指令。一般只有系统程序员使用,并可用,8086伪指令删除。
(6),8087/.287/.387:分别选择 8087,80287和 80387数字协处理器指令集,并指定实数的二进制码为 IEEE格式。
第 4章 伪指令及汇编语言源程序结构
(7),486/.486P:选择 80486指令集,.486不包括特权指令。与,386/.386C类似,允许汇编 80486非保护方式下的指令。
(8),486P:选择 80486指令集,.486包括特权指令。
与,386P类似,允许汇编 80486的全部指令。
(9),586/.586P:选择 Pentium指令集,不包括特权指令,.586P包括特权指令。
第 4章 伪指令及汇编语言源程序结构
2.逻辑段定义伪指令逻辑段定义的方法有两种:完整段定义和简化段定义。使用 MASM5.0以上的汇编语言版本中,既可定义完整段,也可定义简化段;在低于 MASM5.0的版本中,只能定义完整段。
1) 完整段定义伪指令采用完整段定义伪指令可具体控制汇编程序 (MASM)和连接程序 (LINK)在内存中组织代码和数据的方式。它包括 3种伪指令语句:
第 4章 伪指令及汇编语言源程序结构
(1) 段定义语句 (SEGMENT/END)。
格式:段名 SEGMENT [定位类型 ][组合类型 ] [‘类别 ’ ]
[属性类型 ]
(段体 )
段名 ENDS
功能:指出段名及段的各种属性,并表示段的开始和结束位置 (地址 )。
说明:段名是用户定义的段的标识符,用于指明段的基址。
SEGMENT后面有 4个可选参数,分别代表段的 4种属性。
…
…
第 4章 伪指令及汇编语言源程序结构
① 定位类型用于规定段的起始地址要求,即指定该段起点的边界类型,有 5种可选类型,默认方式为 PARA。
PARA(节 ):段起始地址从段边界开始 (必为 16的倍数 ),段起始单元 20位地址的最低 4位二进制位必为 0。
BYTE(字节 ):段起始地址从字节边界开始,即该段可以从任何单元开始。
WORD(字 ):段起始地址从字边界开始 (必为偶数 ),段起始单元 20位地址的最低 1位二进制位必为 0。
第 4章 伪指令及汇编语言源程序结构
DWORD(双节 ):段起始地址从双字边界开始 (必为 4的倍数 ),
段起始单元 20位地址的最低 2位二进制位必为 0,一般用于
80386的 32位段中。
PAGE(页 ):段起始地址从页边界开始 (必为 256的倍数 ),
段起始单元 20位地址的最低 8位二进制位必为 0。
第 4章 伪指令及汇编语言源程序结构
② 组合类型用于告诉 LINK程序本段与其他模块中同名段的组合连接关系,有五种可选组合类型:
PUBLIC,LINK程序将不同模块中具有该类型且段名相同的段连接到同一个物理段中,使它们公用一个段地址。
STACK:与 PUBLIC同样处理,只是连接后的段为堆栈段。
LINK程序在连接过程中自动将新段的段地址送到 SS段寄存器,
新段的长度送到 SP寄存器中。如果在定义堆栈段时没有将其说明为 STACK类型,那么就需要在程序中用指令设置 SS和 SP寄存器的值,此时 LINK程序将会给出一个警告信息。
第 4章 伪指令及汇编语言源程序结构
COMMON:产生一个覆盖段。 LINK程序为该类型的同名段指定相同的段地址。段的长度取决于最长的 COMMON段的长度。段的内容为所连接的最后一个模块中的内容及其没有覆盖到的前面 COMMON段的部分内容。
MEMORY,LINK程序不单独区分 MEMORY类型,它把 MEMORY与
PUBLIC类型同等对待。 MASM程序允许使用它主要是为了与其他支持 Intel MEMORY类型的连接程序兼容。
第 4章 伪指令及汇编语言源程序结构
AT表达式,LINK程序将具有 AT类型的段装在表达式值所指定的段地址边界上。这个类型可以为标号或变量赋予绝对地址,
以便程序以标号或变量的形式存取这些存储单元的内容。一般在 AT类型的段中不定义指令或数据,只说明一个地址结构。
第 4章 伪指令及汇编语言源程序结构例 4-21
STUEF SEGMENT AT 0 ;段地址为 0
ORG,410H ;偏移地址为 410H
EQUIPMENT LABEL WORD ;标号 EQUIPMENT的绝对地址为 0000,0410
STUEF ENDS
在保护方式中,AT类型无意义。
若此属性缺省,表示段是独立的,不与其他同名段发生联系,并有自己的段起始地址。
第 4章 伪指令及汇编语言源程序结构
③ 属性类型选择用于定义段中使用的偏移地址和寄存器的字长。该选择只用于设置含有,386和,486语句的段。有两种属性类型可供选择:
USE16—— 选择 16位段,按 16位方式寻址,最大段长为 64 KB。
USE32—— 选择 32位段,按 32位方式寻址,最大段长可达 4 GB。
如果属性类型选择缺省,则在使用,386/.486伪指令时默认为 USE32。
第 4章 伪指令及汇编语言源程序结构
④ ‘类别 ’ 用于控制段的存放次序。它可以是任何合法的名称,但必须用单引号括起来。 LINK程序只使同类别段发生关系,并将它们存放在连续的存储空间中。若 ‘ 类别 ’ 选择项缺省,则表明该段类别为空。
第 4章 伪指令及汇编语言源程序结构
(2) 段寄存器说明语句 (ASSUME)。
格式,ASSUME 段寄存器:段名 /组名 [,段寄存器:段名 /
组名,… ]
功能:说明源程序中定义的段或组由哪个段寄存器去寻址,
它指出了段与段寄存器的关系,并确定某个段分配给哪个段寄存器,以便汇编程序知道段的结构和在执行各种指令时知道应访问哪一个段。段寄存器可以是 CS,SS,DS,ES,FS或 GS。
第 4章 伪指令及汇编语言源程序结构说明:段寄存器 CS只能用于包含有程序的段,反之,含有程序的段也只能以 CS作段寄存器。 SS只能与堆栈段对应。 CS所对应的段名必须在该语句之前有定义,因此,ASSUME语句一般都设置于代码段内,放在段定义语句之后,是说明性语句。
除主程序的代码段及最后一个堆栈段之外,其余段寄存器的初值均由用户在程序中设置的参数,NOTHING”表示取消以前指定的段寄存器。如果各段寄存器的指定都取消,则可写成如下形式:
ASSUME NOTHING
第 4章 伪指令及汇编语言源程序结构例 4-22 3个数相加并把结果存放在 SUM单元中,用完整段定义结构的程序。
DATA SEGMENT ;段定义开始
BUF DB 35H,78H,0A5H ;定义数据
SUM DB? ;定义存放累加和的单元
DATA ENDS ;段定义结束
CODE SEGMENT ;段定义开始
ASSUME CS∶CODE,DS∶DATA ;规定段的性质
START,MOV AX,DATA
MOV DS,AX ;设置 DS的值第 4章 伪指令及汇编语言源程序结构
MOV AL,0 ;累加器清 0
MOV SI,OFFSET BUF ; BUF首地址送 SI
ADD AL,[SI] ;累加第 1个数
INC SI ;地址指针增 1
ADD AL,[SI] ;累加第 2个数
INC SI ;地址指针增 1
ADD AL,[SI] ;累加第 3个数
MOV SUM,AL ;存储累加和
MOV AH,4CH
INT 21H ;返回 DOS
CODE ENDS ;段定义结束
END START ;源程序结束第 4章 伪指令及汇编语言源程序结构
(3) 组定义语句 (GROUP)
格式:组名 GROUP段名 [,段名,… ]
功能:将 GROUP定义符后指定的所有段分配在一个 64 KB的物理段中,并赋予该段一个名字 —— 组名。
说明:组名是用户定义的名字,是指出组的始地址的一种符号,必须是惟一的,不能与任何标号、段名及变量等同名。
段名可以是用 SEGMENT语句定义的或者由 SEG运算符得到的。
第 4章 伪指令及汇编语言源程序结构组定义语句不影响各段的次序,因此组内各段不一定连续存放,但它们都必须包含在 64 KB中。如果组名在语句中已说明,
且相应段寄存器 (DS,ES,FS或 GS)有初始化语句,则系统把所有组内各段中的变量或标号的偏移地址调整为相对于组的起始地址。但是属性常数,变量,没有调整,它还是相对于段始址的偏移值。需要相对于组名地址的偏移值时,可用:
OFFSET组名:变量 ;组名在这里相当于段前缀该语句可使定义在源程序中不同类型的段运行时共用同一个段寄存器,但这些段仍为独立的段。这与 SET语句中的 PUBLIC
组合类型不同,PUBLIC组合类型是将同名段组合成为一个段。
第 4章 伪指令及汇编语言源程序结构
2) 简化段定义伪指令简化段有利于实现汇编语言程序模块与 Microsoft高级语言程序模块的连接,它可以由操作系统自动安排段序,自动保证名字定义的一致性。但是命令文件 (.COM)的编程不可使用简化段定义。
(1) 段次序语句 (DOSSEG)。
格式,DOSSEG
功能:各段在内存的顺序按 DOS段次序约定排列。
说明:各段在内存的次序决定于很多因素,多数程序对段次序无明确要求,可由操作系统安排。本语句用于主模块前面,
其他模块不必使用。
第 4章 伪指令及汇编语言源程序结构
(2) 内存模式语句 (.MODEL)。
格式,.MODEL 模式类型 [,高级语言 ]
功能:指定数据和代码允许使用的长度。
说明,[高级语言 ]是可选项,可使用 C,BASIC,FORTRAN、
PASCAL,SYSCALL,STDCALL等关键字来指定和哪种高级程序设计语言接口,还可用关键字 OS_OS2或 OS_DOS告诉使用的是哪种操作系统。程序中凡数据或代码的长度不大于 64 KB时为近程,
否则为远程。近程的数据通常定义在一个段中,对应一个物理段,只要程序一开始设置其段值于 DS中,以后数据的访问只改变偏移值,不改变段值。
第 4章 伪指令及汇编语言源程序结构本语句一般放在用户程序中其他简化段定义语句前。可选内存模式有 5类:
SMALL:小模式。数据、代码各放入一个物理段中,均为近程。
MEDIUM:中模式。数据为近程,代码允许为远程。
COMPACT:压缩模式。代码为近程,数据允许为远程,但任一个数据段所占内存不可超过 64 KB。
第 4章 伪指令及汇编语言源程序结构
LARGE:大模式。数据与代码均允许为远程。但任一个数据段不可超过 64 KB。
HUGE:巨型模式。数据与代码均允许为远程,且数据语句所占内存也可大于 64 KB。
当独立的汇编语言源程序不与高级语言程序连接时,多数情况下只用小模式即可,而且小模式的效率也最高。
第 4章 伪指令及汇编语言源程序结构
(3) 段语句。简化段定义的段语句有以下几种:
① 代码段语句。
格式,.CODE [名字 ]
功能:定义一个代码段。如有多个代码段,要用名字区别。
② 堆栈段语句。
格式,.STACK[长度 ]
功能:定义一个堆栈段,并形成 SS及 SP初值。 (SP)=长度,
如省略长度,则 (SP)= 1024。
第 4章 伪指令及汇编语言源程序结构
③ 初始化近程数据段语句。
格式,.DATA
功能:定义一个近程数据段。当用于与高级语言程序连接时,其数据空间要赋初值。
④ 非初始化近程数据段语句。
格式,.DATA?
功能:定义一个近程数据段。当用于与高级语言程序连接时,其数据空间只能用,?”定义,表示不赋初值。
第 4章 伪指令及汇编语言源程序结构
⑤ 常数段语句。
格式,.CONST
功能:定义一个常数段。该段是近程的,用于与高级语言程序连接。段中数据不能改变。
⑥ 初始化远程数据段语句。
格式,.FARDATA [名字 ]
功能:定义一个远程数据段,且其数据语句的数值应赋初值。用于与高级语言程序连用。
第 4章 伪指令及汇编语言源程序结构
⑦ 非初始化远程数据段语句。
格式,.FARDATA? [名字 ]
功能:定义一个远程数据段,但其数据空间不赋初值,只能用,?”定义数值。用于高级语言程序连用。
第 4章 伪指令及汇编语言源程序结构例 4-23 三个数相加并把结果存放在 SUM单元中,用简化段定义结构程序。
.MODEL SMALL ;选用小模式
.DATA ;数据段定义
BUF DB 35H,78H,0A5H ;定义数据
SUM DB? ;定义存放累加和的单元
.CODE ;代码段定义
MOV AX,@DATA ;数据段段名为 @DATA
MOV DS,AX ;设置 DS值第 4章 伪指令及汇编语言源程序结构
MOV AL,0 ;累加器清 0
MOV SI,OFFSET BUF ; BUF首地址送 SI
ADD AL,[SI] ;累加第 1个数
INC SI ;地址指针增 1
ADD AL,[SI] ;累加第 2个数
INC SI ;地址指针增 1
ADD AL,[SI] ;累加第 3个数
MOV SUM,AL ;存储累加和
MOV AH,4CH
INT 21H ;返回 DOS
END ;源程序结束第 4章 伪指令及汇编语言源程序结构对于简化段定义需要说明的是:
① 凡是与高级语言程序连接的数据,必须把常数与变量分开,变量中又要把赋初值的与不赋初值的分开,并分别定义在,CONST,.DATA/FARDATA和,DATA? /.FARDATA?中。远程数据段只能在压缩模式、大模式和巨型模式中使用,其他数据段和代码段可在任何模式下使用。
② 不与高级语言连接的源程序独立的汇编语言源程序只用前述的 DOSSEG,.MODEL,.CODE,.STACK和,DATA 5种简化语句,
并且不区分常数与变量以及赋初值与不赋初值。在,DATA语句定义的段中,所有数据语句均可使用。其一般格式如下:
第 4章 伪指令及汇编语言源程序结构
DOSSEG
.MODEL
.STACK [长度 ]
.DATA
数据语句
.CODE
启动标号:
MOV AX,DGROUP ;或 MOV AX,@DATA
MOV DS,AX
执行性语句
END启动标号
…
…
…
…
第 4章 伪指令及汇编语言源程序结构这种简化段的源程序结构中只有一个堆栈段、一个数据段和一个代码段。代码段长度可达 64 KB,数据段与堆栈段为一个组,其总长度可达 64 KB,组名为 DGROUP。组名 DGROUP与数据段名 @DATA都代表组对应物理段的段界地址。装入内存时,系统给
CS和 IP赋初值,使其指向代码段,同时系统还给 SS和 SP赋初值,
使 (SS)= DGROUP,(SP)=数据段长度+堆栈段长度,从而使堆栈段为对应的物理段。这样处理是使堆栈元素也能用 DS寄存器访问,以便同高级语言程序连接。在代码段开始运行处 (启动标号处 ),用户应设置 DS指向组的段界地址。
第 4章 伪指令及汇编语言源程序结构
3.指定地址伪指令 (ORG)
格式,ORG偏移地址
ORG $+偏移地址功能:以其指定的偏移地址或由 $给出的当前地址加上指定的偏移地址作为当前开始分配和使用的偏移地址。
说明:该伪指令语句不占内存,它指定下一个占内存语句的偏移地址。偏移地址可写成表达式形式,但其取值范围在
0~ 65 535之间,通常不必使用该语句,只在需要指定存储空间或保留一段存储空间时才使用它。该语句不能使用标号,否则语句无效。
第 4章 伪指令及汇编语言源程序结构
4.模块定义伪指令一个可执行的汇编源程序可由多个模块组成,每个模块是一个独立的汇编单位。在操作系统中,汇编源程序是一个 *.ASM
源文件。汇编源程序的模块与汇编源文件是一一对应的。
1) 模块开始语句 (NAME)
格式,NAME[模块名 ]
功能:表示源程序开始并指出模块名。
说明:该语句一般可省略。省略时,模块名取源程序中
TITLE语句之页标题的前 6个字符。若没有 TITLE语句,则取该模块的源程序文件名为模块名。
第 4章 伪指令及汇编语言源程序结构
2) 模块结束语句 (END)
格式,END[标号 /过程名 ]
功能:模块结束语句表示源程序到此结束,并可指出程序的启动地址。
说明:一个源程序必须有且只能有一个 END语句来指出源程序文件的结束。方括号中的标号或过程名是可选项,只有主模块才具有该项,其作用是指出该程序的第一条可执行指令的位置,系统将给 CS,IP赋初值。
第 4章 伪指令及汇编语言源程序结构
5.模块连接伪指令
1) 全局符说明语句 (PUBLIC)
格式,PUBLIC 符号名 1[,符号名 2,… ]
功能:将本文件中定义的符号名说明为全局符号,允许程序中其他模块使用。
说明:该语句中的符号名可以是标号、变量名、过程名或由
EQU(或= )伪指令定义的名字。这些符号名必须是在当前源程序中定义的,其他模块不能再用它们去定义别的内容。未被说明的符号名不能被其他模块引用。
需要注意的是,PUBLIC伪指令与 SEGMENT伪指令中的 PUBLIC
组合类型是两个不同的概念。
第 4章 伪指令及汇编语言源程序结构
2) 外部符说明语句 (EXTRN)
格式,EXTRN 符号名 1:类型 [,符号名 2:类型,… ]
功能:该语句中指定的符号名是在其他模块中用 PUBLIC伪指令语句定义过的。类型可以是 NEAR,FAR,BYTE,WORD,DWORD、
FWORD,QWORD,TBYTE或 ABS(由 EQU伪指令定义的常数符 ),具体类型必须与其他模块中定义的相同符号名的类型相一致。
说明:当前模块要引用其他模块中定义的符号名时,必须用
EXTRN伪指令说明,如果当前模块中没有用 EXTRN伪指令说明,或者在被引用模块中没有用 PUBLIC伪指令说明,均不能引用,否则
LINK程序将会产生一个错误信息。可见,EXTRN伪指令和 PUBLIC伪指令是互相对应的。
第 4章 伪指令及汇编语言源程序结构
3) 包含语句 (INCLUDE)
格式,INCLUDE 文件名功能:将指定文件的内容完整地插入到本语句出现的位置。
说明:使用本伪指令语句可避免重复书写多个模块都要使用的相同程序块。当汇编某一源程序文件时,若遇到 INCLUDE伪指令,就按文件说明打开磁盘上存在的相应文件,并将它插入到当前文件的该 INCLUDE伪指令处,然后汇编插入进来的文件中的语句。当该文件中的所有语句处理完后,MASM继续处理当前文件中 INCLUDE语句后面的语句。
汇编语言程序设计时,常用 INCLUDE伪指令语句将一个标准的宏定义插入到程序中。
第 4章 伪指令及汇编语言源程序结构
4) 公用符号说明语句 (COMM)
格式,COMM [NEAR/FAR] 符号名:尺寸 [:元素数 ],…
功能:将语句中的符号名说明为公用符号。公用符号既是全局的又是外部非初始化的。
NEAR/FAR语句中的符号名可以是近程 (NEAR)或远程 (FAR)数据段的符号,NEAR/FAR缺省时,在完整段和简化段的中、小模式下为 NEAR,其他模式下为 FAR。尺寸可以是 BYTE,WORD、
DWORD,DWORD,QWORD及 TBYTE。元素数为符号的个数,缺省值为 1。一条语句中可说明多个公用符号,多个符号间用逗号隔开。
该伪指令语句经常用在 INCLUDE文件中。如果一个变量用于多个模块中,可以在 INCLUDE文件中将它说明为公用变量,然后在每一个模块中都用 INCLUDE指令嵌入这个 INCLUDE文件。
第 4章 伪指令及汇编语言源程序结构例 4-24
.DATA
COMM NEAR NBUFFER,BYTE,20 ;在近程数据段中定义一个 20字节的公用缓存区
.FARDATA
COMM FAR FBUFFER,DWORD,12 ;远程数据段中定义一个 12双字的公用缓存区第 4章 伪指令及汇编语言源程序结构
4.3.3 过程定义伪指令语句汇编语言中常用定义过程来实现按模块管理程序代码的功能,因此过程是进行模块化程序设计的基础。过程是程序的一部分,它们可被程序调用。每次可调用一个过程,当过程中的指令执行完后,控制返回调用它的地方。 80x86中调用过程指令是 CALL,从过程返回的指令是 RET。这两条指令分为:段内的和段间的指令两种情况。段间的指令把过程应返回的地址的段地址和偏移量两者同时入栈 (CALL)和退栈 (RET)。段内的调用与返回指令只入栈和退栈地址偏移量。过程相当于高级语言程序中的子程序,常用于代替完成特定任务的代码模块。
第 4章 伪指令及汇编语言源程序结构过程定义包含两条伪指令,PROC和 ENDP。 PROC表示过程的开始,ENDP表示过程的结束。过程定义语句的格式为过程名 PROC [属性 ] ;过程开始;过程体
[RET]
RET
过程名 ENDP ;过程结束功能:定义一个过程 (子程序 )。
…
…
第 4章 伪指令及汇编语言源程序结构伪指令 PROC与 ENOP必须成对出现,ENDP指示过程结束,但它不会产生 HLT或 RET指令。利用过程定义语句可以把程序分段,
便于理解、调试和修改。若整个程序由主程序和若干子程序组成,则主程序和这些子程序都应包含在代码段中,而主程序及子程序都可以作为一个过程,用过程定义语句定义。
过程定义语句 PROC和 ENDP限定一个过程,并说明它是 NEAR
或 FAR过程。汇编程序根据过程定义语句,当汇编到 CALL过程时,
知道汇编的是什么样的过程调用,当汇编到从这个过程返回时,
知道是什么样的返回。
第 4章 伪指令及汇编语言源程序结构例 4-25
MY_CODE SEGMENT
UP_COUNT PROC NEAR
ADD CX,1
RET
UP_COUNT ENDP
START:
CALL UP_COUNT
HLT
MY_CODE ENDS
END START
…
…
第 4章 伪指令及汇编语言源程序结构因为 UP_COUNT标明是 NEAR过程,所以对它的调用,都汇编成段内调用,所有在它之中的 RET指令,都汇编为段内返回。
说明:
① 过程名是过程的标识符 (也可视为标号,当标号处理 )。
② 过程的属性可以是 FAR或 NEAR类型。 NEAR为近,即可在段内调用。 FAR类型为远,可跨段调用,缺省时为 NEAR。如果使用简化段指令,则不需要用 FAR指定类型,这时过程的类型是由,MODEL伪指令决定的。
第 4章 伪指令及汇编语言源程序结构
③ RET为返回指令,是过程的出口点,但不一定是过程的最后一条指令。一个过程可以有多个 RET指令,但至少要执行到一个 RET指令。
④ 过程可以嵌套,嵌套的深度 (层数 )只受堆栈的限制,
过程和段也可以嵌套,但不能交叉覆盖。
第 4章 伪指令及汇编语言源程序结构例 4-26 下面程序段定义了两个子程序 P1和 P2,其中 P1又调用了 P2。
P1 PROC ;定义过程 P1
CALL P2 ;过程嵌套
RET
P1 ENDP
P2 PROC ;定义过程 P2
RET
P2 ENDP
…
…
第 4章 伪指令及汇编语言源程序结构
4.3.4 列表伪指令语句汇编程序在对源程序进行汇编时,除可产生目标代码程序
(.OBJ)外,还可产生一个列表文件 (.LST)和一个交叉参考列表文件 (.CRE),它们都是能被显示或打印的文件,其中列表文件以源程序指令与其相应目标程序指令相对照形式给出汇编结果并随后给出程序中所用符号 (标号、变量名等 )的符号表;交叉参考列表文件按字母顺序列出源程序中所用的符号清单及其使用情况,并给出它们在程序中使用的行号。这两种文件便于程序调试。列表伪指令就是用来控制上述两种文件的输出格式和方式的。
第 4章 伪指令及汇编语言源程序结构
1.显示汇编信息语句格式,% OUT 信息功能:汇编时,将该伪指令语句给出的信息在屏幕上显示。
说明:,信息,可以是任意的 ASCII码字符串。若要显示多行信息,每行开头都要使用本语句。
第 4章 伪指令及汇编语言源程序结构
2.控制列表文件显示的页格式
1) TITLE
格式,TITLE 标题功能:指定列表文件每页的标题。
说明:,标题,可以是长度在 80个字符内的字符串。若无本语句,则标题为空。
第 4章 伪指令及汇编语言源程序结构
2) SUBTYL
格式,SUBTYL 子标题功能:指定列表文件每页的子标题。
说明:,子标题,可以是长度在 60个字符内的字符串。若无本语句或虽有但未给出子标题,则子标题为空。
第 4章 伪指令及汇编语言源程序结构
3) PAGE
格式,PAGE ([行数 ],[列数 ])
功能:控制列表文件的分页及每页的行列数。
说明:行数范围在 10~ 255之间,默认值为 58行;列数范围在
60~ 132之间,默认值为 80列。若没选行、列数这两个参数,
则使打印机换页,走纸到下页的顶端,页号加 1,并打印新页的标题、子标题及文件的其余部分。
第 4章 伪指令及汇编语言源程序结构
4) PAGE
格式,PAGE+
功能:控制换页并开始新的一节,且使节号加 1,页号重置为 1。
说明:节数是对整个文件而言,而页号则是在节中的页数。
第 4章 伪指令及汇编语言源程序结构
3.控制列表文件输出内容
1) LIST
格式,.LIST
功能:控制列表的开始。
2) XLIST
格式,.XLIST
功能:控制列表的结束。
说明,LIST和 XLIST一般成对出现,用来选择或禁止源程序中某些行的输出。
第 4章 伪指令及汇编语言源程序结构
3) LFCOND
格式,.LFCOND
功能:允许其后条件 1为假的条件块被列表。
4) SFCOND
格式,.SFCOND
功能:禁止其后条件为假的条件块被列表。
说明,LFCOND和 SFCOND一般成对出现,用于限制程序中条件块的列表输出。
第 4章 伪指令及汇编语言源程序结构
5) TFCOND
格式,.TFCOND
功能:改变对条件为假的条件块的现行列表状态,即原来列表改为不列表,原来不列表改为列表。
说明:其控制条件块列表的状态正好与 LFCOND和 SFCOND相反。
6) LALL
格式,.LALL
功能:将宏展开中的所有内容列表输出。
第 4章 伪指令及汇编语言源程序结构
7) SALL
格式,.SALL
功能:对所有的宏展开内容均不列表输出。
8) XALL
格式,.XALL
功能:只将宏展开中产生数据或目标代码的语句列表输出。
说明,LALL,SALL和 XALL用于控制宏展开的内容是否包含在列表文件中。
第 4章 伪指令及汇编语言源程序结构
4.控制交叉参考列表文件的输出
1) CREF
格式,.CREF
2) XCREF
格式,.XCREF
功能:这两条语句的功能是:控制交叉参考信息 (以字母顺序排列的符号、变量、标号的清单及其使用情况 )是否列在交叉参考列表文件 (.CRF)中。
说明,CREF恢复在,CRF文件中产生交叉参考信息。汇编程序默认的状态是,CREF; XCREF禁止在,CRF文件中产生交叉参考信息。
第 4章 伪指令及汇编语言源程序结构
4.4 标号、变量和表达式
4.4.1 标号标号在程序中是一个代表逻辑地址的名字。定义一个标号后,也相应定义了标号的四个属性:段属性,USE属性、标段偏移地址和标号类型。标号有两种类型,NEAR和 FAR。汇编语言预定义的标号有位置计数器,用 $代表。位置计数器的值是正在汇编的位置在当前段内的偏移量。 $一般作为指令或表达式的操作数。有两条伪指令控制位置计数器,ORG和 EVEN。
第 4章 伪指令及汇编语言源程序结构
1,ORG伪指令
ORG伪指令用来置位置计数器的值。因此,也包括代码的起始地址。一个 ORG表达式把代码或数据定位于当前段指定的偏移地址处。 ORG伪指令的格式如下:
ORG EXP
其中,EXP是一个常量表达式或一个标号。在 USE32段中,EXP
的值以 232-1为模,在 USE16段中,EXP的值是以 65 536为模。
第 4章 伪指令及汇编语言源程序结构例 4-27
ORG 100H ;把位置计数器定位于 100H处
ORG OFFSET($+1000)
ORG OFFSET($-1000)
第 4章 伪指令及汇编语言源程序结构
2,EVEN伪指令
EVEN伪指令保证代码或数据序列是以 DWORD或 WORD对界。
其格式如下:
EVEN
当程序汇编时遇到 EVEN伪指令,汇编系统就在代码或数据序列中加多达三个 NOP指令 (90H)。若是 USE32段则按最近的 DWORD对界,若是 USE16段则按 WORD对界。
第 4章 伪指令及汇编语言源程序结构
3,LABEL伪指令
LABEL伪指令在当前汇编的位置上建立一个名字,不管这个位置是数据还是代码。其格式如下:
NAME LABEL TYPE
其中,NAME是一个标识符; TYPE是 NEAR或 FAR,或一个变量类型
(BIT,BYFE,WORD,DWORD,PWORD,QWORD或 TBYTE)、一个标号名、一个记录名或一个结构名。标号、记录名、结构名不能超前引用,在此之前应定义过。利用 LABEL可以把一个 FAR标号定义成一个 NEAR标号别名。然而相反类型的别名标号只能作为 JMP或条件转移指令的操作数。如果子程序需要返回,用 CALL指令调用同一个子程序时,只能是同一类型的标号,不能又用 FAR标号,又用其别名后的 NEAR标号。子程序中的 RET指令要么是 NEAR,要么是 FAR,不能二者兼具。
第 4章 伪指令及汇编语言源程序结构例 4-28 LOWBYTE和 HIGHBYTE是两个相邻的 BYTE类型变量,
可以利用 LABEL伪指令把它们定义为一个 WORD类型的变量 AWORD。
这样,我们就可以用变量 AWORD来访问这两个相邻的单元了。
AWORD LABEL WORD
LOWBYTE DB 0
HIGHBYTE DB 0
第 4章 伪指令及汇编语言源程序结构例 4-29 在同一数据区域建立了三种访问方式。
BIT_ARRAY,TBYTE_AR_RAY和 WORD_ARRAY,都对应同一数据区
BYTE_ARRAY。
BYTE_RECORD RECORD B7,1,B6,1,B5,1,B4,1,
B3,1,B2,1,B1,1,B0,1
BIT_ARRAY LABEL BYTE_RECORD
TBYTE_ARRAY LABEL TBYTE
WORD_ARRAY LABEL WORD
BYTE_ARRAY DB 100 DUP(0)
第 4章 伪指令及汇编语言源程序结构
4.4.2 标号和变量
1.标号和变量程序中标号和变量都定义了一个逻辑地址。标号定义一个当前段的段内偏移地址,或者定义一个不在当前段的其他段的段选择符及其段内偏移地址。变量也定义一个地址,该地址存储单元的内容 (数据的值 )可以通过变量名来引用。
标号和变量都有自己的类型,每个汇编语言标号都具有以下两种类型之一:
(1) NEAR:指出标号代表的逻辑地址是一个偏移地址,
NEAR是汇编语言的缺省标号类型;
(2) FAR:指出标号代表的逻辑地址是一个段选择符和一个偏移量。
第 4章 伪指令及汇编语言源程序结构每个汇编语言变量的类型必须在定义该变量时给出,以分配一定的存储空间。变量的类型可以是简单类型,或是复合类型。复合类型由一种或多种简单类型构成。
变量的简单类型有以下几种,在汇编语言中的保留字分别为:
(1) bit 虽然定义为位,但分配 1个字节的存储空间;
(2) BYTE 为变量分配 8位存储空间;
(3) WORD 为变量分配 16位存储空间;
第 4章 伪指令及汇编语言源程序结构
(4) DWORD 为变量分配 32位存储空间;
(5) PWORD 为变量分配 48位存储空间;
(6) QWORD 为变量分配 64位存储空间;
(7) TBYTE 为变量分配 80位存储空间。
复合类型的变量是一个记录或结构。记录和结构是程序员定义的类型。可以利用记录和结构存储分配语句来定义这些类型的变量。
第 4章 伪指令及汇编语言源程序结构
2.符号数据的使用汇编程序中的标号和变量名是符号数据,所有程序定义的标识符都是符号数据,关键字和保留字也可作为符号。
用 EQU伪指令为符号另起一个新名字。用 PURGE伪指令告知汇编系统,忽略目标文件信息中的用 EQU定义的符号和程序员定义的符号。
第 4章 伪指令及汇编语言源程序结构
1) EQU伪指令格式,NAME EQU VALUE
其中,NAME是一个汇编语言标识符 VALUE赋给 NAME的值。
功能:为一个标识符赋一个值,也可为一个符号值建一个别名,或为一个汇编时的常量或运行时的表达式值建立一个标识符。
说明:给标识符赋的值可以是下列之一:变量名、标号名、
变量或寄存器表达式、一个寄存器、一个浮点栈元素、一个助记符或指令前缀、一个宏调用或前缀、操作符 NOT,AND,OR、
XOR,SHL或 SHR。 VALUE可以是任何地址表达式。
第 4章 伪指令及汇编语言源程序结构例 4-30 标号 ALAB代表的值可被 EQU超前引用。
ALABEL EQU ALAB
ALAB,MOV EAX,0
第 4章 伪指令及汇编语言源程序结构例 4-31 用 EQU为 80386寄存器定义一个别名。
COUNT EQU ECX
PNTR EQU EBX
MOV COUNT,10 ; ECX= 10
MOV PNTR,OFFSET ARRAY ; EBX= ARRAY的偏移地址第 4章 伪指令及汇编语言源程序结构例 4-32 为指令 MOV和 INC定义一个别名。
DATAMOVE EQU MOV
INCREMENT EQU INC
DATAMOVE EAX,EBX ;此语句即 MOV EAX,EBX
INCREMENT EAX ;此语句即 INCEAX
第 4章 伪指令及汇编语言源程序结构例 4-33 用 EQU赋常量。
TDTAL EQU 6
PI EQU 3.141592653589793
DD PI ;单精度
DQ PI ;双精度
DEG_TO_RAD EQU 3FF98EFA351294E9C8AEF ; PI/180
DT DEG_TO_RAD ;扩展精度第 4章 伪指令及汇编语言源程序结构例 4-34 此例说明汇编时的初始化赋值。
E1 EQU 2+3
E2 EQU E1 AND 4
E2 EQU (E1-E2)/12
第 4章 伪指令及汇编语言源程序结构例 4-35 用 EQU定义在堆栈中存取的变量。
STKWRD EQU WORDPTR[EBP+2]
ONEVAR EQU SS∶[EBX+3]
TWOVAR EQU SS∶[EBX]
第 4章 伪指令及汇编语言源程序结构
2) PURGE伪指令格式,PURGE NAME,[,… ]
其中,NAME是一个符号数据标识符。
功能:删除已定义的一个或多个符号。使用 EQU定义的标号、变量和关键字或寄存器别名都可用 PURGE删除。
说明,PURGE不能删除的符号有下面几种:说明为 PUBLIC
的名字、寄存器名、保留字。
第 4章 伪指令及汇编语言源程序结构例 4-36 删除用 EQU定义的指令和寄存器别名
DATAMOVE EQU MOV
COUNT EQU ECX
PURGE DATAMOVE,COUNT
…
第 4章 伪指令及汇编语言源程序结构例 4-37 在程序 END语句前的 PURGE语句,使汇编系统从目标文件中省略掉被 PURGE删掉的符号。
PURGE ALABEL,VAR1
END ;模块结束第 4章 伪指令及汇编语言源程序结构
4.4.3 汇编语言表达式表达式包括操作数和操作符,它可以是一个初始化数据的值或是一个存储器地址。一条汇编语言的指令对数据操作时,
该数据必须是作为该指令的一个操作数。一些指令有隐含的操作数,如寄存器。但是,大多数指令有明显的操作数。一条指令的操作数可以用下述形式表示:一个寄存器、一个常量、一个存储器地址或这些的组合。一些操作数可以用表达式来表示,
这包括一系列的变量名、基址和变址寄存器及用操作符连在一起的常量,例如,一个寄存器内容和一个常量可用操作符加在一起。
第 4章 伪指令及汇编语言源程序结构
1.常量表达式大多数的操作符都可用于常量,使常量成为一个表达式中的操作数。在存储分配伪指令中,可使用常量表达式初始化变量值。在汇编时,由其他模块定义的符号常量的值是不知道的。
例 4-38
EXTRN ANUMBER,ABS
DATA SEGMENT
AWORD DW ANUMBER ;当模块连接时 AWORD得到 ANUMBER的值
DATA ENDS
第 4章 伪指令及汇编语言源程序结构
2.地址表达式一个地址表达式定义一个存储器的存储单元位置,这个位置可用变量或标号表示。每一个地址表达式都是一个简单类型。
1) 变量名和标号名作为地址表达式最简单的地址表达式就是一个变量的名字或一个标号的名字。在这种情况下,该名字意味着寻址使用的是变量或标号在所定义的段中相对段基地址的偏移地址。这个地址是可重定位的。
第 4章 伪指令及汇编语言源程序结构例 4-39
ADD DX,COUNT ; COUNT是一个简单的地址表达式或是一个变量
ADD DX,COUNT+2 ;在这种情况下,地址表达式具有与 COUNT同样的段和类型;只是偏移值大于 2
第 4章 伪指令及汇编语言源程序结构
2) 寄存器表达式格式:
[BASE_REG] 或 [INDEX_REG * SCALE]
[BASE_REG+INDEX_REG * SCALE]
[BASE_REG+DISP] 或 [INDEX_REG * SCALE+DISP]
[BASE_REG+INDEX_REG * SCALE+DISP]
第 4章 伪指令及汇编语言源程序结构其中,BASE_REG是任何用于 32位寻址的 32位通用寄存器,以及
16位寻址的 BX或 BP; INDEX_REG是除 ESP外的任何 32位寻址的 32
位通用寄存器,以及用于 16位寻址的 SI或 DI; SCALE是一个可选的常量或常量表达式,其值是 1,2,4或 8,只用于 32位寻址,
不能用于 16位寻址; DISP在 32位寻址时是一个 8位或 32位的偏移,
16位寻址时是 8位或 16位的偏移。
一个寄存器表达式是一个使用基址和变址寄存器或基址或变址寄存器的地址表达式。
第 4章 伪指令及汇编语言源程序结构例 4-40
MOV CX,[BX] ;把 BX所指的 WORD类型数据送到 CX
例 4-41
MOV WORD PTR[DI],5 ;把 5赋于 2个字节
INC BYTE PTR[BX]+2 ; 1个字节单元增 1
第 4章 伪指令及汇编语言源程序结构
3) 简单地址表达式和寄存器表达式的组合格式,VARNAME[REG_EXP]
其中,VARNAME是一个变量名,REG_EXP是一个寄存器表达式,写在一对方括号内。实际形成的地址为变量的偏移地址与寄存器内容之和。
寄存器表达式与简单地址表达式组合,可组成为一个较复杂的地址。
第 4章 伪指令及汇编语言源程序结构例 4-42
COUNT[EBX] ;简单基址,COUNT的偏移地址加 EBX内容
COUNT[EBX]+2 ;比上一语句多一个偏移量 2
COUNT[EBX]+[ESI] ;基址加变址第 4章 伪指令及汇编语言源程序结构
4) 地址表达式中的结构域地址表达式的另一个形式是,利用结构域名作为偏移量再加上结构的段内偏移。对一个结构类型变量来说,二个域名代表了其在结构内的偏移量。一个域名可以和一个相同类型的变量名或一个寄存器表达式组合成一个地址表达式。
第 4章 伪指令及汇编语言源程序结构例 4-43
ASTRUC STRUC
ABYTE DB 0
AWORD DW 0
BYTE2 DB 0
ASTRUC ENDS
ANARRAY DB 1,2,3,4 ; ANARRAY.AWORD的类型为 WORD
MOV AL,ANARRAY.BYTE2 ; AL= 4
MOV CX,ANARRAY.AWORD ; CX= 0302H
MOV BX,OFFSET ANARRAY ;偏移地址送 BX
MOV AL,[BX].ABYTE ; AL= 1,[BX].ABYTE类型为 BYTE
…
…
第 4章 伪指令及汇编语言源程序结构
5) 可重定位表达式如果地址表达式中有变量名、标号名、段名,则在所有程序模块汇编、连接、定位之前,它们的结果是不知道的。这样的表达式称为可重定位的。系统软件将为这些地址表达式赋值。
第 4章 伪指令及汇编语言源程序结构例 4-44 段名代表了段描述符的逻辑地址,一个段名形成一个基址可重定位地址。
DATA1 SEGMENT
DATA1 ENDS
DATA2 SEGMENT
SEGBASE DW DATA1 ; SEGBASE装有 DATA1段的基址可重定位地址
DATA2 ENDS
…
…
第 4章 伪指令及汇编语言源程序结构例 4-45 变量名或标号名可形成一个偏移或指针可重定位地址。
DATA SEGMENT USE32
ABYTE DB 0
AN_OFFSET DDABYTE+2 ; AN_OFFSET装有 ABYTE+2的偏移可重定位地址
A_POINTER DPABYTE ; A_POINTER装有 ABYTE的指针可重定位地址
DATA ENDS
第 4章 伪指令及汇编语言源程序结构
4.4.4 指令操作数
1.寄存器操作数大多数的寄存器都可作为显式操作数。段寄存器只能用于指令 MOV,PUSH和 POP。
例 4-46
MOV AX,FS ; FS寄存器的内容送 AX
ADD ESI,EBX ; ESI= ESI+EBX
MOV AX,BX ; BX寄存器的内容送 AX
第 4章 伪指令及汇编语言源程序结构
2.立即操作数立即操作数是一个整数或序数常量值。立即操作数只能作为源操作数,而不能作为目的操作数。
例 4-47
MOV AX,5 ; AL= 5
CMP AX,0FFFFH ; AX寄存器的内容与 0FFFFH比较
CMP BL,15 0R 5 ;立即操作数是一个常量表达式
MOV EDX,0FFSET VAR+1000 ;立即操作数是一个产生整数的表达式
MOV AX,DATASEG ;立即操作数是段名 DATASEG
MOV DS,AX ; DS初始化为 DATASEG段第 4章 伪指令及汇编语言源程序结构
3.存储器操作数
1) 直接存储器寻址直接对存储器寻址,指令操作数应该用变量或标号表示。
例 4-48
MOV EAX,COUNT ;把存储器中 COUNT处的双字送到 EAX中第 4章 伪指令及汇编语言源程序结构
2) 间接存储器寻址例 4-49 寄存器间接存储器寻址。
MOV BX,OFFSET AVAR ; BX=变量 AVAR的偏移
MOV AX,[BX] ; AX= AVAR的值例 4-50 基址寻址。
MOV EBX,OFFSET DATASTRUC ; EBX= DATASTRUC的基址
MOV EBX,[EBX+4] ; EBX=距 DATASTRUC第 4个字节的双字第 4章 伪指令及汇编语言源程序结构例 4-51 基址变址寻址。
XOR EAX,EAX ; EAX= 0
MOV EBX,OFFSET ARRAYSTR ; EBX=数组 ARRAYSTR的基地址
MOV ECX,LENGTH ARRAYSTR
MOV ESI,0 ;变址寄存器 ESI指向 0
ALAB,ADD EAX,[EBX+ESI] ;利用基址加变址得到数组元素
ADD ESI,4 ;增加变址
LOOP ALAB ;继续第 4章 伪指令及汇编语言源程序结构例 4-52 变址寻址。
MOV SI,0
MOV DI,0
MOV CX,LENGTHSOURCE ; CX= SOURCE数据单元的个数
ALAB,MOV AX,SOURCE[SI] ;变址地址
MOV DEST[DI],AX ;变址地址
ADD SI,2 ;指向 SOURCE的下一个字
ADD DI,2 ;指向 DEST的下一个字
LOOP ALAB ;循环到 ALAB
第 4章 伪指令及汇编语言源程序结构
4.5 段 的 组 织
4.5.1 代码段和数据段的定义
1,SEGMENT..ENDS伪指令可用一对伪指令 SEGMENT..ENDS定义逻辑段。之所以称为逻辑段是因为它们表示的是逻辑地址,在程序运行前,必须先映射到 80x86的物理地址上。汇编程序把命名后的段变成一块连续的物理地址,当程序运行时,把该段名字装入到一个 80X86段寄存器,逻辑段就能实际地访问了。
第 4章 伪指令及汇编语言源程序结构格式
NAME SEGMENT[ACCESS][USE][COMBINE]
[指令,伪指令,数据的初始化定义 ]
NAME ENDS
功能:定义一个汇编语言程序的代码或数据段。
…
…
第 4章 伪指令及汇编语言源程序结构说明:
(1) NAME是程序员为该段命名的标识符,即段名。在一个模块中,NAME必须是惟一的,NAME表示了该逻辑段的起始逻辑地址。在 SEGMENT..ENDS之间的段的内容表示了从段名 NAME开始的逻辑偏移地址。
(2) ACCESS是汇编语言及保护模式的描述,对程序中某段的存取限制方式有:只读、只可执行、可执行、可读及可读可写,其保留字分别为,RO,EO,ER和 RW。当省略 ACCESS时,汇编程序产生一个警告信息,汇编程序根据段的内容赋一个
ACCESS值,规则是:如果一个段中只有数据,其值为 RW;只有代码,其值为 EO;代码和数据都有,其值为 ER。
第 4章 伪指令及汇编语言源程序结构
(3) USE定义段的 USE属性。 USE属性决定一个段中代码的寻址方式、最大段的大小和操作数尺寸。 USE有两个值,即
USE16和 USE32。
① USE16 为该段内的标识符 (变量、标号、结构、记录和过程名 )产生一个 16位的地址偏移,用 USE16定义的段可长达
64KB;
第 4章 伪指令及汇编语言源程序结构
② USE32 为该段内的标识符 (变量、标号、结构、记录和过程名 )产生一个 32位的地址偏移,用 USE32定义的段可长达 4GB。
如果 SEGMENT语句省略 USE的值,段的 USE属性取决于离它最近的段或模块的属性。一般情况下,程序模块的缺省值是 USE32。
段的 USE属性也决定了某些 80X86指令的操作数尺寸。例如,如果一个段为 USE32,则 ENTER指令需要的立即操作数是 32位;如果一个段为 USE16,则操作数会用 0扩展到 32位。
第 4章 伪指令及汇编语言源程序结构
(4) COMBINE描述不同模块中的同名段怎样合并,以便在存储器中形成一个单一的物理段。实际上合并是发生在连接的时候。 COMBINE的值有两个,即 PUBLIC和 COMMON。
① PUBLIC所有定义为 PUBLIC的名字相同的段,将连接起来形成一个物理段;
② COMMON所有定义为 COMMON的名字相同的段,将重叠起来形成一个物理段。每个模块中的段名都有相同的物理地址,
在合并后的段内,偏移均为 0。
第 4章 伪指令及汇编语言源程序结构如果 COMBINE属性没有赋值,则段是不能合并的,即各个模块中同名的段并不形成一个单一的物理段。合并后的 PUBLIC
段的长度近似等于各 SEGMENT..ENDS段长度之和。对于定义为
PUBLIC的段,合并后的段并不保证连接的前后顺序,即不能确定某个段的哪部分在合并后的段中有 0偏移。合并后的 COMMON
段的长度等于各模块中所定义的段中那个最长的段的长度。一个 COMMON段的 ACCESS属性不能为 EO或 ER。
第 4章 伪指令及汇编语言源程序结构例 4-53
PROG_CODE SEGMENT RO PUBLIC USE32
PROG_CODE ENDS
此例定义了一个名叫 PROG_CODE的段。它的 ACCESS属性是
RO(只读 ); COMBINE属性是 PUBUC(公共 ); USE属性是 USE32(段内偏移为 32位 )。
…
第 4章 伪指令及汇编语言源程序结构
2.一个段的多次定义段在一个源程序模块中可任意打开和关闭多次。所有单独定义的段都被汇编程序连接起来,就好像它们被定义在单一的一个 SEGMENT..ENDS内。
过程、代码宏和结构的定义在段的边界上不能重叠。
当一个段重新打开时,并不需要重新定义 ACCESS,USE和
COMBINE属性。当段的 ACCESS属性重新指定时,两者的 ACCESS
属性应是兼容的,即 RW兼容 RO和 RW,ER兼容 RO,EO和 ER。如果重新指定的 ACCESS属性不兼容,将会出错。
第 4章 伪指令及汇编语言源程序结构例 4-54 说明下述程序段实现的功能。
DATA SEGMENT
ABYTE DB 0
AWORD DW 0
DATA ENDS ;关闭 DATA段;这里可定义任意其他非 DATA段
DATA SEGMENT ;重新打开 DATA段
ANOTHERBYTE DB 0
ANOTHERWORD DW 0
DATA ENDS
…
第 4章 伪指令及汇编语言源程序结构该程序段实现的功能是重新打开名为 DATA的段。该程序段中的语句等同于以下语句:
DATA SEGMENT
ABYTE DB 0
AWORD DW 0
ANOTHERBYTE DB 0
ANOTHERWORD DW 0
DATA ENDS
第 4章 伪指令及汇编语言源程序结构例 4-55 段属性具有承接性。
CODE SEGMENT ROPUBLIC USE32
CODE ENDS
CODE SEGMENT EO;承上面,隐含为 PUBLIC和 USE32
CODE ENDS
…
…
…
第 4章 伪指令及汇编语言源程序结构例 4-56 段属性的修改要符合兼容性规则。
F_SEG SEGMENT RW COMMON USE16
F_SEG ENDS
F_SEG SEGMENT ER PUBLIC USE32; 有 3个错误,RW和 ER不兼容,不能改变 COMBINE属性,不能改变 USE属性
F_SEG ENDS
…
…
…
第 4章 伪指令及汇编语言源程序结构
3.段的嵌套在实际的存储器中,不会嵌套汇编程序中的段。为了方便起见,汇编语言程序可嵌套定义段,但这只是语法上的嵌套,
并不表示实际上的嵌套。编程时注意要把要嵌套的段定义在其他段的 SEGMENT..ENDS之内。
第 4章 伪指令及汇编语言源程序结构例 4-57
PROG_CODE SEGMENT;开始处理 PROG_CODE段
PROG_DATA SEGMENT;开始处理 PROG_DATA段,停止汇编 PROG_CODE段
PROG_DATA ENDS;停止处理 PROG_DATA段重新开始处理 PROG_CODE段
PROG_CODEENDS ;结束 PROG_CODE段
…
…
…
此例中说明了一个合法的汇编语言段结构的嵌套。汇编程序认为 PROG_CODE代码段与 PROG_DATA数据段是分开的,
PROG_DATA段中的数据并不在 PROG_CODE段中,连接后,
这两个段在 80x86存储器中的物理地址可能相距很远。
第 4章 伪指令及汇编语言源程序结构例 4-58 本例中 SEGMENT...ENDS并没有成对地嵌套出现,
在汇编时会产生错误。
PROG_CODE SEGMENT;开始处理 PROC_CODE段
PROG_DATA SEGMENT;开始处理 PROG_DATA段,停止汇编 PROG_CODE段
PROG_CODE ENDS ;出错,在关闭 PROG_DATA段前不能关闭 PROG_CODE段
PROG_DATA ENDS
…
…
第 4章 伪指令及汇编语言源程序结构
4.5.2 堆栈段的定义
1,STACKSEG伪指令格式如下:
name STACKSEG exp
其中,name是所定义的逻辑栈段名,在程序中 name必须是惟一的; exp是为堆栈开辟的空间尺寸,可为表达式,单位是字节。
对于 USE32段,exp值为 0~ 4GB;对 USE16段来说,exp的值为
0~ 64 KB。
功能:定义一个逻辑堆栈段,并在储存器中为该堆栈段分配一定字节的存储空间。
第 4章 伪指令及汇编语言源程序结构说明:
① STACKSEG伪指令打开一个段,随即也关闭了该段,不能用 ENDS关闭段。
② 汇编语言堆栈段的 ACCESS属性总是 EW,COMBINE属性总是 PUBLIC。同名堆栈段的多次定义导致一个尺寸为所有堆栈段总和的一个段。
③ 堆栈段并不明显地给 USE属性赋值,它的 USE属性与离它最近关闭的段的 USE属性或模块的 USE属性相同。
④ 在堆栈段内不能定义代码、变量、标号或数据。可用
STACKSTART操作符初始化堆栈指针,即 SS∶ (E)SP中的内容。
第 4章 伪指令及汇编语言源程序结构
2.堆栈段和数据段的合并如果一个数据段和一个堆栈段具有一个相同的名字,并且它们的属性兼容,则它们合并为单一的数据 /堆栈段,数据段的属性必须为 PUBLIC和 RO或 RW。如果数据段不为 PUBLIC或它的
ACCESS属性是 EO或 ER时,则会产生错误。在这种情况下,汇编程序不会合并数据段和堆栈段,而在堆栈段的名字后附加上一 STACK,以区别每个段。
第 4章 伪指令及汇编语言源程序结构
4.5.3 段访问的指定
1,ASSUME伪指令格式:
ASSUME SREG∶ SEGPART[,…]
或 ASSUME SREG∶ NOTHING[,…]
或 ASSUME NOTHING
其中,SREG 是一个段寄存器,即 DS,ES,FS,GS或 SS。只有指定 NOTHING时,SREG才可以是 CS; SEGPART可以是保留字 NOTHING、段名或格式 SEG 变量名,SEG 过程名和 SEG外部名中的一个。
第 4章 伪指令及汇编语言源程序结构功能:告知汇编程序,CPU的哪个段寄存器指向程序中的一个逻辑段。值得注意的是,ASSUME并不对段寄存器实际装填,段寄存器需通过指令 (如 MOV等 )来进行装填。
说明:
① 当一条指令的操作数是变量或标号时,需要知道该变量或标号按哪个段访问。
② ASSUME 一般出现在代码段中可执行的汇编指令之前。
第 4章 伪指令及汇编语言源程序结构例 4-59 变量 ABYTE在 ESEG段中定义,现要在 CSEG段中使用,利用 ASSUME伪指令告知汇编程序 ES寄存器装有 ABYTE所在段的选择符。
ESEG SEGMENT RW USE32
ABYTE DB?
ESEG ENDS
CSEG SEGMENT ER USE32
ASSUME ES∶ ESEG
MOV AL,ABYTE ;汇编程序产生一个 ES段超越字节,;并对 ABYTE重新定位
MOV AL,ES,BYTE PTR 0 ;对 ES,BYTE PTR 0重新定位
…
…
…
第 4章 伪指令及汇编语言源程序结构例 4-60 若要通知汇编程序 DS寄存器装有 ABYTE所在段的选择符,可选用如下程序段。
ASSUME DS∶ SEG ABYTE
第 4章 伪指令及汇编语言源程序结构例 4-61 汇编程序处理 ASSUME语句和检查存储器访问的过程与方法如下述程序段描述。
DATA SEGMENT RW PUBLIC
ABYTE DB 0
AWORD DW 0
DATA ENDS
EDATA SEGMENT RW PUBLIC
WHERE DB 0
EDATA ENDS
CODE SEGMENT ER PUBLIC
CBYTE DB 0 ; CODE段的内容
…
第 4章 伪指令及汇编语言源程序结构
ASSUME DS,DATA ; DATA段通过 DS寻址
MOV AX,DATA ; AX= DATA段的选择符
MOV DS,AX ;初始化 DS
MOV AL,ABYTE ; ABYTE在 DS段中,通过 DS寻址,指令是正确的
MOV BL,CBYTE ; CBYTE在 CODE段中,就在当前段,指令是正确的,;汇编系统将生成一个 CS段超越,字节
MOV CL,WHERE ;这是一个程序错误,WHERE在 EDATA段中没有被任何; ASSUME指定,汇编程序将发出警告信息
…
第 4章 伪指令及汇编语言源程序结构
MOV AX,EDATA
MOV ES,AX ;现在 ES可寻址 WHERE,但汇编程序并不知道,;于是会发出警告
MOV CL,WHERE
ASSUME ES,EDATA
MOV CL,WHERE ;语句合法,因为 WHERE所在的段 EDATA被指定为 ES,;汇编程序将产生 ES段超越
CODE ENDS
…
第 4章 伪指令及汇编语言源程序结构
2,ASSUME NOTHlNG伪指令格式:
ASUUME NOTHING
功能,清掉以前的 ASSUME命令,等价于下列语句:
ASSUME CS∶ NOTHING,DS∶ NOTHING,
ES∶ NOTHING,FS∶ NOTHING,GS∶ NOTHING,
SS∶ NOTHING
说明:如果对段中定义的符号没有指定段寄存器,对符号的引用必须采用明显的 DS,ES,FS,GS或 SS段超越。汇编程序对代码段的访问总是通过 CS段寄存器进行。
第 4章 伪指令及汇编语言源程序结构例 4-62 说明 ASSUMEDS∶ DSEG和 ASSUMEDS∶ NOTHING
如何影响对 CSEG段中的 ABYTE符号的引用。
ASSUMEDS∶ DSEG
DSEG SEGMENTRW USE32
ABYTE DB?
DSEG ENDS
CSEG SEGMENT ER USE32
MOV AL,ABYTE ; ASSUME DS∶ DSEG仍影响着对 ABYTE的寻址,;汇编程序对有效的符号引用总是重新寻址
ASSUMEDS,NOTHING
MOV AL,ABYTE ;发生错误
MOV AL,DS∶ ABYTE ;采用段超越,因此无错
…
第 4章 伪指令及汇编语言源程序结构例 4-63 说明在一个数据段内,ASSUME ES∶ SEGMENT和 ASSUME
ES∶ NOTHING如何影响汇编程序对地址的生成。
ASSUME DS∶ DSEG,ES∶ ESEG;这里定义 ESEG段
DSES SEGMENT RW USE32
VAR1 PP ES∶ WORD PTR 0 ;汇编程序为 VAR1产生一个;可重定位的地址指针
ASSUME ES∶ NOTHING
VAR2 DP ES∶ WORD PTR 0 ;但并不为 VAR2产生
DSEG ENDS
…
…
…
第 4章 伪指令及汇编语言源程序结构
4.5.4 段寄存器的初始化
ASSUME伪指令仅仅指定逻辑段与段寄存器的匹配关系,
告知汇编程序某个逻辑段中的数据应通过哪个段寄存器寻址。
但是 ASSUME伪指令并没有将段选择符装入段寄存器。因此,
必须在程序中通过一定的指令 (如 MOV指令 ),把段选择符装入到段寄存器中。
第 4章 伪指令及汇编语言源程序结构
1,CS的初始化
CS寄存器的装填是自动进行的。主模块代码段的入口点必须指定一个标号,主模块的 END语句必须指示出这个入口点标号。当程序装载时,CS∶ (E)IP自动指向代码段入口点标号。
第 4章 伪指令及汇编语言源程序结构例 4-64 若要告诉汇编程序,程序从 START标号处开始,
CS∶ EIP装填标号 START的段选择符和偏移地址,可采用下述程序段。
CODE SEGMENT ER USE32
START:
CODE ENDS
END CS∶ START
当计算机复位、中断、程序转移时,CS∶ EIP的装填都是自动进行的,不用程序员干预。
…
第 4章 伪指令及汇编语言源程序结构
2,DS,ES,FS和 GS的初始化这 4个寄存器在源程序的代码段中,有 4种装填方法。
(1) 利用段名和 MOV指令。
例 4-65 在 ES中装入 DATA2段的选择符。
DATA1 SEGMENT RW
DATA1 ENDS
DATA2 SEGMENT RW
VAR32 DD 0
DATA2 ENDS
MOV BX,DATA2
ASSUME ES∶ DATA2
MOV ES,BX
…
…
第 4章 伪指令及汇编语言源程序结构
(2) 利用 SEG操作符和 MOV指令。
例 4-66 在 FS中装入 VAR32所在段的选择符,EXTRN伪指令指出 VAR32是在另一个源程序模块中定义的。
EXTRN VAR32 DWORD
MOV CX,SEG VAR32
ASSUME FS∶ SEG VAR32
MOV FS,CX
…
…
第 4章 伪指令及汇编语言源程序结构
(3) 利用一条 MOV指令,DS,ES,FS或 GS作为目的操作数,一个已初始化的存储器地址作为源操作数。
(4) 利用 LDS,LES,LFS或 LGS指令,这些指令的操作数是存储器指针。不要用段名作为源操作数。段名是立即数,不是存储器操作数。
第 4章 伪指令及汇编语言源程序结构
3,SS的初始化初始化 SS,(E)SP寄存器有 3种方法:
(1) 同数据段寄存器一样,可用若干条 MOV指令装填 SS。
(2) (E)SP的装填可用 MOV指令,(E)SP作为目的操作数,
带有 STACKSTART操作符的堆栈段名作为源操作数。
(3) 利用 LSS指令,不要用堆栈名作为 LSS的源操作数。
第 4章 伪指令及汇编语言源程序结构例 4-67 使用堆栈段名装填 SS和 ESP。
MOV AX,PROG_STACK ; PROG_STACK是定义的堆栈段名
MOV SS,AX
MOV ESP,STACKSTART PROG_STACK
段寄存器的初始化也可利用 END语句,而不必用指令装填。
第 4章 伪指令及汇编语言源程序结构例 4-68 可用 END语句初始化段寄存器 CS,DS,SS,即将段寄存器与对应的段名一起放在 END语句的后面。设 START为代码段的入口标号,DATA1为数据段名,PROG_STACK为堆栈段名,则用 END语句初始化段寄存器 CS,DS,SS描述如下:
END CS∶ START,DS∶ DATA1,SS∶ PROG_STACK
第 4章 伪指令及汇编语言源程序结构
4.6 程 序 段 前 缀
4.6.1 程序段前缀结构程序前缀 (PSP)是一个 256个字节的保留区,它位于分配给暂住程序内存块的底端,由 DOS创建。 PSP包含一些可被暂住程序使用的 DOS入口,一些 DOS为自己的目的所存储的信息,一些由 DOS传送给暂住程序的信息,这些信息视程序需要可能会使用也可能不会被使用。程序前缀的结构如图 4-3所示。
第 4章 伪指令及汇编语言源程序结构图 4-3 程序前缀的结构偏移地址
0000H INT 20H
0002H 段,分配块尾
0004H 保留区
0005H DOS功能调用
000AH 终止处理程序中断向量的以前的内容 (INT 22H)
000EH Ctrl-C中断向量以前的内容 (INT 23H)
0012H 出错处理中断向量以前的内容 (INT 22H)
0016H 保留区
002CH 环境块段地址
002EH 保留区
005CH 缺省文件控制块# 1
006CH 缺省文件控制块# 2(第 2个未经打开时将被覆盖 )
0080H
00FFH 命令行尾和缺省磁盘传送区域 (缓冲区 )
第 4章 伪指令及汇编语言源程序结构一个典型的,EXE型文件在刚刚加载进入内存后的映像如图
4-4所示。 EXE的内容被重新定位后,被加载到重新段前缀之后。
代码段、数据段和堆栈段驻留在不同的段中 (可不必与图 4-4所示的顺序相同 )。程序入口可位于代码段的任何地址中,该入口由程序主模块的 END语句给出。程序取得控制权后,DS和 ES寄存器指向程序段前缀,通常程序先将这两个值保存起来,然后 DS
和 ES寄存器指向数据段 (或附加段 )。
汇编时,汇编程序必须知道程序的段结构和在各种指令执行时访问哪一段,这个信息是由 ASSUME命令提供的。
第 4章 伪指令及汇编语言源程序结构图 4-4 一个典型的,EXE型文件刚加载进入内存后的映像地 址
SS∶ SP 堆栈段:堆栈由高端向下生长
SS∶ 0000H 数据段
CS∶ 0000H 程序代码
DS∶ 0000H 程序段前缀第 4章 伪指令及汇编语言源程序结构例 4-69 阅读下面给出的程序,回答以下 3个问题。
(1) 使用 SEGMENT,ENDS和 ASSUME命令定义代码段、
数据段、堆栈段和附加段的方法;
(2) 在用过程定义的程序中,为什么在程序的开始部分会有:
PUSH DS
SUB AX,AX
PUSH AX
这样的 3条指令,即程序中标有 **的 3条指令。
…
第 4章 伪指令及汇编语言源程序结构
(3) 程序前缀 (PSP)的使用。
DATA SEGMENT ;数据段
X DB?
Y DW?
Z DD?
DATA ENDS
ESTRA SEGMENT ;附加段
ALPHA DB?
BETA DW?
GAMA DD?
ESTRA ENDS
第 4章 伪指令及汇编语言源程序结构
STACK SEGMENT PARA STACK 'STACK' ;堆栈段
STAPN DB 100 DUP(?) ; 100个字节栈空间
TOP EQU LENGTH STAPN
STACK ENDS
CODE SEGMENT ; 代码段
ASSUME CS∶ CODE,ES∶ ESTRA,DS∶ DATA,SS∶ STACK
HAIN PROC FAR
PUSH DS
SUB AX,AX **
PUSH AX
MOV AX,DATA
第 4章 伪指令及汇编语言源程序结构
MOV DS,AX
MOV AX,EXTRA
MOV ES,AX
MOV AX,STACK
MOV SS,AX
MOV AX,TOP
MOV SP,AX
ORG 0009H
RET
MAIN ENDP
CODE ENDS
END MAIN
第 4章 伪指令及汇编语言源程序结构本例中的数据段和附加段均定义了一些数据,在堆栈段中定义了 100个字节的堆栈空间。
ASSUME的格式、功能和使用方法在前面已作过介绍,
ASSUME语句告诉汇编程序可以假定一个特定的段寄存器指向一个特定的段,汇编程序还无法生成目的码程序,即 ASSUME
伪指令只是指出各段的段寄存器的分配,并没有把段地址装入相应的段寄存器,因此,在代码段中,还必须把段地址装入相应的段寄存器中,这个过程称之为段寄存器的加载。本例中由
ASSUME指明 CS寄存器指向命名为 CODE的段,ES指向 EXTRA
段,DS指向 DATA段,SS指向 STACK段。
第 4章 伪指令及汇编语言源程序结构各个段寄存器的加载方法是:由 DOS将控制权交给程序时,通过,EXE文件头的入口信息和程序加载地址计算得到代码段寄存器 CS和指令指针 (E)IP的初始值。入口信息由源代码中某程序模块中的 END语句的参数转换而来。数据段 CS和附加段 ES,FS,GS寄存器被设置指向程序段前缀,以便程序存取环境块指针、命令行尾以及包含于其中的别的有用的信息。
堆栈段寄存器 SS和堆栈指针 (E)SP的值由文件头给出。该指针信息由源程序中 STACK属性段转换而来,分配给堆栈的内存空间依堆栈段的定义,可以是初始化的,也可以是不经初始化的。
第 4章 伪指令及汇编语言源程序结构若将堆栈内存初始化为可识别的数据类型,能观察内存信息,确定程序使用了多少堆栈空间。要完成这一工作,必须通过一定的指令来实现。其中,CS的加载较为特殊,只有它是无需用户专门处理,DS,SS,ES,FS和 GS必须由用户通过编程自行加载。
第 4章 伪指令及汇编语言源程序结构
1,CS的加载
CS的加载有以下几种情况:
(1) 用户执行的 END后有标号,连接后的可执行程序自动将
CS,(E)IP在执行时执行该标号处;
(2) 遇到 JMP或 CALL指令时,自动修正 CS,(E)IP的值;
(3) 当使用 INT n时,或产生硬件中断时,将利用 n× 4的物理地址,从中取出低字装入 (E)IP、高字装入 CS;
(4) 硬件复位时,自动将 (E)IP清 0,CS置为 0FFFFH,以指向
ROM中初始化程序。
第 4章 伪指令及汇编语言源程序结构
2,DS,SS,ES,FS和 GS加载这几个段寄存器的加载应由用户编程实现,一般方法:
MOV AX,<逻辑段名 >
MOV <段寄存器名 >,AX
设数据段的段名为 DATA,加载 DS段寄存器的方法如下:
MOV AX,DATA
MOV DS,AX
一个,EXE程序执行完后,将通过 INT 20H功能调用将控制权返回 DOS。
第 4章 伪指令及汇编语言源程序结构在此程序中,若要求把字节单元 X的内容传送至字节单元
ALPHA,这需要在码段中增加一些指令。先把 X的内容传送给一个寄存器 (例如 BX),然后再从这个寄存器传送给 ALPHA,所以需要如下命令:
MOV BX,X
MOV ALPHA,BX
第 4章 伪指令及汇编语言源程序结构在指令执行时,80x86 CPU将用寄存器 DS去寻找所指定的项 (X或 ALPHA)所在段的起始地址。执行第一条指令工作正常,
因为 X确实是在由 DS的内容 DATA作为起始地址的段内。但在执行第二条指令时,如何能正常工作呢?因为包含有 ALPHA的这一段的起始地址 EXTRA并不在 DS中,对这样的指令,在汇编时,
由 ASSUME语句告诉汇编程序,EXTRA不在 DS中,而在另一个段寄存器 ES中。所以要正确执行第二条指令,必须要有 — 个段超越前缀,虽然指令中没有,汇编程序会产生这样的前缀,
加到第二条指令中去,以便将来能正确执行。
第 4章 伪指令及汇编语言源程序结构有些情况下,为了更明确地指明段寄存器,或代替
ASSUME语句的作用,可以在有关的指令中增加段超越前缀,
用以告诉汇编程序,在这一条指令执行时,应使用哪 — 个段寄存器,例如上面提到的把 X的内容移至 ALPHA中可以写成:
MOV DX,DS∶ X
MOV ES∶ ALPHA,BX
这表示当访问 X时,应用 DS,而访问 ALPHA时,应该用 ES。
第 4章 伪指令及汇编语言源程序结构由于程序采用的是过程定义方式 (过程定义在 4.3.4节中作了描述 ),在程序执行完成后能正确地返回,如本例所示,必须有标有 **的一段程序。当执行此程序时,DOS把控制权转给这个程序时,在程序段前缀的开始 (偏移地址 00H)处安排了一条中断返回指令 INT 20H(如图 4-3)。为了在程序执行后正常返回,必须先将 DS进栈,同时将段内偏移量 (AX中的零 )进栈。然后再把数据段的地址传送给 DS,由 ASSUME语句告诉汇编程序,DS寄存器指向数据段。
第 4章 伪指令及汇编语言源程序结构
4.6.2 COM文件结构
.COM文件结构的源程序经过汇编、连接形成,EXE文件后,
再用 EXE2BIN.EXE命令即可转换成,COM文件。
扩展名为,COM的文件也可以通过在 DOS下直接键入文件名的方法装入并执行,而且也产生一个程序段前缀。但是与,EXE
文件不同的是,DOS把段前缀看作是被装入文件的一部分,覆盖着被装入文件的前面 100H个字节。因此程序员必须保证程序中第一条可执行的指令一定在 CS∶ 100H处。
第 4章 伪指令及汇编语言源程序结构
.COM文件被装入后,CS,DS,ES,SS都设置为指向程序段前缀的段地址,IP固定为 100H,整个程序只占一个物理段 (最大 64 KB),SP指向这一物理段的末尾,并在栈顶存放了两个字节 00H。,COM文件不像,EXE文件那样带有定位信息,因此只能把整个文件看作一段,整段可重定位。但不能分段重定位。
正因为不带定位信息,因此程序中不能出现如 MOV AX,DATA
这样的指令,因为装入程序无法确定 DATA的定位信息。,COM
文件中若要对段寄存器进行操作,程序员应确保这些操作是参照当前 CS的。例如,应该用 PUSH CS与 POP DS指令代替,EXE
文件中的 MOV AX,CODE与 MOV DS,AX指令。,COM文件中任何地方都可以安排 INT 20H指令,以实现退出程序,返回
DOS。,COM文件占用内存少。
第 4章 伪指令及汇编语言源程序结构再者,因为不需要重定位信息,所以在用 DEBUG调试完,COM文件后,可用 DEBUG的写入命令将文件写回盘上。注意,因 DEBUG不能生成重定位信息,所以,.EXE文件经
DEBUG调试完后,不能直接写回盘上。
如果程序在编写时就符合,COM文件的规定要求,那么,
经汇编连接后生成的,EXE文件可以直接转换为,COM文件;
DOS中的 EXE2BIN程序可以将,EXE文件转换成,COM文件,但被转换的,EXE文件必须符合,COM文件的规定。例 4-70给出的程序是一个符合,COM文件要求的例子。
第 4章 伪指令及汇编语言源程序结构例 4-70
CODE SEGMENT
ASSUME CS∶ CODE,DS∶ CODE ;数据段和代码段是同一个物理段
ORG 100H
START,JMP BEGIN ;第一条可执行指令存放在 0100H处
BUF DB 35H,78H,0A5H
SUM DB?
BEGIN,MOV AX,CS
MOV DS,AX ;设置数据段地址
MOV AL,0
第 4章 伪指令及汇编语言源程序结构
MOV SI,OFFSET BUF
ADD AL,[SI]
INC SI
ADD AL,[SI]
INC SI
ADD AL,[SI]
MOV SUM,AL ;存储累加结果
MOV AH,4CH
INT 21H ;返回 DOS
CODE ENDS
END START
第 4章 伪指令及汇编语言源程序结构由此可看出,.COM结构的程序有如下两个特点:
(1) 整个程序逻辑段可以有几个,但物理段只能有一个,
即整个程序 (包括数据和代码 )在一个段 (64 KB)的范围内。
(2) 程序中的第一条可执行指令在段中的 0100H处存放。
第 4章 伪指令及汇编语言源程序结构习 题 四
4.1 对于下面数据定义,三条 MOV指令分别汇编成什么?
(可用立即数方式表示)
TABLEA DW 10 DUP(?)
TABLEB DB 10 DUP(?)
TABLEC DB '1234'
MOV AX,LENGTH TABLEA
MOV BL,LENGTH TABLEB
MOV CL,LENGTH TABLEC
…
第 4章 伪指令及汇编语言源程序结构
4.2 在指令 AND AX,OPD1 AND OPD2中,OPD1和 OPD2
是两个已赋值的变量,问两个 AND操作分别在什么时间进行?
有什么区别?
4.3 如下指令或程序是否有错? 错在哪里?
(1) K1 EQU 1024
MOV K1,AX
(2) MOV DS,100
MOV [1000],[2000]
(3) IMP DB?
MOV IMP,AX
第 4章 伪指令及汇编语言源程序结构
(4) A1 DB?
A2 DB 10
CMP A1,A2
(5) 将 1000送入 X1单元,用如下程序:
X1 DB?
MOV BX,X1
MOV [BX],1000
第 4章 伪指令及汇编语言源程序结构
4.4 指出下列伪指令表达方式的错误,并改正之。
(1) STACK_SEG SEGMENT 'STACK'
(2) DATA_SEG SEG
(3) MYDATA SEGMENT 'DATA'
ENDS
(4) SEGMENT 'CODE'
(5) MAIN_PROC PROC FAR
END MAIN_PROC
MAIN_PROC ENDP
…
…
第 4章 伪指令及汇编语言源程序结构
4.5 下列语句在存储器中分别为变量分配多少字节?
VR1 DW 9
VR2 DW 4 DUP(?),2
CONT EQU 10
VR3 DD CONT DUP(?)
VR4 DB 2 DUP(?,CONT DUP(0))
VR5 DB 'HOW ARE YOU? '
第 4章 伪指令及汇编语言源程序结构
4.6 下面语句有何区别?
X1 EQU 1000H
X2 = 1000H
4.7 分析操作符和合成操作符各有哪几种,分别举例并加以解释说明。
4.8 80x86汇编语言程序中段的类型有几种?各段如何定义?
段定义中,定位类型,组合类型、类别各起什么作用?各有什么含义?
第 4章 伪指令及汇编语言源程序结构
4.9 画图说明下列伪指令所定义的数据在内存中的存放形式。
ARY1 DB 7,43H,-2
ARY2 DW 476FH,1,?
ARY3 DB 3 DUP(1,2 DUP(2),3)
第 4章 伪指令及汇编语言源程序结构
4.10 定义一个名字为 DATA的数据段,段中的变量及数据如下:
DA1为字符串变量,'ABCDEPGH'
DA2为字节变量,43H,76,-5,0F8H
DA3为字变量,20个 0
DA4为字变量,4F5AH,3786,-2
DA5为双字变量,768AEF4BH
第 4章 伪指令及汇编语言源程序结构
4.11 假设有如下数据定义伪指令:
BUF1 DB 1,2,3,4,5
BUF2 DB 10 DUP(?)
BUF3 DW 4786H,5F6BH
BUF4 DW 20 DUP(?)
第 4章 伪指令及汇编语言源程序结构写出下列指令执行后的结果:
MOV AL,TYPE BUF1 AL=( )
MOV BL,TYPE BUP4 BL=( )
MOV CL,LENGTH BUF1 CL=( )
MOV DL,LENGTH BUF2 DL=( )
MOV AH,LENGTH BUF4 AH=( )
MOV BH,SIZE BUF2 BH=( )
MOV CH,SIZE BUF3 CH=( )
MOV DH,SIZE BUF4 DH=( )
第 4章 伪指令及汇编语言源程序结构
4.12 给定如下数据定义伪指令:
BUFB DB 42H,1,-1
BUFW DW 4785H,2A60H
写出下列指令执行后的结果:
MOV AL,BUFB AL= ( H)
MOV Bl,BYTE PTR BUFW BL= ( H)
MOV AX,WORD PTR BUFB+1 AX= ( H)
MOV BX,BUFW+2 BX= ( H)
第 4章 伪指令及汇编语言源程序结构
4.13 给出如下伪指令:
BUF DW 10,20,30,40,50
下面的程序段执行后,AX= ( H)
MOV BX,OFFSET BUF
ADD BX,5
MOVAX,[BX]
第 4章 伪指令及汇编语言源程序结构
4.14 自 BX寄存器所指的内存单元开始,连续存放着两个四字节的有符号数 (低位字节在前 ),编程序求它们的差 (第一个数减第二个数 ),并将结果存放在这两个数之后,若有溢出,
将 BX寄存器清零。
第 4章 伪指令及汇编语言源程序结构
4.15 编程序使:
(1) AX寄存器的低四位清零。
(2) BX寄存器的低四位置 1。
(3) CX寄存器的低四位变反。
(4) 用 TEST指令测试 DL寄存器的位 3位 6是否同时为 0,若是,
将 0送 DL寄存器;否则,将 1送 DH。要求用两种方法。
4.16 编程序使 AL寄存器中的无符号数乘 20。
第 4章 伪指令及汇编语言源程序结构
4.17 数据定义语句如下所示:
FIRST DB 90H,5FH,6EH,69H
SECOND DB 5 DUP(?)
THIRD DB 5 DUP(?)
FOURTH DB 5 DUP(?)
自 FIRST单元开始存放的是一个四字节的十六进制数 (低位字节在前 ),注意保留移出部分。要求:
(1) 编一段程序将这个数左移两位后存放到自 SECOND开始的单元。
(2) 编一段程序将这个数右移两位后存放到自 THIRD开始的单元。
(3) 编一段程序将这个数求补以后存放到自 FOURTH开始的单元。