Download presentation
Presentation is loading. Please wait.
1
汇编语言程序设计 吴 向 军 中山大学计算机科学系
2
第1章 预备知识 1.1 汇编语言的由来及其特点 1.1.1 机器语言 机器指令是CPU能直接识别并执行的指令,它的表现形式是二进制编码。
机器指令通常由操作码和操作数两部分组成: 操作码指出该指令所要完成的操作,即指令的功能; 操作数指出参与运算的对象,以及运算结果所存放的位置等。 机器指令与CPU紧密相关,所以,不同种类的CPU所对应的机器指令也就不同。
3
第1章 预备知识 1.1.2 汇编语言 用通俗易懂、具有一定含义的符号来代表机器指令,这些符号称为助忆符,用指令助忆符、符号地址等组成的符号指令称为汇编格式指令(或汇编指令)。 汇编语言是汇编指令集、伪指令集和使用它们规则的统称。 伪指令是在程序设计时所需要的一些辅助性说明指令,它不对应具体的机器指令。 用汇编语言编写的程序称为汇编语言程序,或汇编语言源程序,在本教材中简 称为源程序。汇编语言程序要比用机器指令编写的程序容易理解和维护。
4
第1章 预备知识 1.1.3 汇编程序 用汇编语言编写的程序大大提高了程序的可读性,但失去了CPU能直接识别的特性。
目前,常用的汇编程序有:MASM、TASM和DEBUG等。 图1.1 汇编语言指令到机器指令的示意图
5
第1章 预备知识 1.1.4 汇编语言程序的主要特点 汇编语言程序归纳起来大概有以下几个主要特性。 与机器相关性 执行的高效率
编写程序的复杂性 调试的复杂性 现在在调试方面有所改善,CV(CodeView)、TD(Turbo Debug)等软件可在源程序级进行符号跟踪。
6
第1章 预备知识 1.1.5 汇编语言的使用领域 根据应用程序的“可移植性”和“执行效率”来确定是否选用汇编语言。
下面简单列举几个领域以示说明,但不要把它们绝对化。 1、适用的领域 要求执行效率高、反应快的领域,如:操作系统内核,实时系统等; 系统性能的瓶颈,或频繁被使用子程序或程序段; 与硬件资源密切相关的软件开发,如:设备驱动程序等; 受存储容量限制的应用领域,如:家用电器的计算机控制功能等; 2、不宜使用的领域 大型软件的整体开发; 没有特殊要求的一般应用系统的开发等。
7
第1章 预备知识 1.2 数据的表示和类型 1.2.1 数值数据的表示
用汇编语言进行程序设计时,程序员可以直接访问内存,对数据在存储器内的表示形式要有清晰的认识。有关“数据表示”的详细内容请参阅《计算机组成原理》中的章节。 1.2.1 数值数据的表示 1、二进制 二进制的表示元素是:0和1。书写时,在数据后面紧跟一个字母B。如:0101B、10101B等。 数据的二进制写起来比较长,通常情况下,程序中不直接用二进制来书写具体的数值,而改用八进制、十进制或十六进制。
8
第1章 预备知识 2、八进制 八进制是一种二进制的变形,三位二进制可变为一位八进制,反之也然。 八进制的表示元素是:0、1、…、7。
书写时,在数据后面紧跟一个字母Q。如:1234Q、7654Q、54Q等。 3、十进制 十进制是我们最熟悉的一种数据表示形式,其基本元素是:0、1、…、9。 书写时,在数据后面紧跟一个字母D。如:1234D、7674D、5411D等。 4、十六进制 十六进制是另一种二进制的变形,四位二进制可变为一位十六进制,反之也然。其基本元素是:0~9、A~F、a~f,其中:A~F依次代表10~15。 书写时,数据后面紧跟一个字母H。当十六进制数的第一个字符是字母时,在其之前必须添加一个‘0’。如:100H、56EFH、0FFH、0ABCDH等。
9
第1章 预备知识 进 制 字 符 例 子 二进制 B/Y(*) 1010B、1011B 八进制 Q/O 1234Q、311Q 十进制 D/T
1.2.2 进制在编程环境中的表示 程序员在用汇编语言进行程序设计时,需要知道当前环境的数据表示符号。 进 制 字 符 例 子 二进制 B/Y(*) 1010B、1011B 八进制 Q/O 1234Q、311Q 十进制 D/T 1234D、512D 十六进制 H 1234H、1011H (*) 字符Y、O和T是宏汇编MASM系统所增加的进制表示符。
10
第1章 预备知识 1.2.3 非数值数据的表示 1、ASCII码 在ASCII码表中,对学习本课程有用的主要信息有:
小写字母的ASCII码比大写字母的编码大,对应字母的编码之间相差20H。 2、汉字编码 我国在1981年5月对6000多个常用的汉字制定了交换码的国家标准,即:GB 。 该标准给定每个字符的二进制编码,即国标码。
11
第1章 预备知识 1.2.4 基本的数据类型 1、字节 一个字节有8位二进制组成,其最高位是第7位,最低位是第0位。
通常情况下,存储器按字节编址,读写存储器的最小信息单位就是字节。 2、字 由2个字节组成一个字,其最高位是第15位,最低位是第0位。高8位称为高字节,低8位称为低字节。 3、双字 用2个字(4个字节)来组成一个双字,其高16位称为高字,低16位称为低字。 双字有较大的数据表示范围,它通常是为了满足数据的表示范围而选用的数据类型,也可用于存储远指针。
12
第1章 预备知识 4、四字 由4个字(8个字节)组成一个四字类型,它总共有64个二进制位,有更大的数据表示范围,但在汇编语言中很少使用该数据类型。 5、十字节 由10个字节组成一个十字节类型,它总共有80个二进制位。在汇编语言中很少使用该数据类型。 6、字符串 字符串是由若干个字节组成的,字节数不定,通常每个字节存储一个字符。该数据形式是汇编语言程序中经常使用的一种数据形式。 汇编语言中没有C语言中的规定:以ASCII码0为字符串的结束符。
13
第2章 CPU资源和存储器 2.1 寄存器组 2.1.1 16位寄存器组
计算机的硬件资源是用汇编语言编程所必须要了解的重要内容,因为汇编语言允许、也需要程序员直接使用这些硬件资源,只有这样才能编写出高效的目标代码。 2.1 寄存器组 位寄存器组 4个数据寄存器:AX、BX、CX和DX,每个寄存器又可分为2个8位寄存器 2个变址寄存器:DI和SI 2个指针寄存器:SP和BP 4个段寄存器:ES、CS、SS和DS 1个标志寄存器:FLAG 1个指令指针寄存器:IP
14
第2章 CPU资源和存储器 位寄存器组 32位CPU把通用寄存器、指令指针和标志寄存器从16位扩充成32位,而且还增加了2个16位的段寄存器:FS和GS。如下图所示。 32位CPU有8个32位的通用寄存器EAX、EBX、ECX、EDX、ESI、EDI、ESP和EBP,这些通用寄存器的低16位就是先前CPU中的AX、BX、CX、DX、SI、DI、SP和BP。对其低16位数据的存取,不会影响高16位的数据。
15
第2章 CPU资源和存储器 2.1.3 通用寄存器的作用 1. 数据寄存器
数据寄存器主要用来保存操作数和运算结果等信息,从而节省读取操作数所需占用总线和访问存储器的时间。 4个32位寄存器:EAX、EBX、ECX和EDX 4个16位寄存器:AX、BX、CX和DX 8个8位寄存器:AH和AL、BH和BL、CH和CL、DH和DL 每个寄存器都有自己的名称,可独立存取。程序员可利用数据寄存器“能分可合”的特性,灵活地处理双字、字和字节等信息。
16
第2章 CPU资源和存储器 2. 变址寄存器(Index Register)
寄存器SI和DI称为变址寄存器,它们可作一般的存储器指针使用。在字符串操作指令的执行过程中,对它们有特定的要求,且具有特殊的功能。 3. 指针寄存器(Pointer Register) 寄存器BP和SP称为指针寄存器,它们主要用于访问堆栈内的存储单元,并且规定: BP为基指针(Base Pointer)寄存器,用它可直接存取堆栈中的数据 SP为堆栈指针(Stack Pointer)寄存器,用它只可访问栈顶。
17
第2章 CPU资源和存储器 表2.1 通用寄存器的主要用途 寄存器名称 寄存器符号 主 要 用 途 累加器 EAX、AX、AL
主 要 用 途 累加器 EAX、AX、AL 乘、除、I/O、快速的算术运算,中间结果的缓存 基地址寄存器 EBX、BX 在数据段中作基地址指针 计数器 ECX、CX、CL 循环计数器、重复操作计算器、移位操作计数器 数据寄存器 EDX、DX 字的乘、除运算,间接的输入输出 源变址寄存器 ESI、SI 存储器指针、串指令中的源操作数指针 源目标变址寄存器 EDI、DI 存储器指针、串指令中的目的操作数指针 基地址指针 EBP、BP 存储器指针、存取堆栈的指针 栈顶指针 ESP、SP 堆栈的栈顶指针
18
第2章 CPU资源和存储器 2.1.4 段寄存器的作用 CS——代码段寄存器(Code Segment Register)
DS——数据段寄存器(Data Segment Register) SS——堆栈段寄存器(Stack Segment Register) ES——附加段寄存器(Extra Segment Register) FS——386CPU增加段寄存器(Extra Segment Register) GS——386CPU增加段寄存器(Extra Segment Register) 有关寄存器的作用详细描述。
19
第2章 CPU资源和存储器 2.1.5 专用寄存器的作用 1、指令指针寄存器(Instruction Pointer)
指令指针IP和EIP是16位和32位的寄存器,它们分别位于16位和32位处理器之中。指令指针寄存器存放着下次将要执行的指令在代码段的偏移量。 在80386及其高档处理器处于保护模式时,其指令指针寄存器是32位的EIP。 在实方式下,由于每个段的最大范围就是64K,所以,EIP中的高16位肯定都为0,相当于只用其低16位来反映程序中指令的执行次序,这样,EIP低16位与先前CPU中的IP作用相同。 2、标志寄存器(Flags Register) 有关标志位寄存器的详细描述。
20
第2章 CPU资源和存储器 2.2 存储器的管理模式 2.2.1 16位微机的内存管理模式 1. 存储器的分段
计算机的内存单元是以“字节”为最小单位进行线性编址的。为了标识每个存储单元,就给每个存储单元规定一个编号,此编号就是该存储单元的物理地址。 16位微机把内存空间划分成若干个逻辑段,每个逻辑段的要求如下: 逻辑段的起始地址(通常简称为:段地址)必须是16的倍数,即最低4位二进制必须全为0; 逻辑段的最大容量为64K,这由16位寄存器的寻址空间所决定。 按上述规定,1M内存最多可分成64K个段,即65536个段(段之间相互重叠),至少可分成16个相互不重叠的段。
21
第2章 CPU资源和存储器 物理地址PA=段地址×16 + 偏移量 2. 物理地址的形成方式
存储单元的逻辑地址分为两部分:段地址和偏移量。由逻辑地址得到其物理地址(PA—Physical Address)的计算方法如下: 物理地址PA=段地址×16 + 偏移量 计算存储单元物理地址的公式可用“左移4位”和“加”运算来实现。 对物理地址来说,当其段地址变化时,只要对其偏移量进行相应的调整就可得到同一个物理地址,所以,同一个物理地址可有多个逻辑地址。
22
第2章 CPU资源和存储器 3、段寄存器的引用 段寄存器是因为对内存的分段管理而设置的。一般情况下,段寄存器及其指针寄存器的引用关系方面有如下规定: 取指令所用的段寄存器和偏移量一定是用CS和IP; 堆栈操作所用的段寄存器和偏移量一定是SS和SP; 串操作的目标操作数所用的段寄存器和偏移量一定是ES和DI; 其它情况,段寄存器除其默认段寄存器外,还可以强行改变为其它段寄存器。
23
第2章 CPU资源和存储器 表2.3 段寄存器及其指针寄存器的引用关系 访问存储器方式 缺省的段寄存器 可选用的段寄存器 偏 移 量 取指令
偏 移 量 取指令 CS IP 堆栈操作 SS SP 一般取操作数 DS CS、ES、SS 有效地址 串操作 源操作数 SI 目标操作数 ES DI 使用指针寄存器BP CS、DS、ES
24
第2章 CPU资源和存储器 1. 存储单元的内容 存储单元中所存放的二进制信息称为该存储单元的内容或值,并且规定:
一个字节的内容是该字节单元内存放的二进制信息; 一个字的内容是该字地址所指向的单元及其后继一个单元的内容拼接而成; 一个双字的内容是该字地址所指向的单元及其后三个单元的内容拼接而成。 在拼接“字内容”时,我们按“高高低低”的原则来处理,即:高存储单元(地址大的存储单元)的值是“字内容”的高8位,低存储单元(地址小的存储单元)的值是“字内容”的低8位。 在拼接“双字内容”时也是如此。
25
第2章 CPU资源和存储器 下图是一段内存单元存放数据的例子。从图中可看出下列存储结果:
字节12340H、12341H的内容分别为:12H和34H 字12340H、12341H的内容分别为:3412H和5634H 双字12340H、12341H的内容分别为: H和 H
26
第3章 操作数的寻址方式 微机系统有七种基本的寻址方式:立即寻址方式、寄存器寻址方式、直接寻址方式、寄存器间接寻址方式、寄存器相对寻址方式、基址加变址寻址方式、相对基址加变址寻址方式等。其中,后五种寻址方式是确定内存单元有效地址的五种不同的计算方法,用它们可方便地实现对数组元素的访问。 另外,在32位微机系统中,为了扩大对存储单元的寻址能力,增加了一种新的寻址方式——32位地址的寻址方式。
27
第3章 操作数的寻址方式 3.1 立即寻址方式 操作数作为指令的一部分而直接写在指令中,这种操作数称为立即数,这种寻址方式也就称为立即数寻址方式。 立即数可以是8位、16位或32位数,该数值紧跟在操作码之后。如果立即数为16位或32位,那么,它将按“高高低低”的原则进行存储。例如: MOV AH, 80H ADD AX, 1234H MOV ECX, H MOV B1, 12H MOV W1, 3456H ADD D1, H 其中:B1、W1和D1分别是字节、字和双字单元。 立即数寻址方式通常用于对通用寄存器或内存单元赋初值。
28
第3章 操作数的寻址方式 下图是指令“MOV AX, 4576H”的存储形式和执行情况示意图。
29
第3章 操作数的寻址方式 3.2 寄存器寻址方式 指令所要的操作数已存储在某寄存器中,或把目标操作数存入寄存器。把在指令中指出所使用寄存器(即:寄存器的助忆符)的寻址方式称为寄存器寻址方式。 指令中可以引用的寄存器及其符号名称如下: 8位寄存器有:AH、AL、BH、BL、CH、CL、DH和DL等; 16位寄存器有:AX、BX、CX、DX、SI、DI、SP、BP和段寄存器等; 32位寄存器有:EAX、EBX、ECX、EDX、ESI、EDI、ESP和EBP等。 寄存器寻址方式是一种简单快捷的寻址方式,源和目的操作数都可以是寄存器。 由于指令所需的操作数已存储在寄存器中,或操作的结果存入寄存器,这样,在指令执行过程中,会减少读/写存储器单元的次数。 通常情况下,我们提倡应尽可能地使用寄存器寻址方式,但也不要绝对化。
30
第3章 操作数的寻址方式 3.3 直接寻址方式 指令所要的操作数存放在内存中,在指令中直接给出该操作数的有效地址,这种寻址方式为直接寻址方式。 通常情况下,操作数存放在数据段中,所以,其物理地址将由数据段寄存器DS和指令中给出的有效地址直接形成,但如果使用段超越前缀,那么,操作数可存放在其它段。
31
第3章 操作数的寻址方式 例3.1 假设有指令:MOV BX, [1234H],在执行时,(DS)=2000H,内存单元21234H的值为5213H。问该指令执行后,BX的值是什么? 解:根据直接寻址方式的寻址规则,把该指令的具体执行过程如下图所示。
32
第3章 操作数的寻址方式 3.4 寄存器间接寻址方式 操作数在存储器中,操作数的有效地址用SI、DI、BX和BP等四个寄存器之一来指定,称这种寻址方式为寄存器间接寻址方式。 该寻址方式物理地址的计算方法如下: 在不使用段超越前缀的情况下,有下列规定: 若有效地址用SI、DI和BX等之一来指定,则其缺省的段寄存器为DS; 若有效地址用BP来指定,则其缺省的段寄存器为SS(即:堆栈段)。
33
PA=(DS)*16+(DI)=1000H*16+2345H=12345H。
第3章 操作数的寻址方式 例3.2 假设有指令:MOV BX, [DI],在执行时,(DS)=1000H,(DI)=2345H,存储单元12345H的内容是4354H。问执行指令后,BX的值是什么? 解:根据寄存器间接寻址方式的规则,在执行本例指令时,寄存器DI的值不是操作数,而是操作数的地址。该操作数的物理地址应由DS和DI的值形成,即: PA=(DS)*16+(DI)=1000H* H=12345H。 该指令的执行效果:把从物理地址为12345H开始的一个字的值传送给BX。
34
第3章 操作数的寻址方式 3.5 寄存器相对寻址方式 操作数在存储器中,其有效地址是一个基址寄存器(BX、BP)或变址寄存器(SI、DI)的内容和指令中的8位/16位偏移量之和。 其有效地址的计算公式如下: 在不使用段超越前缀的情况下,有下列规定: 若有效地址用SI、DI和BX等之一来指定,则其缺省的段寄存器为DS; 若有效地址用BP来指定,则其缺省的段寄存器为SS(即:堆栈段)。
35
第3章 操作数的寻址方式 EA=(SI)+100H=2345H+100H=2445H
例3.3 假设指令:MOV BX, [SI+100H],在执行它时,(DS)=1000H,(SI)=2345H,内存单元12445H的内容为2715H,问该指令执行后,BX的值是什么? 解:根据寄存器相对寻址方式的规则,在本指令中的源操作数的有效地址EA为: EA=(SI)+100H=2345H+100H=2445H 该操作数的物理地址应由DS和EA的值形成,即: PA=(DS)*16+EA=1000H* H=12445H。 该指令的执行效果是:把从物理地址为12445H开始的一个字的值传送给BX。
36
第3章 操作数的寻址方式 3.6 基址加变址寻址方式 操作数在存储器中,其有效地址是一个基址寄存器(BX、BP)和一个变址寄存器(SI、DI)的内容之和。 其有效地址的计算公式如下: 在不使用段超越前缀的情况下,有下列规定: 若有效地址用SI、DI和BX等之一来指定,则其缺省的段寄存器为DS; 若有效地址用BP来指定,则其缺省的段寄存器为SS(即:堆栈段)。
37
第3章 操作数的寻址方式 EA=(BX)+(SI)=2100H+0011H=2111H
例3.4 假设指令:MOV BX, [BX+SI],在执行时,(DS)=1000H,(BX)=2100H,(SI)=0011H,内存单元12111H的内容为1234H。问指令执行后,BX的值是什么? 解:根据基址加变址寻址方式的规则,在本指令的源操作数的有效地址EA为: EA=(BX)+(SI)=2100H+0011H=2111H 该操作数的物理地址应由DS和EA的值形成,即: PA=(DS)*16+EA=1000H* H=12111H 该指令的执行效果是:把从物理地址为12111H开始的一个字的值传送给BX。
38
第3章 操作数的寻址方式 3.7 相对基址加变址寻址方式
操作数在存储器中,其有效地址是一个基址寄存器(BX、BP)的值、一个变址寄存器(SI、DI)的值和指令中的8位/16位偏移量之和。 其有效地址的计算公式如下: 在不使用段超越前缀的情况下,有下列规定: 若有效地址用SI、DI和BX等之一来指定,则其缺省的段寄存器为DS; 若有效地址用BP来指定,则其缺省的段寄存器为SS(即:堆栈段)。
39
EA=(BX)+(SI)+200H=2100H+0010H+200H=2310H
第3章 操作数的寻址方式 例3.5 假设指令:MOV AX, [BX+SI+200H],在执行时,(DS)=1000H,(BX)= 2100H,(SI)=0010H,内存单元12310H的内容为1234H。问指令执行后,AX的值是什么? 解:根据相对基址加变址寻址方式的规则,本指令中源操作数的有效地址EA为: EA=(BX)+(SI)+200H=2100H+0010H+200H=2310H 该操作数的物理地址应由DS和EA的值形成,即: PA=(DS)*16+EA=1000H* H=12310H 该指令的执行效果是:把从物理地址为12310H开始的一个字的值传送给AX。
40
第3章 操作数的寻址方式 相对基址加变址寻址方式有多种等价的书写方式,书写格式:
[BX+SI+1000H]、1000H[BX+SI]、1000H[BX][SI]和1000H[SI][BX]等格式都是正确的,并且其寻址含义也是一致的, 但格式:BX[1000H+SI]、SI[1000H+BX]等是错误的,即所用寄存器不能在”[“,”]”之外,该限制对寄存器相对寻址方式的书写也同样起作用。
41
第3章 操作数的寻址方式 相对基址加变址寻址方式与其它寻址方式之间的变形关系 源操作数 指令的变形 源操作数的寻址方式 只有一个偏移量
MOV AX, [100H] 直接寻址方式 只有一个寄存器 MOV AX, [BX] 或 MOV AX, [SI] 寄存器间接寻址方式 有一个寄存器和偏移量 MOV AX, [BX+100H] 或 MOV AX, [SI+100H] 寄存器相对寻址方式 有二个寄存器 MOV AX, [BX+SI] 基址加变址寻址方式 有二个寄存器和常数项 MOV AX, [BX+SI+100H] 相对基址加变址寻址方式
42
第3章 操作数的寻址方式 3.8 32位地址的寻址方式 在32位微机系统中,除了支持前面的七种寻址方式外,又提供了一种更灵活、方便,但也更复杂的内存寻址方式。 用16位寄存器来访问存储单元时,只能使用基地址和变址寄存器来作为地址偏移量的一部分,但在用32位寄存器寻址时,不存在上述限制,所有32位寄存器(EAX、EBX、ECX、EDX、ESI、EDI、EBP和ESP)都可以是地址偏移量的一个组成部分。 当用32位地址偏移量进行寻址时,内存地址的偏移量可分为三部分:一个32位基址寄存器,一个可乘1、2、4或8的32位变址寄存器,一个8位/32位的偏移常量,并且这三部分还可进行任意组合,省去其中之一或之二。 基址寄存器是:EAX、EBX、ECX、EDX、ESI、EDI、EBP和ESP; 变址寄存器是:EAX、EBX、ECX、EDX、ESI、EDI和EBP(除ESP之外)。
43
第3章 操作数的寻址方式 用32位地址偏移量进行寻址的有效地址计算公式归纳如下:
MOV AX, [123456H] MOV EAX, [EBX] MOV EBX, [ECX*2] MOV EBX, [EAX+100H] MOV EDX, [EAX*4+200H] MOV EBX, [EAX+EDX*2] MOV EBX, [EAX+EDX*2+300H] MOV AX, [ESP]
44
第3章 操作数的寻址方式 由于32位寻址方式能使用所有的通用寄存器,和该有效地址相组合的段寄存器也就有新的规定。具体规定如下:
1、地址中寄存器的书写顺序决定该寄存器是基址寄存器,还是变址寄存器;如:[EBX+EBP]中的EBX是基址寄存器,EBP是变址寄存器,而[EBP+EBX]中的EBP是基址寄存器,EBX是变址寄存器; 2、默认段寄存器的选用取决于基址寄存器; 3、基址寄存器是EBP或ESP时,默认段寄存器是SS,否则,默认段寄存器是DS; 4、在指令中,如果使用段前缀的方式,那么,显式段寄存器优先。
45
第3章 操作数的寻址方式 下面列举几个32位地址寻址指令及其内存操作数的段寄存器。 MOV AX, [123456H] ;默认段寄存器DS
MOV EAX, [EBX+EBP] ;默认段寄存器DS MOV EBX, [EBP+EBX] ;默认段寄存器SS MOV EBX, [EAX+100H] ;默认段寄存器DS MOV EDX, ES:[EAX*4+200H] ;显式段寄存器ES MOV [ESP+EDX*2], AX ;默认段寄存器SS MOV EBX, GS:[EAX+EDX*2+300H] ;显式段寄存器GS MOV AX, [ESP] ;默认段寄存器SS
46
第4章 标识符和表达式 4.1 标识符 标识符和表达式是程序设计经常用到的两个基本概念。
标号、内存变量名、子程序名和宏名等都是标识符。通常情况下,汇编语言不区分标识符中字母的大小写。 和高级语言的变量名一样,一般要求标识符尽可能取得有点含义,这会有助于对程序的理解。
47
第4章 标识符和表达式 标识符不能是汇编语言的保留字,汇编语言的保留字主要是指:指令助忆符、伪指令定义符、寄存器名以及一些具有特殊含义的字符串等。 例如:MSG1、ERRMSG2、ASC1、asc2等是合法的标识符,而1a、ah、mov等就不是标识符。 试比较ABCDH和0ABCDH之间的差异。前者是标识符,而后者是十六进制数值。
48
第4章 标识符和表达式 4.2 简单内存变量的定义 在高级语言程序中,要给存储单元取一个符号名,然后通过引用该符号名来访问其所对应的存储单元。 在汇编语言程序中要灵活一些,它可以给存储单元取符号名,也可以不取符号名。 当给存储单元取符号名时,则可通过该符号名来访问其对应的存储单元; 当不给存储单元取符号名时,则可通过存储单元的偏移量(有效地址)来访问它。
49
[变量名] 数据定义符 表达式1[, 表达式2, …, 表达式n] [;注释]
第4章 标识符和表达式 4.2.1 内存变量定义的一般形式 定义内存变量语句是程序中经常使用的伪指令语句,其一般格式如下: [变量名] 数据定义符 表达式1[, 表达式2, …, 表达式n] [;注释] 该定义格式的主要解释如下: 变量名必须是一个合法的标识符,它可以写,也可以不写; 数据定义符用于确定内存单元的数据类型,常用定义符有:DB、DW和DD等; 表达式是定义内存单元时的初值表达式,一个定义语句可以有多个初值表达式,各表达式之间必须用逗号分开;如果某个存储单元没有初值表达式,则必须用一个问号’?’来表示; 在定义语句的后面可以书写注释内容,也可以不写。
50
第4章 标识符和表达式 在定义变量时,虽然可以不写变量名,但我们建议还是要写,因为不写变量名,就意味着只能用内存单元的偏移量来访问它。
这时,一旦内存单元的偏移量发生变化,那么程序中所有引用都要修改。这不仅增加了程序维护的工作量,而且也容易因遗漏修改而出错。
51
第4章 标识符和表达式 4.2.2 字节变量 字节变量的定义符为DB/BYTE(Define Byte)(*),每个字节变量只占一个字节单元。 例如: COUNTER DB 6 DB ‘A’, ‘D’, 0Dh, ‘$’ TABLE DB 1, 3, 5, 7, 9, 11 … 06 41 44 0D 24 01 03 05 07 09 0B COUNTER TABLE (*) BYTE是MASM 6.0及其以后版本的数据类型说明符,随后的其它类型说明符同此说明。
52
第4章 标识符和表达式 用定义符DB还可定义一种特殊的数据形式——字符串。
在定义字符串时,必须用成对的单引号或双引号把所要的字符括起来,括号内字符的ASCII码将依次存放在相应的字节单元内。例如: MSG1 DB ‘I am a student.’ … ‘I’ ‘ ‘ ‘a’ ‘m’ ‘s’ ‘t’ ‘u’ ‘d’ ‘e’ ‘n’ ‘.’ 上面的例子也可改写为另一种等价的语句: MSG1 DB ‘I’, ‘ ‘, ‘a’, ‘m’, ‘ ‘, ‘a’, ‘ ‘, ‘s’, ’t’, ’u’, ’d’, ’e’, ’n’, ’t’, '.' 显然,前者要比后者方便得多,所以,在程序中都采用前者的书写方式。
53
第4章 标识符和表达式 4.2.3 字变量 字变量的定义符为DW/WORD(Define Word),每个字变量占两个连续的字节单元。
例如: Word1 DW 89H, 1909H, -1 DW 0abcdH, ?, 0 … 89 00 09 19 FF CD AB -- 由于字变量的数据是按照“高高低低”的原则存于存储单元之中的,而字节数据是按照排列顺序存于存储单元中的,所以,它们的存储方式有所不同。
54
第4章 标识符和表达式 试比较下面两个定义的存储顺序。 B1 DB ‘AB’ W1 DW ‘AB’
其中:41H和42H分别是’A’和’B’的ASCII码。 … 41 42
55
第4章 标识符和表达式 4.2.4 双字变量 双字变量的定义符为DD/DWORD (Define Double word),每个双字变量占用二个连续的字单元(四个字节)。 例如: DD1 DD H, ? DD2 DD 0abcd1243H 上述定义的内存分配如下所示,双字的内容也是按“高高低低”的原则来存储的。 … 78 56 34 12 -- 43 CD AB
56
第4章 标识符和表达式 4.2.5 六字节变量 六字节变量的定义符为DF/FWORD (Define Farword)。每个六字节变量占用六个连续的字节。 例如: DF1 DF abH, 0H, -1 DF 1abcd23H 第一个六字节常量 abH在内存中的分配方式如下所示,它也是按“高高低低”的原则来存储的。其它六字节常量的存储方式与此一致。 … ab 90 78 56 34 12
57
第4章 标识符和表达式 4.2.6 八字节变量 八字节变量的定义符为DQ/QWORD(Define Quadword)。每个八字节变量占用八个连续的字节。 例如: DQ1 DQ H, 0H, -1234H DQ ?, 1238H, ? 第一个八字节常量 H在内存中的分配方式如下所示,其存储原则与前面相同。其它八字节常量的存储方式与此一致。 … 78 56 34 12 00
58
第4章 标识符和表达式 4.2.7 十字节变量 定义十字节变量的定义符为DT/TBYTE (Define Tenbytes)。每个十字节变量占用十个连续的字节。 例如: DT1 DT H, ? DT2 DT ?, -1H 第一个十字节常量 H在内存中的分配方式如下所示,它同样按“高高低低”的原则来存储。其它十字节常量的存储方式与此一致。 … 78 56 34 12 00
59
第4章 标识符和表达式 4.3 调整偏移量伪指令 4.3.1 偶对齐伪指令EVEN
调整偏移量伪指令是在内存变量定义时用来调整内存变量起始偏移量的,它们是在把源程序汇编成目标文件时起作用。 常用的调整偏移量伪指令有:EVEN、ALIGN和ORG。 4.3.1 偶对齐伪指令EVEN 偶对齐伪指令格式: EVEN 伪指令的作用是:告诉汇编程序(Assember),本伪指令下面的内存变量从下一个偶地址单元开始分配。 如果下一个偏移量是偶地址,那么,该伪指令不起作用;否则,汇编程序将空出一个字节,从下一偶地址开始为其后变量分配内存单元。
60
第4章 标识符和表达式 假设有下列变量定义,并且变量B1的偏移量是偶数。
B1 DB 12H ;为了表示方便,不妨再假设其偏移量为:xxxx0H W1 DW 4567H 可把前面的变量定义改变成下列形式: B1 DB 12H EVEN W1 DW 4567H
61
第4章 标识符和表达式 4.3.2 对齐伪指令ALIGN 对齐伪指令格式: ALIGN Num
试比较下面二组变量定义,它们的对齐效果一致吗? B1 DB 12H B1 DB 12H EVEN ALIGN 2 W1 DW H W1 DW 4567H
62
第4章 标识符和表达式 4.3.3 调整偏移量伪指令ORG 调整偏移量伪指令格式: ORG 数值表达式
伪指令的作用是:告诉汇编程序,本伪指令下面的内存变量从该“数值表达式”所指定的偏移量开始分配。 假设有下列变量定义,且变量word1的偏移量为0。 word1 DW h byte1 DB 56h word2 DW 0abcdh ORG 1 byte2 DB ? word3 DW ? byte3 DB ?
63
第4章 标识符和表达式 4.3.4 偏移量计数器的值 汇编语言提供了一个特殊的符号“$”来引用偏移量计数器的值。 例如:
W1 DW $, $ ORG $+3 ;从当前地址开始空3个字节 B1 DB 43h 假设:在给变量W1分配内存单元时,当前偏移量计数 器的值为2。
64
第4章 标识符和表达式 4.4 复合内存变量的定义 4.4.1 重复说明符DUP
count DUP (表达式, 表达式, …, 表达式) 解释:count是重复次数,(表达式, 表达式, …, 表达式)是被重复的部分,“表达式”可以是存储单元的初值,也可以是含义另一个DUP的式子。如果在表达式的括号中有多个表达式,那么,它们之间要用逗号‘,’分开。 例如: BUFFER DB DUP (?) STRING DB DUP ('ABCDE'), 0 DATA1 DW 50 DUP (10H, 20 DUP(1,2,3), 20H) POINTS DD 12, 30 DUP (0)
65
第4章 标识符和表达式 4.4.2 结构类型的定义 1、结构类型的定义
用STRUC和ENDS可以把一系列数据定义语句括起来作为一种新的、用户定义的结构类型。其一般说明格式如下: 结构名 STRUC [Alignment] [,NONUNIQUE] 数据定义语句序列 结构名 ENDS 解释:结构名是一个合法的标识符,且具有唯一性。结构名代表整个结构类型,前后两个结构名必须一致。结构内被定义的变量为结构字段,变量名即为字段名。 一个结构中允许含有任意多个字段,各字段的类型和所占字节数也都可任意。如果字段有字段名,则字段名必须唯一。每个字段可独立存取。
66
第4章 标识符和表达式 对齐方式(Alignment):可用1、2或4来指定结构中字段的字节边界(Byte boundary),其缺省值为1。 NONUNIQUE:要求结构中的字段必须用全名才能访问,见本小节中的“结构类型字段的引用”。 例如: COURSE STRUC NO DD ? CNAME DB ‘Assember’ SCORE DW 0 COURSE ENDS A s e m b r NO CNAME SCORE
67
第4章 标识符和表达式 结构中的字段可以有字段名,也可以没有字段名。有字段名的字段可直接用该字段名来访问它,没有字段名的字段可以用该字段在结构中的偏移量来访问。 例如: PEASON STRUC NO DD ? ;偏移量为0 NAME DB 10 dup (?) ;偏移量为4 DB ;偏移量为14 PEASON ENDS 在结构PEASON中,有二个字段有字段名,一个字段没有字段名,但不管有无字段名,我们都可用其偏移量来访问它。
68
第4章 标识符和表达式 2、结构类型变量的定义 在定义某个结构类型后,程序员就可以说明该结构类型的内存变量。它的说明形式与前面介绍的简单数据类型的变量说明基本上相一致。其说明格式如下: [变量名] 结构名 <[字段值表]> 解释: 变量名即为该结构类型的变量名,它可省缺。如果省缺,则不能用符号名来访问该内存单元; 字段值表是给字段赋初值,中间用逗号‘,’分开,其字段值的排列顺序及类型应与该结构说明时各字段相一致; 如果结构变量中某字段用其定义时的缺省值,那么,可用逗号来表示;如果所有字段都如此,则可省去字段值表,但必须保留尖括号“<”、“>”。
69
第4章 标识符和表达式 例如: COURSE1 COURSE <> ;使用缺省的初值
COURSE <1, 'Pascal', 60> COURSE3 COURSE <2, , 84> ;使用缺省的课程名 PEASON1 PEASON <1000, '张 三', 34> 3、结构类型字段的引用 定义了结构类型的变量后,若要访问其结构中的某字段,则可采用如下形式: 结构变量名.字段名 该引用方式与高级语言的字段引用方式完全一致。 我们还可用偏移量来访问其中的某个字段,但此方法不直观,变动性大,所以,一般情况下,不提倡使用此方法。
70
第4章 标识符和表达式 例如: EXAM1 STRUC F1 DW ? F2 DB ? EVEN ;偶对齐 F3 DW ?
EXAM1 ENDS E1 EXAM1 <1234H, ’A’, 8765H> ;定义EXAM1的一个变量E1 下面二种方法都可把结构变量E1中字段F3的内容赋给寄存器AX,但如果在字段F3之前增加或减少了字段,那么,这些引用需要改变吗? (1)、用字段名直接引用 MOV AX, E1.F3 (2)、用字段的偏移量间接引用 LEA SI, E1 MOV AX, [SI+4] ;其中4是字段F3的偏移量
71
第4章 标识符和表达式 4.4.3 联合类型的定义 联合数据类型是一种特殊的数据类型。它可以实现:以一种数据类型存储数据,以另一种数据类型来读取数据。程序员可以根据不同的需要,以不同的数据类型来读取联合类型中的数据。 1、联合类型的说明 联合数据类型其说明格式如下: [联合类型名] UNION [Alignment] [,NONUNIQUE] 数据定义语句序列 [联合类型名] ENDS 联合类型中的各字段相互覆盖,即同样的存储单元被多个不同的字段所对应,并且其每个字段的偏移量都为0。 联合类型所占的字节数是其所有字段所占字节数的最大值。
72
第4章 标识符和表达式 例如: DATATYPE UNION BB1 DB ? ;一个字节类型的字段 WW1 DW ? ;一个字类型的字段
DD1 DD ? ;一个双字类型的字段 DATATYPE ENDS 在联合类型的最外层定义中,在伪指令UNION和ENDS的前面一定要书写该联合类型名,而在其嵌套定义的内层,伪指令UNION和ENDS之前一定不能写联合类型名。 UNION1 UNION BB DB ? WW DW ? UNION ;联合类型的嵌套定义形式 W1 DW ? B1 DB ? ENDS UNION1 ENDS
73
第4章 标识符和表达式 2、联合类型变量的定义 联合数据类型的变量只能用第一个字段的数据类型来进行初始化。 例如:
U1 DATATYPE <’J’> ;定义一个联合变量,并初始化其值 U2 DATATYPE <1234H> ;初始化错误,只能用字节数据来初始化 U3 UNION1 <1> 3、联合类型字段的引用 定义了联合类型的变量后,就可根据需要,以不同的数据类型或字段名来存取该联合类型中的数据。引用其字段的具体形式如下: 联合类型变量名.字段名 MOV U3.WW, 1234H ;给联合类型变量赋字数据 MOV AL, U3.BB ;AL=34H MOV BX, U3.WW ;BX=1234H MOV U3.BB, ‘A’ ;U1的值1241H,41H是’A’的ASCII码
74
第4章 标识符和表达式 4.4.4 记录类型的定义 1、记录类型的说明
汇编语言的记录类型与高级语言的记录类型不同,它是为按二进制位存取数据提供方便的。记录类型的说明要用到另一个保留字RECORD,其说明格式如下: 记录名 RECORD 字段 [, 字段, ……] 其中“字段”代表:字段名:宽度[=初值表达式]
75
第4章 标识符和表达式 解释: 记录名代表该记录类型; 记录类型可以由多个字段组成,每个字段之间要用逗号‘,’分开;
字段的属性包括字段名、宽度和初值; 字段的“宽度”表示该字段所占的二进制位数,它必须是一个常数,并且所有字段的宽度之和不能大于16;如果记录的总宽度大于8,则系统为该记录类型分配二个字节,否则,只分配一个字节; 记录的最后一个字段排在所分配空间的最低位,然后对记录中的字段依次“从右向左”分配二进制位,左边没有分完的二进制位补0; 初值表达式给出的是该字段的缺省值。如果初值超过了该字段的表示范围,那么,在汇编时将产生错误提示信息;如果某字段没有初值表达式,则其初值为0。
76
第4章 标识符和表达式 例如: COLOR RECORD BLINK:1, BACK:3=0, INTENSE:1=1, FORE:3
FLOAT RECORD DSIGN:1, DATA:8, ESIGN:1, EXP:4
77
第4章 标识符和表达式 2、记录变量的定义 在程序中,必须先说明记录类型,然后才能定义该记录类型的变量。记录变量是把其二进制位分成一个或多个字段的字节或字变量。其定义格式与其它类型变量的定义方式类似,具体如下: [变量名] 记录名 <[字段值表]> 解释: 变量名即为该记录类型的变量名,它可省缺。如果省缺,则不能用符号名来访问该内存单元; 字段值表是给字段赋初值,中间用逗号‘,’分开,其字段值的排列顺序及大小应与该记录说明时各字段相一致; 如果记录变量的某字段用其说明时的缺省值,那么,可用逗号来表示;如果所有字段都如此,则可省去字段值表,但必须保留尖括号“<”、“>”。
78
第4章 标识符和表达式 例如: COLOR1 COLOR <>, <1, 7, 0, 5>, <1, , 0, 7> FLOAT FLOAT <1, 23H, 0, 3>, <0, 89H, 1, 5> 3、记录的专用操作符 操作符WIDTH 操作符WIDTH返回记录或其字段的二进制位数,即其宽度。其一般书写格式如下: WIDTH 记录名 或 WIDTH 记录字段名 假设有前面定义的记录类型COLOR,那么,WIDTH COLOR、WIDTH BACK和WIDTH BLINK的值分别为8、3和1。
79
第4章 标识符和表达式 操作符MASK 操作符MASK返回一个8位或16位二进制数。在该二进制数中,被指定记录或字段使用的对应位的值为1,否则,其值为0。其一般书写格式如下: MASK 记录名 或 MASK 记录字段名 假设有前面定义的记录类型FLOAT,那么,MASK EXP、MASK DATA和MASK DSIGN的值就分别为000FH、1FE0H和2000H。 记录字段 记录字段名是一个特殊的操作符,它本身也是操作数,其返回值是该字段移到所在记录的最低位所需要的位数,即该字段最低位在记录中的位置。 假设有前面定义的记录类型FLOAT,那么,有: MOV CL, EXP 相当于 MOV CL, 0 MOV CL, DATA 相当于 MOV CL, 5
80
第4章 标识符和表达式 4.4.5 数据类型的自定义 在有了一些数据类型后,程序员还可定义这些数据类型的别名或指针类型。表达这种定义的伪指令是TYPEDEF,其定义形式如下: 新数据类型名 TYPEDEF [位距] [PTR] 数据类型 其中:“位距”是NEAR、FAR或PROC等。 例如: CHAR TYPEDEF BYTE ;给BYTE定义另一个别名CHAR PCHAR TYPEDEF PTR CHAR ;定义一个字符指针数据类型PCHAR 有了上述定义之后,下面的变量说明就是合法的。 CH CHAR ‘ABCDEF’ ;定义一个字符串常量 PCH1 PCHAR CH ;定义一个指向字符串CH1的变量
81
第4章 标识符和表达式 4.5 标号 标号是一种特殊的标识符,它代表代码段中的某个具体位置,它主要用于表明转移的目标位置。其说明形式如下:
标号: 汇编语言指令 ;注释 解释:标号必须是合法标识符,其后面紧跟一个冒号‘:’,冒号与汇编语言指令之间要有分隔符。分隔符是指空格和TAB字符。一般用分隔符使有关内容对齐为宜。
82
第4章 标识符和表达式 4.6 内存变量和标号的属性 变量是一个符号地址,其值会根据其数据类型来对应从该地址以后的若干个存储单元中所存的数值。 标号也是一个符号地址,它所对应的存储单元中存放的是指令代码。它们都是一个符号地址,代表一个存储单元的地址,所以,它们都具有存储单元的属性。除此之外,它们还有各自特殊的属性。
83
第4章 标识符和表达式 4.6.1 段属性操作符 段属性操作符(SEG)返回该标识符所在段的段地址。我们一般只会取内存变量所在段的段地址,而很少取标号所在段的段地址。 假设有下面变量定义: … SCORE DW ? NAME DB DUP(10) ;数据段的变量定义 MOV AX, SEG SCORE ;代码段的指令 MOV BX, SEG NAME 由于SCORE和NAME在同一段中定义,所以,寄存器AX和BX的值是相等的。
84
第4章 标识符和表达式 4.6.2 偏移量属性操作符 偏移量属性操作符(OFFSET)返回该标识符离它所在段的段地址有多少字节。
假设有下面变量定义: FIRST DD H, 0 ;数据段的变量定义 SCORE DW ?, 12H NAME DB DUP(10) … MOV AX, OFFSET SCORE MOV BX, OFFSET NAME 假设FIRST是数据段的第一个被定义的变量名,它的偏移量为0,SCORE的偏移量为8,因为它要跳过二个双字,其它如此类推。 由于NAME在SCORE之后,且SCORE之后有二个字,占四个字节,所以,BX的值要比AX的值大4。
85
第4章 标识符和表达式 4.6.3 类型属性操作符 类型属性操作符(TYPE)是返回该变量所占字节数,或标号的“远”(FAR)、“近” (NEAR)类型。 标识符种类 字节变量 字变量 双字变量 近标号 (NEAR) 远标号 (FAR) TYPE的值 1 2 4 -1 -2 例如: PEASON STRUC NO DD ? NAME DB 10 dup (?) DW 1 PEASON ENDS … B1 DB 1, 2, 3 W1 DW 200 DUP(1,2,30 DUP(10,20)), 101H, -1 PEOPLE PEASON <> 按属性TYPE的含义,B1、W1和PEOPLE的属性TYPE值分别为:1,2和16。
86
第4章 标识符和表达式 4.6.4 长度属性操作符 4.6.5 容量属性操作符
长度属性操作符(LENGTH)是针对内存变量的操作符,它返回重复操作符DUP中的重复数。如果有嵌套的DUP,则只返回最外层的重复数;如果没有操作符DUP,则返回1。 根据属性LENGTH的含义,LENGTH B1、W1和PEOPLE的值分别为:1,200和1。 4.6.5 容量属性操作符 容量属性操作符(SIZE)也是针对内存变量的操作符。它的返回值按下列公式计算: SIZE 变量 =(LENGTH 变量) × (TYPE 变量) 如上例所示,SIZE B1、W1和PEOPLE的值分别为:1,400和16。
87
第4章 标识符和表达式 4.6.6 强制属性操作符 在程序中,我们有时需要对同一个存储单元以不同的属性来访问,这时,就要强制属性操作符PTR。该操作符的作用有点象C语言中的类型强制方法。 对于指令:MOV [BX], 1H,其目标操作数[BX]是寄存器间接寻址方式,它指向一个存储单元。 在作传送操作时,是把“1H”扩展成8位作字节传送,还是扩展成16位作字传送呢?这就使该指令具有二义性,因为[BX]指向的存储单元可以字节或字的首地址。 含有该指令的程序在汇编时,可能会产生警告或出错信息。
88
第4章 标识符和表达式 为了使指令中存储单元操作数具有明确的属性,我们可以使用强制属性操作符PTR。其一般格式为:
其中:数据类型是所学的各种数据类型,常用的数据类型有:BYTE、WORD、DWORD、NEAR和FAR等。 为了明确指令中存储单元的属性,可把指令“MOV [BX], 1H”可改写成: MOV byte ptr [BX], 1H 或 MOV word ptr [BX], 1H 在指令中用操作符PTR强制后,不管其后的地址表达式原数据类型是什么,在本指令中就以PTR前面的类型为准。该强制属性只在本指令有效,是一种临时性的属性,它不会改变原内存单元的定义属性。
89
第4章 标识符和表达式 例如: W1 DW 1234H, 5678H B1 DB 2 DB 5 D1 DD 23456789H …
MOV AX, word ptr b1 ;把B1开始的二个字节拼接成一个字, (AX)=0502H MOV BH, byte ptr w1 ;把字W1的低字节传送给BH,(BH)=34H MOV CH, byte ptr w1+1 ;把字W1的高字节传送给CH,(CH)=12H MOV word ptr d1,12H ;把双字D1的低字修改成0012H,(D1)= H 上面指令中的强制属性是临时属性,它不能改变这些变量在定义时的永久属性。 34h 12h 78h 56h 02h 05h 89h 67h 45h 23h W1 B1 D1
90
第4章 标识符和表达式 4.6.7 存储单元别名操作符 我们知道:在程序中,可用强制属性操作符PTR来实现以不同的数据类型来访问某一存储单元时。 如果要经常以某种其它的数据类型来访问该存储单元的话,那么,就必须在每次访问时都要加上强制属性操作符PTR。在编写程序时就显得比较麻烦。 为了克服上述不便,汇编语言提供了另一种操作符THIS,它为同一存储单元取另一别名,该别名可具有其自身的数据属性,但其段地址和偏移量是不变的。 操作符THIS的一般格式为: THIS 数据类型 其中:常用的数据类型有:BYTE、WORD、DWORD、NEAR和FAR等。
91
第4章 标识符和表达式 4.6.8 存储单元别名操作符 例如: WBUFFER EQU THIS WORD
BUFFER DB 20 DUP(?) … WBUFFER:字属性 BUFFER:字节属性
92
第4章 标识符和表达式 4.7 表达式 4.7.1 进制伪指令RADIX
表达式是程序设计中的一个重要的基本概念,它一般由运算符、操作符、括号、常量和一些符号连在一起的式子。 在汇编语言中,表达式分为:数值表达式和地址表达式。 4.7.1 进制伪指令RADIX 伪指令RADIX用来设置整数的缺省进制,宏汇编开始时所默认的整数进制为十进制。该伪指令的使用格式如下: .RADIX exp 其中:伪指令前面要用点‘.’开始,exp的值必须是区间[2, 16]内的一个整数。 该伪指令说明下面整数的默认进制为exp。如果某整数已显式地表明了其进制,则该默认进制对其不起作用。 在源文件中,可以使用多个RADIX伪指令来分别说明其后整数的默认进制。
93
第4章 标识符和表达式 例如: .radix 8 B1 DB 10, 11, 12 ;这三个数是八进制数 DB 10D ;这数是十进制数 …
MOV AX, ;1234是十进制数 MOV AX, 1234H ;1234H是十六进制数 思考题: .radix 16 DW 90D, 101B ;前者是十进制数,后者是二进制数吗?
94
第4章 标识符和表达式 4.7.2 数值表达式 数值表达式是在汇编过程中能够由汇编程序计算出来的数值型表达式,它的各组成部分在汇编时就能完全确定。它通常是一些常量的运算组合。 1、常量 常量是一个立即数,直接写在汇编语言语句中,在程序的执行过程中,它不可能发生变化。如: B、324Q、1234D、1234H、0abcdH、'AB'等。 在前面的内容里,我们叙述了可用伪指令.RADIX来改变数据基数的方法。 2、算术运算符 算术运算符包括符号:+(正)、-(负),运算符:+(加)、-(减)、*(乘)、/(除)和MOD(取模)。这些运算符和常量、括号可组成数值表达式。 如:120+(321-90) mod 3,322*5/32,0abcdH+5,-590等
95
第4章 标识符和表达式 3、关系运算符 关系运算符包括符号:EQ(相等)、NE(不等)、LT(小于)、GT(大于)、LE(小于等于)和GE(大于等于)。该表达式的计算结果规定如下: 若关系不成立,则该数值表达式的计算结果为0;否则,其结果为0FFFFH。 如:120H LT 100H+3,21H LE 21H等,计算结果分别为:0和0FFFFH。 4、逻辑运算符 逻辑运算符包括按位操作符和移位操作符。具体是:AND、OR、NOT、XOR、SHL(左移位)和SHR(右移位)。 如:1 SHL 3,47H AND 0FH,NOT 56H等,计算结果分别为:8,7和0A9H。
96
第4章 标识符和表达式 5、表达式中的其它操作符 汇编语言中,还有其它可在数值表达式中使用的操作符。它们是:
HIGH(高8位)、LOW(低8位) SEG(段地址)、OFFSET(偏移量) TYPE(标识符类型)、LENGTH(变量长度)、SIZE(变量容量) WIDTH(记录/记录字段宽度)、MASK(记录/记录字段的屏蔽位) 在以上操作符中,HIGH和LOW还没有介绍过。它们的使用格式如下: HIGH 表达式 LOW 表达式 它们的作用是分别选取表达式计算结果的高8位和低8位。 如:HIGH (1234H+100H),LOW 1234H等,选取结果分别为:13H和34H。
97
第4章 标识符和表达式 6、运算符和操作符的优先级 汇编语言有各种运算符和操作符,它们的优先级按从高到低的排列如下:
LENGTH、SIZE、WIDTH、MASK、()、[]、.(结构字段)、<>(记录类型) PTR、SEG、OFFSET、TYPE、THIS、:(段超越前缀) *、/、MOD、SHL、SHR HIGH、LOW +、- EQ、NE、LT、LE、GT、GE NOT AND OR、XOR SHORT 这些符号及其优先级并不要强记,有些符号同时出现的可能性非常小。
98
第4章 标识符和表达式 4.7.3 地址表达式 地址表达式是计算存储单元地址的表达式,它可由标号、变量名和由括号括起来的基址或变址寄存器组成。 其计算结果表示一个存储单元的地址,而不是该存储单元的值。 例如: B1 DB 10H, 11H, 12H DB 'ABCD' W1 DW 1234H, 5678H … 10 11 12 'A' 'B' 'C' 'D' 34 78 56 B1 B1+1 B1+3 W1+2 注意:地址表达式W1+1并不表示字变量W1之后一个字的存储单元,而是字变量W1之后一个字节的存储单元,它的存储单元值是:7812H。
99
第4章 标识符和表达式 4.8 符号定义语句 4.8.1 等价语句 1、一般格式 等价语句的一般使用格式如下: 符号名 EQU 表达式
其作用是用左边的符号名来代表右边的表达式。 注意:等价语句不会给符号名分配存储空间,符号名不能与其它符号同名,也不能被重新定义。
100
第4章 标识符和表达式 2、用符号名代表常量或表达式
当把一个常量或表达式定义成一个具有一定含义的符号名后,在程序中就可以用该符号名来代表该常量或表达式。 例如: NUMBER EQU ;给缓冲区的长度取一个符号名 BUFF_LEN EQU NUMBER+2 CR EQU 13 ;给“回车”符的ASCII码定义一个符号名 LF EQU 10 ;给“换行”符的ASCII码定义一个符号名 … BUFFER DB NUMBER, ?, NUMBER DUP (?)
101
第4章 标识符和表达式 3、用符号名代表字符串 用一个具有一定含义的符号名定义某一个较长的字符串,在随后的程序中就用该符号名。例如:
GREETING EQU "How are you!" 在该定义之后,就可使用符号名GREETING来代表字符串"How are you!"。
102
第4章 标识符和表达式 4、用符号名关键字或指令助忆符 用一个(或一组)程序员自己习惯的符号名来代替汇编语言中的关键字或指令助忆符。 例如:
MOVE EQU MOV ;给指令MOV取另一个符号名MOVE COUNTER EQU CX ;给寄存器CX取一个叫“计数器”的符号名 上面的定义只是给原来的助忆符MOV和CX起了另一个别名,而原来的助忆符MOV和CX仍然是可以使用的,所以,我们可编写如下语句: MOVE AX, CX ;相当于指令:MOV AX, CX MOV COUNTER, BX ;相当于指令:MOV CX, BX
103
第4章 标识符和表达式 5、用符号名定义存储单元的别名 对存储单元定义另一个数据类型的符号名。 例如:
WORD1 EQU THIS WORD ;给后面的字节存储单元取一个字属性的符号名 BYTE1 DB h, 21h FLAG DW H FLAG1 EQU byte ptr FLAG ;给FLAG的低字节取一个字节属性的符号名 FLAG2 EQU byte ptr FLAG+1 ;给FLAG的高字节取一个字节属性的符号名 有了上述定义后,可编写如下语句: MOV AX, WORD1 ;执行后,(AX)=2112H MOV BL, FLAG1 ;执行后,(BL)=34H
104
第4章 标识符和表达式 4.8.2 等号语句 汇编语言提供了用等号来定义符号常数的方法,即可用符号名代表一个常数。其一般格式如下:
符号名=数值表达式 数值表达式在汇编时应该可以计算出数值,它不能含有向前引用的符号名称。用等号语句定义的符号可以被重新定义。 例如: ABC = * 5 ;ABC的值为1010 ABC1 = 5 * ABC + 21 ;ABC1的值为5071 COUNT = 1 ;COUNT的值为1 COUNT = 2*COUNT + 1 ;COUNT的值为3
105
第4章 标识符和表达式 4.8.3 符号名定义语句 符号名定义语句LABEL语句定义一个符号名,该符号名的段地址和偏移量与下面紧跟存储单元的相应属性相同,但该符号的类型是新指定的。 LABEL语句的一般格式如下: 符号名 LABEL 类型 其中:常用的类型有BYTE、WORD、DWORD、NEAR和FAR等。 例如: WBUFFER LABEL WORD ;WBUFFER与BUFFER具有相同的段地址和 BUFFER DB DUP(0) ;偏移量,但它们的数据类型不同。 … NEXT1 LABEL FAR ;NEXT1和NEXT有相同的段地址和偏移量, NEXT: MOV AX, BX ;NEXT1是“远”标号,NEXT是“近”标号。 标号NEXT1和NEXT可用于不同的情况。当在同一个模块内转移时,可使用标号NEXT;当在不同的模块之间进行转移时,需要使用“远”标号NEXT1。
106
谢 谢 计算机科学系 2003年03月20日
Similar presentations