⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 汇004.txt

📁 会变语言实现的一些程序
💻 TXT
📖 第 1 页 / 共 4 页
字号:
了解的内容:等价定义符(EQU)和等号(=)的作用及其差异,知道操作符THIS和LABEL的作用。

掌握的内容:汇编语言标识符的命名规则,语句标号的书写格式。字符串和数值在内存中存放次序的差异。结构类型和记录变量的定义及其域引用等方法。

熟练掌握的内容:汇编语言中,各类内存变量(字节、字、双字等)定义的一般形式,初值的赋值方法。内存变量的各种属性(如:偏移量、段地址、类型等)的含义。

定义连续存储单元的说明符(DUP)的用法和作用。

数值表达式和地址表达式的含义、作用和它们之间的区别,各种运算符的优先次序。

建议学习时间:12小时。
第4章 标识符和表达式
标识符和表达式是程序设计经常用到的两个基本概念。在用高级语言进行程序设计时,如果程序要对某个变化的量进行处理时,通常都要对该变化量定义一个具有某种数据类型的符号名,用该符号名也就等于使用了该变化量。在汇编语言中,也是如此,所不同的是它们的说明和引用方式不同。

4.1 标识符
在汇编语言中,标号、内存变量名、子程序名和宏名等都是标识符,它一般最多由31个字母、数字及规定的特殊字符(?、@、_、$)等组成,并且不能用数字开头。通常情况下,汇编语言不区分标识符中字母的大小写。

和高级语言的变量名一样,一般要求标识符尽可能取得有点含义,这会大大改善程序的可读性,并有助于对程序的理解。但标识符不能是汇编语言的保留字,汇编语言的保留字主要是指:指令助忆符、伪指令定义符、寄存器名以及一些具有特殊含义的字符串等。

例如:MSG1、ERRMSG2、ASC1、asc2等是合法的标识符,而1a、ah、mov等就不是合法的标识符。

试比较ABCDH和0ABCDH之间的差异。前者是标识符,而后者是十六位进制数值。

4.2 简单内存变量的定义
在编程序时,我们往往要根据程序的需要定义一些内存单元。在高级语言程序中,要给存储单元取一个符号名,然后通过引用该符号名来访问其所对应的存储单元,而在汇编语言程序中要灵活一些,它可以给存储单元取符号名,也可以不取符号名。当给存储单元取符号名时,则可通过该符号名来访问其对应的存储单元;当不给存储单元取符号名时,则可通过存储单元的偏移量(有效地址)来访问它。

汇编语言中,常见的数据类型有字节、字和双字等。下面介绍如何定义各种整型类型的内存变量,有关浮点类型变量的定义方式将在第11章中介绍。 

4.2.1 内存变量定义的一般形式
定义数据变量语句是在程序中经常使用的伪指令语句,其一般格式如下:

[变量名]  数据定义符  表达式1[, 表达式2, …, 表达式n]  ;注释

该定义格式的主要解释如下:
 
 变量名必须是一个合法的标识符,它可以写,也可以不写; 
、 数据定义符用于确定内存单元的数据类型,常用的定义符有:DB、DW和DD等; 
、 表达式是定义内存单元时的初值表达式,一个定义语句可以有多个初值表达式,各表达式之间必须用逗号‘,’分开;如果某个存储单元没有初值表达式,则必须用一个问号‘?’来表示; 
、 在定义语句的后面可以书写注释内容,也可以不写。 

在定义变量时,虽然可以不写变量名,但我们建议还是要写,因为不写变量名,就意味着只能用内存单元的偏移量来访问它。这时,一旦内存单元的偏移量发生变化,那么,程序中的所有引用都要修改,这不仅增加了程序维护的工作量,而且也容易因遗漏修改而出错。
4.2.2 字节变量
定义字节变量的定义符为DB/BYTE(Define Byte),每个字节只占一个字节单元。其中:BYTE是MASM 6.0及其以后版本的数据类型说明符,随后的其它类型说明符同此说明。

例如:

COUNTER  DB 6 
 DB 'A', 'D', 0Dh, '$'
 
TABLE  DB 1, 3, 5, 7, 9, 11 

上面的定义语句经汇编后所产生出的内存单元分配情况如图4.1所示。图中的数据是用十六进制表示的(以后也如此,不再说明),由引号括起来的字符在内存中是存放其ASCII码值。所以,'D'和0Dh是不同的,前者是字符'D',后者是数值12的十六进制编码。

 06
 41
 44
 0D
 24
 01
 03
 05
 07
 09
 0B
 

   
COUNTER TABLE 

图4.1 内存单元的分配情况示意图

注意:在上例中,说明语句“DB 'A', 'D', 0Dh, '$'”之前并没有给出变量名,但我们可以从前面的变量名COUNTER一直往后数,或从TABLE往前数,来访问某存储单元,因为它们是一片连续的存储单元,这和高级语言的变量定义有点区别的。在高级语言中,我们一定要用某个标识符来说明变量,也必须用该变量名来访问其所对应的存储单元。

用定义符DB还可定义一种特殊的数据形式——字符串。在定义字符串时,必须用成对的单引号或双引号把所要的字符括起来,括号内字符的ASCII码将依次存放在相应的字节单元内。例如:

MSG1 DB 'I am a student.'

该说明语句所对应的存储单元分布如下所示。为了看起来方便,并没有用字符的ASCII码来存放在相应的存储单元内,而直接用该字符,请不要引起误解。

… 'I' ' ' 'a' 'm' ' ' 'a' ' ' 's' 't' 'u' 'd' 'e' 'n' 't' … 

上面的例子也可改写为另一种等价的语句:

MSG1 DB 'I', ' ', 'a', 'm', ' ', 'a', ' ', 's', 't', 'u', 'd', 'e', 'n', 't', '.'

显然,前者的说明要比后者方便得多,所以,在程序中都采用前者的书写方式。
4.2.3 字变量
定义字变量的定义符为DW/WORD(Define Word),每个字占用两个连续的字节单元。

例如:

Word1 DW 89H, 1909H, -1
DW 0abcdH, ?, 0

上述定义的内存分配如下所示。

… 89 00 09 19 FF FF CD AB -- -- 00 00 … 

由于字变量的数据是按照“高高低低”的原则存于存储单元之中的,而字节数据是按照排列顺序存于存储单元中的,所以,它们的存储方式有所不同。

试比较下面两个定义的存储顺序,其中:41H和42H分别是'A'和'B'的ASCII码。

B1 DB 'AB'
 
W1 DW 'AB'
 
 … 41h 42h 42h 41h … 
 

4.2.4 双字变量
定义双字变量的定义符为DD/DWORD(Define Doubleword),每个双字变量占用二个连续的字单元(四个字节)。

DW1 DD 12345678H, ?
DW2 DD 0abcd1243H

上述定义的内存分配如下所示。

… 78 56 34 12 -- -- -- -- 43 12 CD AB … 
4.2.5 六字节变量
定义六字节变量的定义符为DF/FWORD(Define Farword)。顾名思义,每个六字节变量占用六个连续的字节。

DF1 DF 1234567890abH, -1
DF 1abcd23H

上述定义的内存分配如下所示。

… abH 90H 78H 56H 34H 12H 0FFH 0FFH 0FFH 0FFH 0FFH 0FFH 23hH 0cdH 0abH 01H 00H 00H … 

4.2.6 八字节变量
定义八字节变量的定义符为DQ/QWORD(Define Quadword)。同理,每个八字节变量占用八个连续的字节。

DQ1 DQ 12345678H, 0H, -1234H
DQ ?, 1238H, ?

第一个八字节常量12345678H在内存中的分配方式如下所示,其存储原则与前面相同。其它八字节常量的存储方式与此一致。

… 78
 56 34 12 00 00 00 00 … 

4.2.7 十字节变量
定义十字节变量的定义符为DT/TBYTE(Define Tenbytes)。同理,每个十字节变量占用十个连续的字节。

DT1 DT 12345678H, 0H, -1234H
DT2 DT ?, -1H

第一个十字节常量12345678H在内存中的分配方式如下所示,它同样按“高高低低”的原则来存储。其它十字节常量的存储方式与此一致。

… 78
 56 34 12 00 00 00 00 00 00 … 

以上六个数据类型是汇编语言中最基本的数据类型,其中,前三个是在程序中经常使用的,后三个的使用频率不太高。 
4.3 调整偏移量伪指令
调整偏移量伪指令是在内存变量定义时用来调整内存变量起始偏移量的,它们是在把源程序汇编成目标文件时起作用。常用的调整偏移量伪指令有:EVEN、ALIGN和ORG,它们的主要目的是:为了更有效地读取内存单元的内容。

4.3.1 偶对齐伪指令EVEN
偶对齐伪指令格式:

EVEN

伪指令的作用是:告诉汇编程序(Assember),本伪指令下面的内存变量从下一个偶地址单元开始分配。

如果下一个偏移量是偶地址,那么,该伪指令不起作用,否则,汇编程序将空出一个字节,从下一偶地址开始为其后变量分配内存单元。

假设有下列变量定义,并且变量B1的偏移量是偶数,其内存单元分布如图4.2所示。

 B1 DB 12H ;为了表示方便,不妨再假设其偏移量为:xxxx0H 
W1 DW 4567H 

 
 
图4.2 内存单元分布图
 图4.3 齐偏移量读取一个字的过程示意图
 

在上述定义情况下,在许多微机系统中,当需要读变量W1及其后面的字内容时,硬件将按图4.3所示的方式分二次读出该字内容,再拼接成一个字内容,这时,无疑需要二个读内存周期,从而影响程序执行的速度。

出现上述问题的主要原因就是字变量W1在数据段内的偏移量是奇数,为了保证其偏移量是偶数,需要在其定义之前加上伪指令EVEN。

所以,可把前面的变量定义改变成下列形式:
  

图4.4 偶偏移量读取字过程
 
 B1 DB 12H 
EVEN 
W1 DW 4567H 
这时,变量的内存分配和读取字变量W1的过程如图4.4所示。
 

4.3.2 对齐伪指令ALIGN
对齐伪指令格式:

ALIGN  Num

其中:Num必须是2的幂,如:2、4、8和16等。

伪指令的作用是:告诉汇编程序,本伪指令下面的内存变量必须从下一个能被Num整除的地址开始分配。

如果下一个地址正好能被Num整除,那么,该伪指令不起作用,否则,汇编程序将空出若干个字节,直到下一个地址能被Num整除为止。

试比较下面二组变量定义,它们的对齐效果一致吗?

B1
 DB 12H B1 DB 12H 
EVEN  ALIGN 2 
W1 
 DW 4567H W1 DW 4567H 

从上面的对比,我们不难看出:伪指令ALIGN的说明功能要比伪指令EVEN强。
4.3.3 调整偏移量伪指令ORG
调整偏移量伪指令格式:

ORG  数值表达式

伪指令的作用是:告诉汇编程序,本伪指令下面的内存变量从该“数值表达式”所指定的地址开始分配。

假设有下列变量定义,并且变量word1的偏移量为0。

word1
  DW 1234h 
 
byte1  DB 56h 
word2  DW 0abcdh 
  ORG 1 
byte2  DB ? 
word3  DW ? 
byte3  DB ? 图4.5 内存变量分配示意图
 

前三个变量定义的内存分布如图4.5的左边所示,但由于伪指令“ORG 1”的作用,说明其后面所说明的变量要从偏移量为“1”的内存单元开始存放。所以,后三个变量的内存分配如图4.5的右边所示。

由图4.5可见,这些变量的内存分配是相互重叠的,对某个变量的操作无疑会影响到与之重叠的变量。

另外,变量byte2、word3和byte3没有赋初值,如果赋初值的话,则重叠部分的内存单元的原来初值将被覆盖掉。

在以上三个伪指令EVEN、ALIGN和ORG中,伪指令EVEN的使用频率较高。

4.3.4 偏移量计数器的值
前面,我们介绍了几种改变偏移量计数器之值的方法,但在程序中还无法引用其值。汇编语言提供了一个特殊的符号“$”来引用偏移量计数器的值。

例如:
 

图4.6 内存单元分布示意图
 
W1  DW $, $ 
  ORG $+3   ;从当前地址开始空3个字节 
B1  DB 43h 
假设:在给变量W1分配内存单元时,当前偏移量计数器的值为2。

于是,变量W1后面第一个“$”代表数值2,第一个字分配后,此时偏移量计数器$的值就为4,所以,第二个“$”就代表数值4。

在分配完二个字之后,偏移量计数器的值变为6,$+3的值为9,所以,伪指令“ORG $+3”就表示下一个变量从偏移量为9的单元地址开始分配。

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -